diff --git a/cmd/wg-portal/main.go b/cmd/wg-portal/main.go index 65713c1..a206262 100644 --- a/cmd/wg-portal/main.go +++ b/cmd/wg-portal/main.go @@ -50,7 +50,7 @@ func main() { mailer := adapters.NewSmtpMailRepo(cfg.Mail) - metricsServer := adapters.NewMetricsServer(cfg, database) + metricsServer := adapters.NewMetricsServer(cfg) cfgFileSystem, err := adapters.NewFileSystemRepository(cfg.Advanced.ConfigStoragePath) internal.AssertNoError(err) diff --git a/deploy/helm/Chart.yaml b/deploy/helm/Chart.yaml index a7abd35..c582041 100644 --- a/deploy/helm/Chart.yaml +++ b/deploy/helm/Chart.yaml @@ -16,7 +16,7 @@ annotations: # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.3.0 +version: 0.4.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/deploy/helm/README.md b/deploy/helm/README.md index 5914960..8b758c9 100644 --- a/deploy/helm/README.md +++ b/deploy/helm/README.md @@ -1,6 +1,6 @@ # wg-portal -![Version: 0.3.0](https://img.shields.io/badge/Version-0.3.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: latest](https://img.shields.io/badge/AppVersion-latest-informational?style=flat-square) +![Version: 0.4.0](https://img.shields.io/badge/Version-0.4.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: latest](https://img.shields.io/badge/AppVersion-latest-informational?style=flat-square) WireGuard Configuration Portal with LDAP, OAuth, OIDC authentication @@ -110,9 +110,13 @@ The [Values](#values) section lists the parameters that can be configured during | monitoring.kind | string | `"PodMonitor"` | Kind of the Prometheus resource. Could be `PodMonitor` or `ServiceMonitor`. | | monitoring.labels | object | `{}` | Resource labels. | | monitoring.annotations | object | `{}` | Resource annotations. | -| monitoring.interval | string | `""` | Interval at which metrics should be scraped. If not specified Prometheus' global scrape interval is used. | +| monitoring.interval | string | `1m` | Interval at which metrics should be scraped. If not specified `config.statistics.data_collection_interval` interval is used. | | monitoring.metricRelabelings | list | `[]` | Relabelings to samples before ingestion. | | monitoring.relabelings | list | `[]` | Relabelings to samples before scraping. | | monitoring.scrapeTimeout | string | `""` | Timeout after which the scrape is ended If not specified, the Prometheus global scrape interval is used. | | monitoring.jobLabel | string | `""` | The label to use to retrieve the job name from. | | monitoring.podTargetLabels | object | `{}` | Transfers labels on the Kubernetes Pod onto the target. | +| monitoring.dashboard.enabled | bool | `false` | Enable Grafana dashboard. | +| monitoring.dashboard.annotations | object | `{}` | Annotations for the dashboard ConfigMap. | +| monitoring.dashboard.labels | object | `{}` | Additional labels for the dashboard ConfigMap. | +| monitoring.dashboard.namespace | string | `""` | Dashboard ConfigMap namespace Overrides the namespace for the dashboard ConfigMap. | diff --git a/deploy/helm/files/dashboard.json b/deploy/helm/files/dashboard.json new file mode 100644 index 0000000..716dea9 --- /dev/null +++ b/deploy/helm/files/dashboard.json @@ -0,0 +1,880 @@ +{ + "annotations": {}, + "description": "WireGuard Portal Dashboard", + "panels": [ + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": 3600000, + "lineInterpolation": "smooth", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (instance, interface) (wireguard_interface_received_bytes_total{instance=\"$instance\", interface=~\"$interface\"})", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "interval": "", + "legendFormat": "Received {{interface}}", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (instance, interface) (wireguard_interface_sent_bytes_total{instance=\"$instance\", interface=~\"$interface\"})", + "hide": false, + "instant": false, + "legendFormat": "Sent {{interface}}", + "range": true, + "refId": "B" + } + ], + "title": "Interface Bytes Total", + "type": "timeseries" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": 3600000, + "lineInterpolation": "smooth", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 13, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (instance, interface) (rate(wireguard_interface_received_bytes_total{instance=\"$instance\", interface=~\"$interface\"}[$__rate_interval]))", + "hide": false, + "instant": false, + "interval": "$__rate_interval", + "legendFormat": "Received {{interface}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (instance, interface) (rate(wireguard_interface_sent_bytes_total{instance=\"$instance\", interface=~\"$interface\"}[$__rate_interval]))", + "hide": false, + "instant": false, + "interval": "$__rate_interval", + "legendFormat": "Sent {{interface}}", + "range": true, + "refId": "B" + } + ], + "title": "Interface Bandwidth", + "type": "timeseries" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": 3600000, + "lineInterpolation": "smooth", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 9 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (name, instance, interface) (rate(wireguard_peer_received_bytes_total{instance=\"$instance\", interface=~\"$interface\"}[$__rate_interval]))", + "hide": false, + "instant": false, + "interval": "$__rate_interval", + "legendFormat": "{{name}}", + "range": true, + "refId": "A" + } + ], + "title": "Peer Receive Bandwidth", + "type": "timeseries" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": 3600000, + "lineInterpolation": "smooth", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 9 + }, + "id": 17, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (instance, interface, name) (rate(wireguard_peer_sent_bytes_total{instance=\"$instance\", interface=~\"$interface\"}[$__rate_interval]))", + "hide": false, + "instant": false, + "interval": "$__rate_interval", + "legendFormat": "{{name}}", + "range": true, + "refId": "A" + } + ], + "title": "Peer Transmit Bandwidth", + "type": "timeseries" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 60, + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 1 + } + ] + }, + "unit": "bool_yes_no" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 24, + "x": 0, + "y": 18 + }, + "id": 12, + "options": { + "colWidth": 0.85, + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "rowHeight": 0.85, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(wireguard_peer_up{instance=\"$instance\", interface=~\"$interface\"}) by (id, instance, interface, name,)", + "instant": false, + "interval": "$__rate_interval", + "legendFormat": "{{name}}", + "range": true, + "refId": "A" + } + ], + "title": "Peer Connection History", + "type": "status-history" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic-by-name" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto", + "wrapText": false + }, + "filterable": false, + "inspect": false + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/(Time|instance|interface|name)\\s\\d*/" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/Received|Transmitted/" + }, + "properties": [ + { + "id": "unit", + "value": "bytes" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Last Handshake" + }, + "properties": [ + { + "id": "unit", + "value": "s" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Connected" + }, + "properties": [ + { + "id": "mappings", + "value": [ + { + "options": { + "0": { + "color": "red", + "index": 0, + "text": "No" + }, + "1": { + "color": "green", + "index": 1, + "text": "Yes" + } + }, + "type": "value" + } + ] + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + } + ] + } + ] + }, + "gridPos": { + "h": 14, + "w": 24, + "x": 0, + "y": 29 + }, + "id": 11, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "enablePagination": false, + "fields": [], + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Sent" + } + ] + }, + "pluginVersion": "11.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "sum by(id, instance, interface, name, addresses) (increase(wireguard_peer_received_bytes_total{instance=\"$instance\", interface=~\"$interface\"}[$__range]))", + "format": "table", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "interval": "", + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "sum by(id, instance, interface, name) (increase(wireguard_peer_sent_bytes_total{instance=\"$instance\", interface=~\"$interface\"}[$__range]))", + "format": "table", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "interval": "", + "legendFormat": "__auto", + "range": true, + "refId": "B", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "time()-sum(wireguard_peer_last_handshake_seconds{instance=\"$instance\", interface=~\"$interface\"}) by(id, instance, interface, name) ", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "legendFormat": "__auto", + "range": false, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(wireguard_peer_up{instance=\"$instance\", interface=~\"$interface\"}) by(id, instance, interface, name) ", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "legendFormat": "__auto", + "range": false, + "refId": "D" + } + ], + "title": "Peer Info", + "transformations": [ + { + "id": "joinByField", + "options": { + "byField": "id", + "mode": "outer" + } + }, + { + "id": "organize", + "options": { + "excludeByName": { + "Time 1": false, + "Time 2": false, + "Time 3": false, + "Time 4": false + }, + "includeByName": {}, + "indexByName": { + "Time 1": 8, + "Time 2": 9, + "Time 3": 10, + "Time 4": 11, + "Value #A": 4, + "Value #B": 5, + "Value #C": 6, + "Value #D": 7, + "addresses": 2, + "id": 3, + "instance 1": 12, + "instance 2": 13, + "instance 3": 16, + "instance 4": 19, + "interface 1": 0, + "interface 2": 14, + "interface 3": 17, + "interface 4": 20, + "name 1": 1, + "name 2": 15, + "name 3": 18, + "name 4": 21 + }, + "renameByName": { + "Value #A": "Received", + "Value #B": "Transmitted", + "Value #C": "Last Handshake", + "Value #D": "Connected", + "addresses": "IP Addresses", + "id": "Public Key", + "interface": "Interface", + "interface 1": "Interface", + "name": "Name", + "name 1": "Name" + } + } + } + ], + "type": "table" + } + ], + "refresh": "30s", + "tags": [ + "wireguard", + "vpn" + ], + "templating": { + "list": [ + { + "current": {}, + "hide": 0, + "includeAll": false, + "label": "Prometheus", + "multi": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "label_values(wireguard_interface_sent_bytes_total,instance)", + "hide": 0, + "includeAll": false, + "label": "Instance", + "multi": false, + "name": "instance", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(wireguard_interface_sent_bytes_total,instance)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "label_values(wireguard_interface_sent_bytes_total{instance=\"$instance\"},interface)", + "hide": 0, + "includeAll": true, + "label": "Interface", + "multi": true, + "name": "interface", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(wireguard_interface_sent_bytes_total{instance=\"$instance\"},interface)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-12h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "WireGuard Portal", + "uid": "wireguard-portal", + "weekStart": "" +} diff --git a/deploy/helm/templates/cm-dashboards.yaml b/deploy/helm/templates/cm-dashboards.yaml new file mode 100644 index 0000000..181fea2 --- /dev/null +++ b/deploy/helm/templates/cm-dashboards.yaml @@ -0,0 +1,14 @@ +{{- with .Values.monitoring.dashboard -}} +{{- if .enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + {{- with .annotations }} + annotations: {{- toYaml . | nindent 4 }} + {{- end }} + labels: {{- include "wg-portal.util.merge" (list $ .labels "wg-portal.labels") | nindent 4 }} + name: {{ printf "grafana-dashboards-%s" (include "wg-portal.fullname" $) }} + namespace: {{ default $.Release.Namespace .namespace }} +data: {{ ($.Files.Glob "files/dashboard.json").AsConfig | nindent 2 }} +{{- end -}} +{{- end -}} diff --git a/deploy/helm/templates/monitoring.yaml b/deploy/helm/templates/monitoring.yaml index 2d6e3ce..4e10904 100644 --- a/deploy/helm/templates/monitoring.yaml +++ b/deploy/helm/templates/monitoring.yaml @@ -19,9 +19,7 @@ spec: {{ $endpointsKey }}: - port: metrics path: /metrics - {{- with .interval }} - interval: {{ . }} - {{- end }} + interval: {{ coalesce .interval ($.Values.config.statistics).data_collection_interval "1m" }} {{- with .metricRelabelings }} metricRelabelings: {{- toYaml . | nindent 8 }} {{- end }} diff --git a/deploy/helm/values.yaml b/deploy/helm/values.yaml index 0cff1b4..59e621e 100644 --- a/deploy/helm/values.yaml +++ b/deploy/helm/values.yaml @@ -218,7 +218,8 @@ monitoring: labels: {} # -- Resource annotations. annotations: {} - # -- Interval at which metrics should be scraped. If not specified Prometheus' global scrape interval is used. + # -- Interval at which metrics should be scraped. If not specified `config.statistics.data_collection_interval` interval is used. + # @default -- `1m` interval: '' # -- Relabelings to samples before ingestion. metricRelabelings: [] @@ -230,3 +231,14 @@ monitoring: jobLabel: '' # -- Transfers labels on the Kubernetes Pod onto the target. podTargetLabels: {} + + dashboard: + # -- Enable Grafana dashboard. + enabled: false + # -- Annotations for the dashboard ConfigMap. + annotations: {} + # -- Additional labels for the dashboard ConfigMap. + labels: {} + # -- Dashboard ConfigMap namespace + # Overrides the namespace for the dashboard ConfigMap. + namespace: '' diff --git a/internal/adapters/metrics.go b/internal/adapters/metrics.go index 0dfe4a8..82abdb7 100644 --- a/internal/adapters/metrics.go +++ b/internal/adapters/metrics.go @@ -16,12 +16,9 @@ import ( type MetricsServer struct { *http.Server - db *SqlRepo - ifaceInfo *prometheus.GaugeVec ifaceReceivedBytesTotal *prometheus.GaugeVec ifaceSendBytesTotal *prometheus.GaugeVec - peerInfo *prometheus.GaugeVec peerIsConnected *prometheus.GaugeVec peerLastHandshakeSeconds *prometheus.GaugeVec peerReceivedBytesTotal *prometheus.GaugeVec @@ -30,13 +27,12 @@ type MetricsServer struct { // Wireguard metrics labels var ( - labels = []string{"interface"} - ifaceLabels = []string{} - peerLabels = []string{"addresses", "id", "name"} + ifaceLabels = []string{"interface"} + peerLabels = []string{"interface", "addresses", "id", "name"} ) // NewMetricsServer returns a new prometheus server -func NewMetricsServer(cfg *config.Config, db *SqlRepo) *MetricsServer { +func NewMetricsServer(cfg *config.Config) *MetricsServer { reg := prometheus.NewRegistry() mux := http.NewServeMux() @@ -47,56 +43,43 @@ func NewMetricsServer(cfg *config.Config, db *SqlRepo) *MetricsServer { Addr: cfg.Statistics.ListeningAddress, Handler: mux, }, - db: db, - ifaceInfo: promauto.With(reg).NewGaugeVec( - prometheus.GaugeOpts{ - Name: "wireguard_interface_info", - Help: "Interface info.", - }, append(labels, ifaceLabels...), - ), ifaceReceivedBytesTotal: promauto.With(reg).NewGaugeVec( prometheus.GaugeOpts{ Name: "wireguard_interface_received_bytes_total", Help: "Bytes received througth the interface.", - }, append(labels, ifaceLabels...), + }, ifaceLabels, ), ifaceSendBytesTotal: promauto.With(reg).NewGaugeVec( prometheus.GaugeOpts{ Name: "wireguard_interface_sent_bytes_total", Help: "Bytes sent through the interface.", - }, append(labels, ifaceLabels...), + }, ifaceLabels, ), - peerInfo: promauto.With(reg).NewGaugeVec( - prometheus.GaugeOpts{ - Name: "wireguard_peer_info", - Help: "Peer info.", - }, append(labels, peerLabels...), - ), peerIsConnected: promauto.With(reg).NewGaugeVec( prometheus.GaugeOpts{ Name: "wireguard_peer_up", Help: "Peer connection state (boolean: 1/0).", - }, append(labels, peerLabels...), + }, peerLabels, ), peerLastHandshakeSeconds: promauto.With(reg).NewGaugeVec( prometheus.GaugeOpts{ Name: "wireguard_peer_last_handshake_seconds", Help: "Seconds from the last handshake with the peer.", - }, append(labels, peerLabels...), + }, peerLabels, ), peerReceivedBytesTotal: promauto.With(reg).NewGaugeVec( prometheus.GaugeOpts{ Name: "wireguard_peer_received_bytes_total", Help: "Bytes received from the peer.", - }, append(labels, peerLabels...), + }, peerLabels, ), peerSendBytesTotal: promauto.With(reg).NewGaugeVec( prometheus.GaugeOpts{ Name: "wireguard_peer_sent_bytes_total", Help: "Bytes sent to the peer.", - }, append(labels, peerLabels...), + }, peerLabels, ), } } @@ -130,20 +113,12 @@ func (m *MetricsServer) Run(ctx context.Context) { // UpdateInterfaceMetrics updates the metrics for the given interface func (m *MetricsServer) UpdateInterfaceMetrics(status domain.InterfaceStatus) { labels := []string{string(status.InterfaceId)} - m.ifaceInfo.WithLabelValues(labels...).Set(1) m.ifaceReceivedBytesTotal.WithLabelValues(labels...).Set(float64(status.BytesReceived)) m.ifaceSendBytesTotal.WithLabelValues(labels...).Set(float64(status.BytesTransmitted)) } // UpdatePeerMetrics updates the metrics for the given peer -func (m *MetricsServer) UpdatePeerMetrics(ctx context.Context, status domain.PeerStatus) { - // Fetch peer data from the database - peer, err := m.db.GetPeer(ctx, status.PeerId) - if err != nil { - logrus.Warnf("failed to fetch peer data for labels %s: %v", status.PeerId, err) - return - } - +func (m *MetricsServer) UpdatePeerMetrics(peer *domain.Peer, status domain.PeerStatus) { labels := []string{ string(peer.InterfaceIdentifier), string(peer.Interface.AddressStr()), @@ -151,7 +126,6 @@ func (m *MetricsServer) UpdatePeerMetrics(ctx context.Context, status domain.Pee string(peer.DisplayName), } - m.peerInfo.WithLabelValues(labels...).Set(1) if status.LastHandshake != nil { m.peerLastHandshakeSeconds.WithLabelValues(labels...).Set(float64(status.LastHandshake.Unix())) } diff --git a/internal/app/wireguard/repos.go b/internal/app/wireguard/repos.go index 320f8be..83c4bce 100644 --- a/internal/app/wireguard/repos.go +++ b/internal/app/wireguard/repos.go @@ -53,5 +53,5 @@ type WgQuickController interface { type MetricsServer interface { UpdateInterfaceMetrics(status domain.InterfaceStatus) - UpdatePeerMetrics(ctx context.Context, status domain.PeerStatus) + UpdatePeerMetrics(peer *domain.Peer, status domain.PeerStatus) } diff --git a/internal/app/wireguard/statistics.go b/internal/app/wireguard/statistics.go index bfc40a7..96ecc68 100644 --- a/internal/app/wireguard/statistics.go +++ b/internal/app/wireguard/statistics.go @@ -75,7 +75,8 @@ func (c *StatisticsCollector) collectInterfaceData(ctx context.Context) { i.BytesTransmitted = physicalInterface.BytesUpload // Update prometheus metrics - go c.ms.UpdateInterfaceMetrics(*i) + go c.updateInterfaceMetrics(*i) + return i, nil }) if err != nil { @@ -134,7 +135,7 @@ func (c *StatisticsCollector) collectPeerData(ctx context.Context) { p.LastHandshake = lastHandshake // Update prometheus metrics - go c.ms.UpdatePeerMetrics(ctx, *p) + go c.updatePeerMetrics(ctx, *p) return p, nil }) @@ -272,3 +273,17 @@ func (c *StatisticsCollector) isPeerPingable(ctx context.Context, peer domain.Pe stats := pinger.Statistics() return stats.PacketsRecv == checkCount } + +func (c *StatisticsCollector) updateInterfaceMetrics(status domain.InterfaceStatus) { + c.ms.UpdateInterfaceMetrics(status) +} + +func (c *StatisticsCollector) updatePeerMetrics(ctx context.Context, status domain.PeerStatus) { + // Fetch peer data from the database + peer, err := c.db.GetPeer(ctx, status.PeerId) + if err != nil { + logrus.Warnf("failed to fetch peer data for metrics %s: %v", status.PeerId, err) + return + } + c.ms.UpdatePeerMetrics(peer, status) +}