diff --git a/README.md b/README.md index 8136183..ef5d8d2 100644 --- a/README.md +++ b/README.md @@ -32,13 +32,15 @@ You can make use of the following environment variables / configurations: | Environment variable | Default value | Description |----------------------|---------------|------------| | `GRAFANA_PORT` | `3000` | Port to bind Grafana webinterface on the host system | -| `SPEEDTEST_SPEEDTEST_INTERVAL` | `3600` | Interval/pause (in seconds) between speedtests | +| `SPEEDTEST_INTERVAL` | `3600` | Interval/pause (in seconds) between speedtests | | `SPEEDTEST_HOST` | `local` | Display name of the client | | `SPEEDTEST_SERVER` | none | Optionally set specific speedtest.net derver ID, otherwise use the closest | -| `INFLUXDB_DB` | `speedtest` | Database to save speedtest results | +| `SPEEDTEST_ENHANCED_LOGGING` | none | Optionally write all returned speedtest CLI metrics to a single InfluxDB measurement (INFLUXDB_MEASUREMENT), else use legacy logging to download, upload, ping measurements only | | `INFLUXDB_HOST` | `influxdb` | Name of the InfluxDB host/containers | | `INFLUXDB_USERNAME` | `root` | Username for InfluxDB authentication | | `INFLUXDB_PASSWORD` | `root` | Password for InfluxDB authentication | +| `INFLUXDB_DB` | `speedtest` | Database to save speedtest results | +| `INFLUXDB_MEASUREMENT` | `results` | InfluxDB measurement to results to. Only valid if SPEEDTEST_ENHANCED_LOGGING is true | ## Usage @@ -88,12 +90,18 @@ $ docker-compose logs -f grafana By default the dashboard shows all speedtest results. To filter for a specifc host, simply add a `and host = 'local'` statement in the `WHERE` clause of the SQL select. -Example (Download Time Serie): +Example 1 - Download Time Series: ``` SELECT mean("value") FROM "download" WHERE $timeFilter and host = 'local' GROUP BY time($interval) fill(null) ``` +Example 2 - Download Time Series (If using SPEEDTEST_ENHANCED_lOGGING): + +``` +SELECT mean("download_bandwidth") FROM "results" WHERE $timeFilter and host = 'local' GROUP BY time($interval) fill(null) +``` + #### Administrative access Access `http://${HOSTNAME}:${GRAFANA_PORT}` ([http://localhost:3000](`http://localhost:3000`) by default) and login using the following default credentials: diff --git a/docker/speedtest/index.js b/docker/speedtest/index.js index 64f33c8..89e2975 100644 --- a/docker/speedtest/index.js +++ b/docker/speedtest/index.js @@ -8,6 +8,9 @@ process.env.INFLUXDB_USERNAME = (process.env.INFLUXDB_DB) ? process.env.INFLUXDB process.env.INFLUXDB_PASSWORD = (process.env.INFLUXDB_DB) ? process.env.INFLUXDB_DB : 'root'; process.env.SPEEDTEST_HOST = (process.env.SPEEDTEST_HOST) ? process.env.SPEEDTEST_HOST : 'local'; process.env.SPEEDTEST_INTERVAL = (process.env.SPEEDTEST_INTERVAL) ? process.env.SPEEDTEST_INTERVAL : 3600; +process.env.SPEEDTEST_ENHANCED_LOGGING = (process.env.SPEEDTEST_ENHANCED_LOGGING) ? process.env.SPEEDTEST_ENHANCED_LOGGING : 'false'; +process.env.INFLUX_MEASUREMENT = (process.env.INFLUX_MEASUREMENT) ? process.env.INFLUX_MEASUREMENT : 'results'; +const enhancedLogging = (process.env.SPEEDTEST_ENHANCED_LOGGING.toLowerCase() != 'false') ? true : false; const bitToMbps = bit => (bit / 1000 / 1000) * 8; @@ -21,19 +24,66 @@ const getSpeedMetrics = async () => { const { stdout } = await execa("speedtest", args); const result = JSON.parse(stdout); - return { - upload: bitToMbps(result.upload.bandwidth), - download: bitToMbps(result.download.bandwidth), - ping: result.ping.latency - }; + + return result; }; const pushToInflux = async (influx, metrics) => { - const points = Object.entries(metrics).map(([measurement, value]) => ({ - measurement, - tags: { host: process.env.SPEEDTEST_HOST }, - fields: { value } - })); + var points = {}; + if (enhancedLogging) { + // Enhanced Logging + // Create InfluxDB data point with all the JSON data in a single measurement. Note in enhanced logging the data is written as-is with no conversion from bitsToMbps + // There's likely a better way of just cycling through the JSON and converting to fields rather than specifying all fields directly below? + + points = [{ + measurement: process.env.INFLUX_MEASUREMENT, + tags: { host: process.env.SPEEDTEST_HOST }, + fields: { + type: metrics.type, + timestamp: metrics.timestamp, + ping_jitter: metrics.ping.jitter, + ping_latency: metrics.ping.latency, + download_bandwidth: metrics.download.bandwidth, + download_bytes: metrics.download.bytes, + download_elapsed: metrics.download.elapsed, + upload_bandwidth: metrics.upload.bandwidth, + upload_bytes: metrics.upload.bytes, + upload_elapsed: metrics.upload.elapsed, + packetLoss: metrics.packetLoss, + isp: metrics.isp, + interface_internalIp: metrics.interface.internalIp, + interface_name: metrics.interface.name, + interface_macAddr: metrics.interface.macAddr, + interface_isVpn: metrics.interface.isVpn, + interface_externalIp: metrics.interface.externalIp, + server_id: metrics.server.id, + server_name: metrics.server.name, + server_location: metrics.server.location, + server_country: metrics.server.country, + server_host: metrics.server.host, + server_port: metrics.server.port, + server_ip: metrics.server.ip, + result_id: metrics.result.id, + result_url: metrics.result.url + } + }]; + + } else { + // Legacy logging + + legacy_metrics = { + upload: bitToMbps(metrics.upload.bandwidth), + download: bitToMbps(metrics.download.bandwidth), + ping: metrics.ping.latency + }; + + points = Object.entries(legacy_metrics).map(([measurement, value]) => ({ + measurement, + tags: { host: process.env.SPEEDTEST_HOST }, + fields: { value } + })); + + } await influx.writePoints(points); }; @@ -50,9 +100,9 @@ const pushToInflux = async (influx, metrics) => { while (true) { log("Starting speedtest..."); const speedMetrics = await getSpeedMetrics(); - log( - `Speedtest results - Download: ${speedMetrics.download}, Upload: ${speedMetrics.upload}, Ping: ${speedMetrics.ping}` - ); + + log(`Speedtest results - Server: ${speedMetrics.server.name} (${speedMetrics.server.location}, ${speedMetrics.server.country}), Download: ${(bitToMbps(speedMetrics.download.bandwidth)).toFixed(2)}Mbps, Upload: ${(bitToMbps(speedMetrics.upload.bandwidth)).toFixed(2)}Mbps, Ping: ${(speedMetrics.ping.latency).toFixed(2)}ms`); + await pushToInflux(influx, speedMetrics); log(`Sleeping for ${process.env.SPEEDTEST_INTERVAL} seconds...`);