1# Remote monitoring and metrics visualization 2 3AFL++ can send out metrics as StatsD messages. For remote monitoring and 4visualization of the metrics, you can set up a tool chain. For example, with 5Prometheus and Grafana. All tools are free and open source. 6 7This enables you to create nice and readable dashboards containing all the 8information you need on your fuzzer instances. There is no need to write your 9own statistics parsing system, deploy and maintain it to all your instances, and 10sync with your graph rendering system. 11 12Compared to the default integrated UI of AFL++, this can help you to visualize 13trends and the fuzzing state over time. You might be able to see when the 14fuzzing process has reached a state of no progress and visualize what are the 15"best strategies" for your targets (according to your own criteria). You can do 16so without logging into each instance individually. 17 18![example visualization with Grafana](resources/statsd-grafana.png) 19 20This is an example visualization with Grafana. The dashboard can be imported 21with [this JSON template](resources/grafana-afl++.json). 22 23## AFL++ metrics and StatsD 24 25StatsD allows you to receive and aggregate metrics from a wide range of 26applications and retransmit them to a backend of your choice. 27 28From AFL++, StatsD can receive the following metrics: 29- cur_item 30- cycle_done 31- cycles_wo_finds 32- edges_found 33- execs_done 34- execs_per_sec 35- havoc_expansion 36- max_depth 37- corpus_favored 38- corpus_found 39- corpus_imported 40- corpus_count 41- pending_favs 42- pending_total 43- slowest_exec_ms 44- total_crashes 45- saved_crashes 46- saved_hangs 47- var_byte_count 48- corpus_variable 49 50Depending on your StatsD server, you will be able to monitor, trigger alerts, or 51perform actions based on these metrics (for example: alert on slow exec/s for a 52new build, threshold of crashes, time since last crash > X, and so on). 53 54## Setting environment variables in AFL++ 55 561. To enable the StatsD metrics collection on your fuzzer instances, set the 57 environment variable `AFL_STATSD=1`. By default, AFL++ will send the metrics 58 over UDP to 127.0.0.1:8125. 59 602. To enable tags for each metric based on their format (banner and 61 afl_version), set the environment variable `AFL_STATSD_TAGS_FLAVOR`. By 62 default, no tags will be added to the metrics. 63 64 The available values are the following: 65 - `dogstatsd` 66 - `influxdb` 67 - `librato` 68 - `signalfx` 69 70 For more information on environment variables, see 71 [env_variables.md](env_variables.md). 72 73 Note: When using multiple fuzzer instances with StatsD it is *strongly* 74 recommended to set up `AFL_STATSD_TAGS_FLAVOR` to match your StatsD server. 75 This will allow you to see individual fuzzer performance, detect bad ones, 76 and see the progress of each strategy. 77 783. Optional: To set the host and port of your StatsD daemon, set 79 `AFL_STATSD_HOST` and `AFL_STATSD_PORT`. The default values are `localhost` 80 and `8125`. 81 82## Installing and setting up StatsD, Prometheus, and Grafana 83 84The easiest way to install and set up the infrastructure is with Docker and 85Docker Compose. 86 87Depending on your fuzzing setup and infrastructure, you may not want to run 88these applications on your fuzzer instances. This setup may be modified before 89use in a production environment; for example, adding passwords, creating volumes 90for storage, tweaking the metrics gathering to get host metrics (CPU, RAM, and 91so on). 92 93For all your fuzzing instances, only one instance of Prometheus and Grafana is 94required. The 95[statsd exporter](https://registry.hub.docker.com/r/prom/statsd-exporter) 96converts the StatsD metrics to Prometheus. If you are using a provider that 97supports StatsD directly, you can skip this part of the setup." 98 99You can create and move the infrastructure files into a directory of your 100choice. The directory will store all the required configuration files. 101 102To install and set up Prometheus and Grafana: 103 1041. Install Docker and Docker Compose: 105 106 ```sh 107 curl -fsSL https://get.docker.com -o get-docker.sh 108 sh get-docker.sh 109 ``` 110 1112. Create a `docker-compose.yml` containing the following: 112 113 ```yml 114 version: '3' 115 116 networks: 117 statsd-net: 118 driver: bridge 119 120 services: 121 prometheus: 122 image: prom/prometheus 123 container_name: prometheus 124 volumes: 125 - ./prometheus.yml:/prometheus.yml 126 command: 127 - '--config.file=/prometheus.yml' 128 restart: unless-stopped 129 ports: 130 - "9090:9090" 131 networks: 132 - statsd-net 133 134 statsd_exporter: 135 image: prom/statsd-exporter 136 container_name: statsd_exporter 137 volumes: 138 - ./statsd_mapping.yml:/statsd_mapping.yml 139 command: 140 - "--statsd.mapping-config=/statsd_mapping.yml" 141 ports: 142 - "9102:9102/tcp" 143 - "8125:9125/udp" 144 networks: 145 - statsd-net 146 147 grafana: 148 image: grafana/grafana 149 container_name: grafana 150 restart: unless-stopped 151 ports: 152 - "3000:3000" 153 networks: 154 - statsd-net 155 ``` 156 1573. Create a `prometheus.yml` containing the following: 158 159 ```yml 160 global: 161 scrape_interval: 15s 162 evaluation_interval: 15s 163 164 scrape_configs: 165 - job_name: 'fuzzing_metrics' 166 static_configs: 167 - targets: ['statsd_exporter:9102'] 168 ``` 169 1704. Create a `statsd_mapping.yml` containing the following: 171 172 ```yml 173 mappings: 174 - match: "fuzzing.*" 175 name: "fuzzing" 176 labels: 177 type: "$1" 178 ``` 179 1805. Run `docker-compose up -d`. 181 182## Running AFL++ with StatsD 183 184To run your fuzzing instances: 185 186``` 187AFL_STATSD_TAGS_FLAVOR=dogstatsd AFL_STATSD=1 afl-fuzz -M test-fuzzer-1 -i i -o o [./bin/my-application] @@ 188AFL_STATSD_TAGS_FLAVOR=dogstatsd AFL_STATSD=1 afl-fuzz -S test-fuzzer-2 -i i -o o [./bin/my-application] @@ 189... 190```