From 7b8e4225f9af3102dffdb1fb5ec075b877591db8 Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Wed, 25 Feb 2026 22:12:12 -0800 Subject: [PATCH] Add Transmission metrics exporter and Grafana dashboard Add metalmatze/transmission-exporter as a sidecar to the torrent deployment, expose metrics on port 19091, configure Prometheus scraping, and create a Grafana dashboard with speed stats, transfer volumes, per-torrent breakdowns, and a details table. Co-Authored-By: Claude Opus 4.6 --- .../dashboards/configmap-transmission.yaml | 591 ++++++++++++++++++ .../grafana-config/kustomization.yaml | 1 + argocd/manifests/prometheus/prometheus.yml | 8 + argocd/manifests/torrent/deployment.yaml | 14 + argocd/manifests/torrent/service.yaml | 3 + .../feature-transmission-dashboard.feature.md | 1 + 6 files changed, 618 insertions(+) create mode 100644 argocd/manifests/grafana-config/dashboards/configmap-transmission.yaml create mode 100644 docs/changelog.d/feature-transmission-dashboard.feature.md diff --git a/argocd/manifests/grafana-config/dashboards/configmap-transmission.yaml b/argocd/manifests/grafana-config/dashboards/configmap-transmission.yaml new file mode 100644 index 0000000..d380fc3 --- /dev/null +++ b/argocd/manifests/grafana-config/dashboards/configmap-transmission.yaml @@ -0,0 +1,591 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: grafana-dashboard-transmission + namespace: monitoring + labels: + grafana_dashboard: "1" +data: + transmission.json: | + { + "annotations": { + "list": [] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [], + "panels": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "thresholds" }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 1048576 }, + { "color": "red", "value": 10485760 } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { "h": 4, "w": 6, "x": 0, "y": 0 }, + "id": 1, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "expr": "transmission_session_stats_download_speed_bytes", + "refId": "A" + } + ], + "title": "Download Speed", + "type": "stat" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "thresholds" }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 1048576 }, + { "color": "red", "value": 10485760 } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { "h": 4, "w": 6, "x": 6, "y": 0 }, + "id": 2, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "expr": "transmission_session_stats_upload_speed_bytes", + "refId": "A" + } + ], + "title": "Upload Speed", + "type": "stat" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "thresholds" }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [{ "color": "green", "value": null }] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { "h": 4, "w": 6, "x": 12, "y": 0 }, + "id": 3, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "expr": "transmission_session_stats_torrents_active", + "refId": "A" + } + ], + "title": "Active Torrents", + "type": "stat" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "thresholds" }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [{ "color": "blue", "value": null }] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { "h": 4, "w": 6, "x": 18, "y": 0 }, + "id": 4, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "expr": "transmission_session_stats_torrents_total", + "refId": "A" + } + ], + "title": "Total Torrents", + "type": "stat" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "smooth", + "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": "Bps" + }, + "overrides": [ + { + "matcher": { "id": "byName", "options": "Download" }, + "properties": [ + { "id": "color", "value": { "fixedColor": "green", "mode": "fixed" } } + ] + }, + { + "matcher": { "id": "byName", "options": "Upload" }, + "properties": [ + { "id": "color", "value": { "fixedColor": "blue", "mode": "fixed" } } + ] + } + ] + }, + "gridPos": { "h": 8, "w": 24, "x": 0, "y": 4 }, + "id": 5, + "options": { + "legend": { + "calcs": ["mean", "max"], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { "mode": "multi", "sort": "desc" } + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "expr": "transmission_session_stats_download_speed_bytes", + "legendFormat": "Download", + "refId": "A" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "expr": "transmission_session_stats_upload_speed_bytes", + "legendFormat": "Upload", + "refId": "B" + } + ], + "title": "Transfer Speed", + "type": "timeseries" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "thresholds" }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [{ "color": "green", "value": null }] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { "h": 4, "w": 12, "x": 0, "y": 12 }, + "id": 6, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "expr": "increase(transmission_session_stats_downloaded_bytes{type=\"cumulative\"}[$__range])", + "refId": "A" + } + ], + "title": "Downloaded (selected range)", + "type": "stat" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "thresholds" }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [{ "color": "blue", "value": null }] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { "h": 4, "w": 12, "x": 12, "y": 12 }, + "id": 7, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "expr": "increase(transmission_session_stats_uploaded_bytes{type=\"cumulative\"}[$__range])", + "refId": "A" + } + ], + "title": "Uploaded (selected range)", + "type": "stat" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "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": "Bps" + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 0, "y": 16 }, + "id": 8, + "options": { + "legend": { + "calcs": ["mean", "max"], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { "mode": "multi", "sort": "desc" } + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "expr": "transmission_torrent_download_bytes > 0", + "legendFormat": "{{name}}", + "refId": "A" + } + ], + "title": "Download Rate by Torrent", + "type": "timeseries" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "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": "Bps" + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 12, "y": 16 }, + "id": 9, + "options": { + "legend": { + "calcs": ["mean", "max"], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { "mode": "multi", "sort": "desc" } + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "expr": "transmission_torrent_upload_bytes > 0", + "legendFormat": "{{name}}", + "refId": "A" + } + ], + "title": "Upload Rate by Torrent", + "type": "timeseries" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "thresholds" }, + "custom": { + "align": "auto", + "cellOptions": { "type": "auto" }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [{ "color": "green", "value": null }] + } + }, + "overrides": [ + { + "matcher": { "id": "byName", "options": "name" }, + "properties": [ + { "id": "custom.width", "value": 400 } + ] + }, + { + "matcher": { "id": "byName", "options": "Value #B" }, + "properties": [ + { "id": "unit", "value": "bytes" }, + { "id": "displayName", "value": "Uploaded" } + ] + }, + { + "matcher": { "id": "byName", "options": "Value #A" }, + "properties": [ + { "id": "displayName", "value": "Ratio" } + ] + }, + { + "matcher": { "id": "byName", "options": "Value #C" }, + "properties": [ + { "id": "unit", "value": "percentunit" }, + { "id": "displayName", "value": "Done" } + ] + } + ] + }, + "gridPos": { "h": 8, "w": 24, "x": 0, "y": 24 }, + "id": 10, + "options": { + "cellHeight": "sm", + "footer": { "countRows": false, "fields": "", "reducer": ["sum"], "show": false }, + "showHeader": true, + "sortBy": [ + { "desc": true, "displayName": "Ratio" } + ] + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "expr": "transmission_torrent_ratio", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "A" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "expr": "transmission_torrent_uploaded_ever", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "B" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "expr": "transmission_torrent_done", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "C" + } + ], + "title": "Torrent Details", + "transformations": [ + { + "id": "seriesToColumns", + "options": { + "byField": "name" + } + }, + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Time 1": true, + "Time 2": true, + "Time 3": true, + "__name__": true, + "__name__ 1": true, + "__name__ 2": true, + "__name__ 3": true, + "cluster": true, + "cluster 1": true, + "cluster 2": true, + "cluster 3": true, + "instance": true, + "instance 1": true, + "instance 2": true, + "instance 3": true, + "job": true, + "job 1": true, + "job 2": true, + "job 3": true + }, + "indexByName": { + "name": 0, + "Value #A": 1, + "Value #B": 2, + "Value #C": 3 + }, + "renameByName": { + "name": "Torrent" + } + } + } + ], + "type": "table" + } + ], + "refresh": "30s", + "schemaVersion": 38, + "tags": ["transmission", "torrent", "bittorrent"], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Transmission", + "uid": "transmission", + "version": 1, + "weekStart": "" + } diff --git a/argocd/manifests/grafana-config/kustomization.yaml b/argocd/manifests/grafana-config/kustomization.yaml index 95bb4bb..e565bf7 100644 --- a/argocd/manifests/grafana-config/kustomization.yaml +++ b/argocd/manifests/grafana-config/kustomization.yaml @@ -19,6 +19,7 @@ resources: - dashboards/configmap-ringtail.yaml - dashboards/configmap-zot.yaml - dashboards/configmap-frigate.yaml + - dashboards/configmap-transmission.yaml - dashboards/configmap-cv-apm.yaml - dashboards/configmap-docs-apm.yaml - dashboards/configmap-flyio.yaml diff --git a/argocd/manifests/prometheus/prometheus.yml b/argocd/manifests/prometheus/prometheus.yml index 524e9f8..3197ca6 100644 --- a/argocd/manifests/prometheus/prometheus.yml +++ b/argocd/manifests/prometheus/prometheus.yml @@ -56,6 +56,14 @@ scrape_configs: - target_label: cluster replacement: indri + # Transmission BitTorrent metrics (via sidecar exporter) + - job_name: "transmission" + static_configs: + - targets: ["transmission.torrent.svc.cluster.local:19091"] + metric_relabel_configs: + - target_label: cluster + replacement: indri + # Frigate NVR metrics (via Caddy on indri — Frigate runs on ringtail) - job_name: "frigate" scheme: https diff --git a/argocd/manifests/torrent/deployment.yaml b/argocd/manifests/torrent/deployment.yaml index bf1e8b1..dfad219 100644 --- a/argocd/manifests/torrent/deployment.yaml +++ b/argocd/manifests/torrent/deployment.yaml @@ -55,6 +55,20 @@ spec: port: 9091 initialDelaySeconds: 10 periodSeconds: 10 + - name: transmission-exporter + image: docker.io/metalmatze/transmission-exporter:master + env: + - name: TRANSMISSION_ADDR + value: "http://localhost:9091" + ports: + - containerPort: 19091 + name: metrics + resources: + requests: + memory: "32Mi" + cpu: "10m" + limits: + memory: "64Mi" volumes: - name: downloads persistentVolumeClaim: diff --git a/argocd/manifests/torrent/service.yaml b/argocd/manifests/torrent/service.yaml index 51f7592..a54fc93 100644 --- a/argocd/manifests/torrent/service.yaml +++ b/argocd/manifests/torrent/service.yaml @@ -11,3 +11,6 @@ spec: - name: web port: 9091 targetPort: 9091 + - name: metrics + port: 19091 + targetPort: 19091 diff --git a/docs/changelog.d/feature-transmission-dashboard.feature.md b/docs/changelog.d/feature-transmission-dashboard.feature.md new file mode 100644 index 0000000..1209802 --- /dev/null +++ b/docs/changelog.d/feature-transmission-dashboard.feature.md @@ -0,0 +1 @@ +Add Transmission Grafana dashboard with metrics exporter sidecar for monitoring upload/download speeds, transfer volumes, and per-torrent breakdowns. -- 2.50.1 (Apple Git-155)