diff --git a/.env b/.env index b1c44ef..2099de8 100644 --- a/.env +++ b/.env @@ -4,14 +4,11 @@ SPEEDTEST_INTERVAL=300 SPEEDTEST_SERVER_ID= # InfluxDB container environment variables -# If you are running on a Raspberry Pi, use 1.8.3 -INFLUXDB_IMAGE_TAG=1.8-alpine -INFLUXDB_GRAPHITE_ENABLED=false -INFLUXDB_REPORTING_DISABLED=true +INFLUXDB_IMAGE_TAG=2.7.1 # You SHOULD change these! -# Make sure you also edit these in /grafana-config/datasources/datasource.yml -INFLUXDB_USER=root -INFLUXDB_USER_PASSWORD=root +DOCKER_INFLUXDB_INIT_USERNAME=root +DOCKER_INFLUXDB_INIT_PASSWORD=root +DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=root # Grafana container environment variables # You SHOULD change these! GF_SECURITY_ADMIN_USER=admin diff --git a/LICENSE b/LICENSE index 9028fcc..e4fe93d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 dbrennand +Copyright (c) 2023 dbrennand Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 6dcf17f..04ee2c9 100644 --- a/README.md +++ b/README.md @@ -6,48 +6,38 @@ Use [Grafana](https://grafana.com/), [InfluxDB](https://www.influxdata.com/produ 1. Docker -2. docker-compose +2. Docker Compose ## Usage -> [!NOTE] -> -> Make sure you run the commands below from the project directory. +1. Build the speedtest-grafana container image: -1. Build the speedtest-grafana container image using the command: `docker-compose build` + ```bash + docker compose build + ``` 2. Set the `SPEEDTEST_SERVER_ID` environment variable located in the [.env](.env) file to the server ID to perform speedtests against. - > [!NOTE] + > **Note** > - > If you don't know any server IDs, run the following command and they will be shown: `docker run --rm -it speedtest-grafana:0.0.2 /librespeed --list` - -3. Modify any other environment variables located in the [.env](.env) file. - - > [!WARNING] - > - > It is **highly** recommended that you change the default usernames and passwords! - > - > When modifying the `INFLUXDB_USER` and `INFLUXDB_USER_PASSWORD` environment variables. Make sure you also modify them in [datasource.yml](/grafana-config/datasources/datasource.yml): - > - > ```yaml - > # You SHOULD change these! - > user: root - > secureJsonData: - > password: root + > If you don't know any server IDs, run the following command to list them: + > ```bash + > docker run --rm -it speedtest-grafana:1.0.0 /librespeed --list > ``` - > [!NOTE] - > - > If you intend to run this project on a Raspberry Pi, make sure you alter the `INFLUXDB_IMAGE_TAG` to `1.8.3`. +3. Set the `DOCKER_INFLUXDB_INIT_PASSWORD`, `DOCKER_INFLUXDB_INIT_ADMIN_TOKEN` and `GF_SECURITY_ADMIN_PASSWORD` environment variables located in the [.env](.env) file. + +4. Start the containers: -4. Start the containers using the command: `docker-compose up -d` + ```bash + docker compose up -d + ``` 5. Access Grafana at [`http://localhost:3000`](http://localhost:3000) - > [!NOTE] + > **Note** > - > You should also be able to access Grafana from your host's IP address. + > Grafana will also be available from your host's IP address. ## Disclaimer @@ -57,7 +47,7 @@ If you like this project then please give their repositories a star! ⭐ ## Authors -- Contributors -* [**dbrennand**](https://github.com/dbrennand) - *Author* +[**Daniel Brennand**](https://github.com/dbrennand) - *Author* ## License This project is licensed under the MIT License - see the [LICENSE](LICENSE) for details. diff --git a/docker-compose.yml b/docker-compose.yml index b132f49..26e7e2c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,30 +6,35 @@ services: expose: - 8086 volumes: - - influxdb:/var/lib/influxdb + - influxdb:/var/lib/influxdb2 restart: always + networks: + - speedtest-grafana environment: - - "INFLUXDB_GRAPHITE_ENABLED=${INFLUXDB_GRAPHITE_ENABLED}" - - "INFLUXDB_REPORTING_DISABLED=${INFLUXDB_REPORTING_DISABLED}" - - "INFLUXDB_DB=internet_speed" - - "INFLUXDB_USER=${INFLUXDB_USER}" - - "INFLUXDB_USER_PASSWORD=${INFLUXDB_USER_PASSWORD}" + - "DOCKER_INFLUXDB_INIT_MODE=setup" + - "DOCKER_INFLUXDB_INIT_USERNAME=${DOCKER_INFLUXDB_INIT_USERNAME}" + - "DOCKER_INFLUXDB_INIT_PASSWORD=${DOCKER_INFLUXDB_INIT_PASSWORD}" + - "DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=${DOCKER_INFLUXDB_INIT_ADMIN_TOKEN}" + - "DOCKER_INFLUXDB_INIT_ORG=internet_speed" + - "DOCKER_INFLUXDB_INIT_BUCKET=internet_speed" speedtest-grafana: build: . - image: speedtest-grafana:0.0.2 + image: speedtest-grafana:1.0.0 container_name: speedtest-grafana depends_on: - influxdb + networks: + - speedtest-grafana environment: - "SPEEDTEST_INTERVAL=${SPEEDTEST_INTERVAL}" - "SPEEDTEST_SERVER_ID=${SPEEDTEST_SERVER_ID}" - "INFLUXDB_HOST=influxdb" - "INFLUXDB_PORT=8086" - - "INFLUXDB_DB=internet_speed" - - "INFLUXDB_USER=${INFLUXDB_USER}" - - "INFLUXDB_USER_PASSWORD=${INFLUXDB_USER_PASSWORD}" + - "INFLUXDB_ORG=internet_speed" + - "INFLUXDB_BUCKET=internet_speed" + - "INFLUXDB_TOKEN=${DOCKER_INFLUXDB_INIT_ADMIN_TOKEN}" grafana: - image: grafana/grafana:7.3.7 + image: grafana/grafana:10.0.3 container_name: grafana ports: - 3000:3000 @@ -39,10 +44,18 @@ services: depends_on: - influxdb - speedtest-grafana + networks: + - speedtest-grafana environment: - "GF_SECURITY_ADMIN_USER=${GF_SECURITY_ADMIN_USER}" - "GF_SECURITY_ADMIN_PASSWORD=${GF_SECURITY_ADMIN_PASSWORD}" + - "INFLUXDB_ORG=internet_speed" + - "INFLUXDB_BUCKET=internet_speed" + - "INFLUXDB_TOKEN=${DOCKER_INFLUXDB_INIT_ADMIN_TOKEN}" volumes: influxdb: grafana-storage: + +networks: + speedtest-grafana: diff --git a/grafana-config/dashboards/dashboard.json b/grafana-config/dashboards/dashboard.json index 747d78d..28b4117 100644 --- a/grafana-config/dashboards/dashboard.json +++ b/grafana-config/dashboards/dashboard.json @@ -3,7 +3,10 @@ "list": [ { "builtIn": 1, - "datasource": "-- Grafana --", + "datasource": { + "type": "datasource", + "uid": "grafana" + }, "enable": true, "hide": true, "iconColor": "rgba(0, 211, 255, 1)", @@ -13,61 +16,121 @@ ] }, "editable": true, - "gnetId": null, + "fiscalYearStartMonth": 0, "graphTooltip": 0, + "id": 2, "links": [], + "liveNow": false, "panels": [ { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": null, + "datasource": { + "type": "influxdb", + "uid": "P5697886F9CA74929" + }, "fieldConfig": { "defaults": { - "custom": {} + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "Mbits" }, - "overrides": [] + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "upload {server_name=\"London, England (Clouvider)\", server_url=\"http://lon.speedtest.clouvider.net/backend\"}" + }, + "properties": [ + { + "id": "displayName", + "value": "Upload" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "download {server_name=\"London, England (Clouvider)\", server_url=\"http://lon.speedtest.clouvider.net/backend\"}" + }, + "properties": [ + { + "id": "displayName", + "value": "Download" + } + ] + } + ] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 8, "w": 24, "x": 0, "y": 0 }, - "hiddenSeries": false, "id": 2, - "legend": { - "alignAsTable": false, - "avg": true, - "current": false, - "max": true, - "min": true, - "rightSide": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, - "nullPointMode": "null", "options": { - "alertThreshold": false + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.3.7", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.0.3", "targets": [ { "alias": "$col", + "datasource": { + "type": "influxdb", + "uid": "P5697886F9CA74929" + }, "groupBy": [ { "params": [ @@ -85,6 +148,7 @@ "measurement": "internet_speed", "orderByTime": "ASC", "policy": "default", + "query": "from(bucket: \"internet_speed\")\n |> range(start: -1h)\n |> filter(fn: (r) => \n r._measurement == \"internet_speed\" and\n r._field == \"upload\"\n )", "refId": "A", "resultFormat": "time_series", "select": [ @@ -126,98 +190,131 @@ ] ], "tags": [] - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Internet Speed (Upload & Download)", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "Mbits", - "label": "", - "logBase": 1, - "max": null, - "min": null, - "show": true }, { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": false + "datasource": { + "type": "influxdb", + "uid": "P5697886F9CA74929" + }, + "hide": false, + "query": "from(bucket: \"internet_speed\")\n |> range(start: -1h)\n |> filter(fn: (r) => \n r._measurement == \"internet_speed\" and\n r._field == \"download\"\n )", + "refId": "B" } ], - "yaxis": { - "align": false, - "alignLevel": null - } + "title": "Internet Speed (Upload & Download)", + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": null, + "datasource": { + "type": "influxdb", + "uid": "P5697886F9CA74929" + }, "fieldConfig": { "defaults": { - "custom": {} + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "decbytes" }, - "overrides": [] + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "bytes_sent {server_name=\"London, England (Clouvider)\", server_url=\"http://lon.speedtest.clouvider.net/backend\"}" + }, + "properties": [ + { + "id": "displayName", + "value": "Bytes Sent" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "bytes_received {server_name=\"London, England (Clouvider)\", server_url=\"http://lon.speedtest.clouvider.net/backend\"}" + }, + "properties": [ + { + "id": "displayName", + "value": "Bytes Received" + } + ] + } + ] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 8, "w": 12, "x": 0, "y": 8 }, - "hiddenSeries": false, "id": 6, - "legend": { - "avg": true, - "current": false, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, - "nullPointMode": "null", "options": { - "alertThreshold": false + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.3.7", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.0.3", "targets": [ { "alias": "$col", + "datasource": { + "type": "influxdb", + "uid": "P5697886F9CA74929" + }, "groupBy": [ { "params": [ @@ -235,6 +332,7 @@ "measurement": "internet_speed", "orderByTime": "ASC", "policy": "default", + "query": "from(bucket: \"internet_speed\")\n |> range(start: -1h)\n |> filter(fn: (r) => \n r._measurement == \"internet_speed\" and\n r._field == \"bytes_sent\"\n )", "refId": "A", "resultFormat": "time_series", "select": [ @@ -276,100 +374,130 @@ ] ], "tags": [] - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Bytes Sent and Received", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "decimals": 1, - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true }, { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": false + "datasource": { + "type": "influxdb", + "uid": "P5697886F9CA74929" + }, + "hide": false, + "query": "from(bucket: \"internet_speed\")\n |> range(start: -1h)\n |> filter(fn: (r) => \n r._measurement == \"internet_speed\" and\n r._field == \"bytes_received\"\n )", + "refId": "B" } ], - "yaxis": { - "align": false, - "alignLevel": null - } + "title": "Bytes Sent and Received", + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": null, - "decimals": 2, + "datasource": { + "type": "influxdb", + "uid": "P5697886F9CA74929" + }, "fieldConfig": { "defaults": { - "custom": {} + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "ms" }, - "overrides": [] + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "ping {server_name=\"London, England (Clouvider)\", server_url=\"http://lon.speedtest.clouvider.net/backend\"}" + }, + "properties": [ + { + "id": "displayName", + "value": "Ping" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "jitter {server_name=\"London, England (Clouvider)\", server_url=\"http://lon.speedtest.clouvider.net/backend\"}" + }, + "properties": [ + { + "id": "displayName", + "value": "Jitter" + } + ] + } + ] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 8, "w": 12, "x": 12, "y": 8 }, - "hiddenSeries": false, "id": 4, - "legend": { - "avg": true, - "current": false, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, - "nullPointMode": "null", "options": { - "alertThreshold": false + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.3.7", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.0.3", "targets": [ { "alias": "$col", + "datasource": { + "type": "influxdb", + "uid": "P5697886F9CA74929" + }, "groupBy": [ { "params": [ @@ -387,6 +515,7 @@ "measurement": "internet_speed", "orderByTime": "ASC", "policy": "default", + "query": "from(bucket: \"internet_speed\")\n |> range(start: -1h)\n |> filter(fn: (r) => \n r._measurement == \"internet_speed\" and\n r._field == \"ping\"\n )", "refId": "A", "resultFormat": "time_series", "select": [ @@ -428,56 +557,34 @@ ] ], "tags": [] - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Ping and Jitter", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "ms", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true }, { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": false + "datasource": { + "type": "influxdb", + "uid": "P5697886F9CA74929" + }, + "hide": false, + "query": "from(bucket: \"internet_speed\")\n |> range(start: -1h)\n |> filter(fn: (r) => \n r._measurement == \"internet_speed\" and\n r._field == \"jitter\"\n )", + "refId": "B" } ], - "yaxis": { - "align": false, - "alignLevel": null - } + "title": "Ping and Jitter", + "type": "timeseries" }, { - "datasource": null, + "datasource": { + "type": "influxdb", + "uid": "P5697886F9CA74929" + }, "fieldConfig": { "defaults": { "custom": { "align": "center", - "filterable": false + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false }, "mappings": [], "thresholds": { @@ -590,36 +697,24 @@ { "matcher": { "id": "byName", - "options": "Country" - }, - "properties": [ - { - "id": "custom.width", - "value": 67 - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "City" + "options": "Server Name" }, "properties": [ { "id": "custom.width", - "value": 109 + "value": 211 } ] }, { "matcher": { "id": "byName", - "options": "Server Name" + "options": "Time" }, "properties": [ { "id": "custom.width", - "value": 211 + "value": 160 } ] } @@ -633,17 +728,30 @@ }, "id": 8, "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, "showHeader": true, "sortBy": [ { "desc": true, - "displayName": "Speedtest Datetime" + "displayName": "Time" } ] }, - "pluginVersion": "7.3.7", + "pluginVersion": "10.0.3", "targets": [ { + "datasource": { + "type": "influxdb", + "uid": "P5697886F9CA74929" + }, "groupBy": [ { "params": [ @@ -660,7 +768,7 @@ ], "orderByTime": "ASC", "policy": "default", - "query": "SELECT * FROM internet_speed", + "query": "from(bucket: \"internet_speed\")\n |> range(start: -1h)\n |> filter(fn: (r) => r._measurement == \"internet_speed\")", "rawQuery": true, "refId": "A", "resultFormat": "table", @@ -681,52 +789,43 @@ "tags": [] } ], - "timeFrom": null, - "timeShift": null, "title": "Speedtest Details", "transformations": [ + { + "id": "prepareTimeSeries", + "options": {} + }, + { + "id": "labelsToFields", + "options": { + "keepLabels": [ + "server_name" + ] + } + }, { "id": "organize", "options": { - "excludeByName": { - "region": true, - "server_url": true, - "timezone": true - }, + "excludeByName": {}, "indexByName": { "Time": 0, - "bytes_received": 14, - "bytes_sent": 13, - "city": 6, - "country": 5, - "download": 9, - "hostname": 3, - "ip": 1, - "jitter": 12, - "org": 2, - "ping": 11, - "region": 4, + "bytes_received": 6, + "bytes_sent": 5, + "download": 3, + "jitter": 2, + "ping": 1, "server_name": 7, - "server_url": 8, - "timezone": 15, - "upload": 10 + "upload": 4 }, "renameByName": { - "Time": "Speedtest Datetime", + "Time": "", "bytes_received": "Bytes Received", "bytes_sent": "Bytes Sent", - "city": "City", - "country": "Country", "download": "Download Speed", - "hostname": "Hostname", - "ip": "Public IP Address", "jitter": "Jitter", - "org": "Organisation", "ping": "Ping", - "region": "Region", "server_name": "Server Name", "server_url": "Server URL", - "timezone": "Timezone", "upload": "Upload Speed" } } @@ -736,7 +835,7 @@ } ], "refresh": "5m", - "schemaVersion": 26, + "schemaVersion": 38, "style": "dark", "tags": [], "templating": { @@ -746,9 +845,24 @@ "from": "now-1h", "to": "now" }, - "timepicker": {}, + "timepicker": { + "hidden": true, + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, "timezone": "", "title": "Speedtest Results", "uid": "ll6ARVfGk", - "version": 14 + "version": 8, + "weekStart": "" } diff --git a/grafana-config/dashboards/dashboard.yml b/grafana-config/dashboards/dashboard.yml index d3ad54f..19f1c90 100644 --- a/grafana-config/dashboards/dashboard.yml +++ b/grafana-config/dashboards/dashboard.yml @@ -6,6 +6,6 @@ providers: folder: Speedtest type: file disableDeletion: false - editable: true + allowUiUpdates: true options: path: /etc/grafana/provisioning/dashboards diff --git a/grafana-config/datasources/datasource.yml b/grafana-config/datasources/datasource.yml index bdf9313..1d05760 100644 --- a/grafana-config/datasources/datasource.yml +++ b/grafana-config/datasources/datasource.yml @@ -1,17 +1,17 @@ # https://grafana.com/docs/grafana/latest/administration/provisioning/ -# config file version +# https://grafana.com/docs/grafana/latest/datasources/influxdb/ apiVersion: 1 datasources: -- name: InfluxDB - type: influxdb - access: proxy - database: internet_speed - url: http://influxdb:8086 - version: 1 - isDefault: true - editable: false - # You SHOULD change these! - user: root - secureJsonData: - password: root + - name: InfluxDB_v2_Flux + type: influxdb + access: proxy + url: http://influxdb:8086 + isDefault: true + jsonData: + version: Flux + organization: ${INFLUXDB_ORG} + defaultBucket: ${INFLUXDB_BUCKET} + tlsSkipVerify: true + secureJsonData: + token: ${INFLUXDB_TOKEN} diff --git a/requirements.txt b/requirements.txt index cf2dd35..1f28d53 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,13 +1,8 @@ -certifi==2020.12.5 -chardet==4.0.0 -colorama==0.4.4 -idna==2.10 -influxdb==5.3.1 -loguru==0.5.3 -msgpack==1.0.2 -python-dateutil==2.8.1 -pytz==2020.5 -requests==2.25.1 -six==1.15.0 -urllib3==1.26.5 -win32-setctime==1.0.3 +certifi==2023.7.22 +influxdb-client==1.37.0 +loguru==0.7.0 +python-dateutil==2.8.2 +reactivex==4.0.4 +six==1.16.0 +typing_extensions==4.7.1 +urllib3==2.0.4 diff --git a/speedtest.py b/speedtest.py index 4f89b82..a0aa4dd 100644 --- a/speedtest.py +++ b/speedtest.py @@ -1,7 +1,7 @@ """ MIT License -Copyright (c) 2021 dbrennand +Copyright (c) 2023 dbrennand Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -23,12 +23,13 @@ """ from loguru import logger import os -import influxdb +from influxdb_client import InfluxDBClient +from influxdb_client.client.write_api import SYNCHRONOUS import subprocess import json import time -__version__ = "0.0.2" +__version__ = "1.0.0" logger.debug(f"Starting speedtest-grafana version: {__version__}.") @@ -38,9 +39,9 @@ SPEEDTEST_SERVER_ID = os.environ.get("SPEEDTEST_SERVER_ID", None) INFLUXDB_HOST = os.environ.get("INFLUXDB_HOST", "influxdb") INFLUXDB_PORT = int(os.environ.get("INFLUXDB_PORT", 8086)) -INFLUXDB_USER = os.environ.get("INFLUXDB_USER", "root") -INFLUXDB_USER_PASSWORD = os.environ.get("INFLUXDB_USER_PASSWORD", "root") -INFLUXDB_DB = os.environ.get("INFLUXDB_DB", "internet_speed") +INFLUXDB_TOKEN = os.environ.get("INFLUXDB_TOKEN", "root") +INFLUXDB_ORG = os.environ.get("INFLUXDB_ORG", "internet_speed") +INFLUXDB_BUCKET = os.environ.get("INFLUXDB_BUCKET", "internet_speed") # Check if SPEEDTEST_SERVER_ID environment variable has not been provided if not SPEEDTEST_SERVER_ID: @@ -53,84 +54,81 @@ # Connect to InfluxDB logger.debug( - f"Connecting to InfluxDB using host: {INFLUXDB_HOST}, port: {INFLUXDB_PORT}, username: {INFLUXDB_USER}, database name: {INFLUXDB_DB}." + f"Connecting to InfluxDB {INFLUXDB_HOST}:{INFLUXDB_PORT}, bucket: {INFLUXDB_BUCKET}." ) -influx = influxdb.InfluxDBClient( - host=INFLUXDB_HOST, - port=INFLUXDB_PORT, - username=INFLUXDB_USER, - password=INFLUXDB_USER_PASSWORD, - database=INFLUXDB_DB, - retries=0, -) - -# Run the speedtest using the librespeed/speedtest-cli on an interval -while True: - logger.debug( - f"Running speedtest with server ID: {SPEEDTEST_SERVER_ID} and telemetry disabled." - ) - result = subprocess.run( - [ - "/librespeed", - "--server", - SPEEDTEST_SERVER_ID, - "--telemetry-level", - "disabled", - "--json", - ], - capture_output=True, - text=True, - ) - # Check if speedtest failed - if result.returncode != 0: - # Speedtest failed - # CLI errors go to stdout +with InfluxDBClient( + url=f"http://{INFLUXDB_HOST}:{INFLUXDB_PORT}", + token=INFLUXDB_TOKEN, + org=INFLUXDB_ORG, +) as client: + # Run the speedtest using the librespeed/speedtest-cli on an interval + while True: logger.debug( - f"Speedtest failed with exit code: {result.returncode}.\nError: {result.stdout}" + f"Running speedtest with server ID: {SPEEDTEST_SERVER_ID} and telemetry disabled." ) - else: - # Speedtest succeeded - logger.debug(f"Speedtest succeeded. Parsing JSON results.") - # Parse JSON results - try: - json_result = json.loads(result.stdout) - except json.decoder.JSONDecodeError as err: - logger.debug(f"Failed to parse JSON results.\nError: {err}") - logger.debug(f"Sleeping for {SPEEDTEST_INTERVAL} seconds.") - # Sleep on the specified interval - time.sleep(SPEEDTEST_INTERVAL) - continue - # Create InfluxDB JSON body - json_body = [ - { - "measurement": "internet_speed", - "tags": { - "server_name": json_result["server"]["name"], - "server_url": json_result["server"]["url"], - "ip": json_result["client"]["ip"], - "hostname": json_result["client"]["hostname"], - "region": json_result["client"]["region"], - "city": json_result["client"]["city"], - "country": json_result["client"]["country"], - "org": json_result["client"]["org"], - "timezone": json_result["client"]["timezone"], - }, - "time": json_result["timestamp"], - "fields": { - "bytes_sent": json_result["bytes_sent"], - "bytes_received": json_result["bytes_received"], - "ping": float(json_result["ping"]), - "jitter": float(json_result["jitter"]), - "upload": float(json_result["upload"]), - "download": float(json_result["download"]), - }, - } - ] - # Write results to InfluxDB - logger.debug( - f"Writing results to InfluxDB database: {INFLUXDB_DB}.\nResults: {json_body}" + result = subprocess.run( + [ + "/librespeed", + "--server", + SPEEDTEST_SERVER_ID, + "--telemetry-level", + "disabled", + "--json", + ], + capture_output=True, + text=True, ) - influx.write_points(json_body) - logger.debug(f"Sleeping for {SPEEDTEST_INTERVAL} seconds.") - # Sleep on the specified interval - time.sleep(SPEEDTEST_INTERVAL) + # Check if speedtest failed + if result.returncode != 0: + # Speedtest failed + # CLI errors go to stdout + logger.debug( + f"Speedtest failed with exit code: {result.returncode}.\nError: {result.stdout}" + ) + else: + # Speedtest succeeded + logger.debug(f"Speedtest succeeded. Parsing JSON results.") + # Parse JSON results + try: + json_result = json.loads(result.stdout) + except json.decoder.JSONDecodeError as err: + logger.debug(f"Failed to parse JSON results.\nError: {err}") + logger.debug(f"Sleeping for {SPEEDTEST_INTERVAL} seconds.") + # Sleep on the specified interval + time.sleep(SPEEDTEST_INTERVAL) + continue + with client.write_api(write_options=SYNCHRONOUS) as write_api: + # Create InfluxDB record + record = [ + { + "measurement": "internet_speed", + "tags": { + "server_name": json_result[0]["server"]["name"], + "server_url": json_result[0]["server"]["url"], + "ip": json_result[0]["client"]["ip"], + "hostname": json_result[0]["client"]["hostname"], + "region": json_result[0]["client"]["region"], + "city": json_result[0]["client"]["city"], + "country": json_result[0]["client"]["country"], + "org": json_result[0]["client"]["org"], + "timezone": json_result[0]["client"]["timezone"], + }, + "time": json_result[0]["timestamp"], + "fields": { + "bytes_sent": json_result[0]["bytes_sent"], + "bytes_received": json_result[0]["bytes_received"], + "ping": float(json_result[0]["ping"]), + "jitter": float(json_result[0]["jitter"]), + "upload": float(json_result[0]["upload"]), + "download": float(json_result[0]["download"]), + }, + } + ] + # Write results to InfluxDB + logger.debug( + f"Writing results to InfluxDB bucket: {INFLUXDB_BUCKET}.\nResults: {record}" + ) + write_api.write(bucket=INFLUXDB_BUCKET, record=record) + logger.debug(f"Sleeping for {SPEEDTEST_INTERVAL} seconds.") + # Sleep on the specified interval + time.sleep(SPEEDTEST_INTERVAL)