mirror of
https://github.com/h44z/wg-portal.git
synced 2025-06-28 01:07:03 +00:00
feat: Metrics for Prometheus (#309)
* feat: prometheus metrics * Added Prometheus resources support to helm chart
This commit is contained in:
parent
ae1be0e367
commit
f22a7e4a2e
@ -59,8 +59,10 @@ ENV TZ=UTC
|
|||||||
COPY --from=builder /build/dist/wg-portal /app/wg-portal
|
COPY --from=builder /build/dist/wg-portal /app/wg-portal
|
||||||
# Set the Current Working Directory inside the container
|
# Set the Current Working Directory inside the container
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
# by default, the web-portal is reachable on port 8888
|
# Expose default ports for metrics, web and wireguard
|
||||||
|
EXPOSE 8787/tcp
|
||||||
EXPOSE 8888/tcp
|
EXPOSE 8888/tcp
|
||||||
|
EXPOSE 51820/udp
|
||||||
# the database and config file can be mounted from the host
|
# the database and config file can be mounted from the host
|
||||||
VOLUME [ "/app/data", "/app/config" ]
|
VOLUME [ "/app/data", "/app/config" ]
|
||||||
# Command to run the executable
|
# Command to run the executable
|
||||||
|
46
README.md
46
README.md
@ -37,6 +37,7 @@ The configuration portal supports using a database (SQLite, MySQL, MsSQL or Post
|
|||||||
* Support for multiple WireGuard interfaces
|
* Support for multiple WireGuard interfaces
|
||||||
* Peer Expiry Feature
|
* Peer Expiry Feature
|
||||||
* Handle route and DNS settings like wg-quick does
|
* Handle route and DNS settings like wg-quick does
|
||||||
|
* Exposes Prometheus [metrics](#metrics)
|
||||||
* ~~REST API for management and client deployment~~ (coming soon)
|
* ~~REST API for management and client deployment~~ (coming soon)
|
||||||
|
|
||||||

|

|
||||||
@ -79,10 +80,11 @@ The following configuration options are available:
|
|||||||
| ping_check_workers | statistics | 10 | Number of parallel ping checks that will be executed. |
|
| ping_check_workers | statistics | 10 | Number of parallel ping checks that will be executed. |
|
||||||
| ping_unprivileged | statistics | false | If set to false, the ping checks will run without root permissions (BETA). |
|
| ping_unprivileged | statistics | false | If set to false, the ping checks will run without root permissions (BETA). |
|
||||||
| ping_check_interval | statistics | 1m | The interval time between two ping check runs. |
|
| ping_check_interval | statistics | 1m | The interval time between two ping check runs. |
|
||||||
| data_collection_interval | statistics | 10m | The interval between the data collection cycles. |
|
| data_collection_interval | statistics | 1m | The interval between the data collection cycles. |
|
||||||
| collect_interface_data | statistics | true | A flag to enable interface data collection like bytes sent and received. |
|
| collect_interface_data | statistics | true | A flag to enable interface data collection like bytes sent and received. |
|
||||||
| collect_peer_data | statistics | true | A flag to enable peer data collection like bytes sent and received, last handshake and remote endpoint address. |
|
| collect_peer_data | statistics | true | A flag to enable peer data collection like bytes sent and received, last handshake and remote endpoint address. |
|
||||||
| collect_audit_data | statistics | true | If enabled, some events, like portal logins, will be logged to the database. |
|
| collect_audit_data | statistics | true | If enabled, some events, like portal logins, will be logged to the database. |
|
||||||
|
| listening_address | statistics | :8787 | The listening address of the Prometheus metric server. |
|
||||||
| host | mail | 127.0.0.1 | The mail-server address. |
|
| host | mail | 127.0.0.1 | The mail-server address. |
|
||||||
| port | mail | 25 | The mail-server SMTP port. |
|
| port | mail | 25 | The mail-server SMTP port. |
|
||||||
| encryption | mail | none | SMTP encryption type, allowed values: none, tls, starttls. |
|
| encryption | mail | none | SMTP encryption type, allowed values: none, tls, starttls. |
|
||||||
@ -204,6 +206,48 @@ make build
|
|||||||
* [Bootstrap](https://getbootstrap.com/), for the HTML templates
|
* [Bootstrap](https://getbootstrap.com/), for the HTML templates
|
||||||
* [Vue.JS](https://vuejs.org/), for the frontend
|
* [Vue.JS](https://vuejs.org/), for the frontend
|
||||||
|
|
||||||
|
## Metrics
|
||||||
|
|
||||||
|
Metrics are available if interface/peer statistic data collection is enabled.
|
||||||
|
|
||||||
|
Add following scrape job to your Prometheus config file:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# prometheus.yaml
|
||||||
|
scrape_configs:
|
||||||
|
- job_name: "wg-portal"
|
||||||
|
scrape_interval: 60s
|
||||||
|
static_configs:
|
||||||
|
- targets: ["wg-portal:8787"]
|
||||||
|
```
|
||||||
|
|
||||||
|
Exposed metrics:
|
||||||
|
|
||||||
|
```console
|
||||||
|
# HELP wireguard_interface_info Interface info.
|
||||||
|
# TYPE wireguard_interface_info gauge
|
||||||
|
|
||||||
|
# HELP wireguard_interface_received_bytes_total Bytes received througth the interface.
|
||||||
|
# TYPE wireguard_interface_received_bytes_total gauge
|
||||||
|
|
||||||
|
# HELP wireguard_interface_sent_bytes_total Bytes sent through the interface.
|
||||||
|
# TYPE wireguard_interface_sent_bytes_total gauge
|
||||||
|
|
||||||
|
# HELP wireguard_peer_info Peer info.
|
||||||
|
# TYPE wireguard_peer_info gauge
|
||||||
|
|
||||||
|
# HELP wireguard_peer_received_bytes_total Bytes received from the peer.
|
||||||
|
# TYPE wireguard_peer_received_bytes_total gauge
|
||||||
|
|
||||||
|
# HELP wireguard_peer_sent_bytes_total Bytes sent to the peer.
|
||||||
|
# TYPE wireguard_peer_sent_bytes_total gauge
|
||||||
|
|
||||||
|
# HELP wireguard_peer_up Peer connection state (boolean: 1/0).
|
||||||
|
# TYPE wireguard_peer_up gauge
|
||||||
|
|
||||||
|
# HELP wireguard_peer_last_handshake_seconds Seconds from the last handshake with the peer.
|
||||||
|
# TYPE wireguard_peer_last_handshake_seconds gauge
|
||||||
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
@ -2,6 +2,11 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/h44z/wg-portal/internal/app/api/core"
|
"github.com/h44z/wg-portal/internal/app/api/core"
|
||||||
handlersV0 "github.com/h44z/wg-portal/internal/app/api/v0/handlers"
|
handlersV0 "github.com/h44z/wg-portal/internal/app/api/v0/handlers"
|
||||||
"github.com/h44z/wg-portal/internal/app/audit"
|
"github.com/h44z/wg-portal/internal/app/audit"
|
||||||
@ -11,10 +16,6 @@ import (
|
|||||||
"github.com/h44z/wg-portal/internal/app/route"
|
"github.com/h44z/wg-portal/internal/app/route"
|
||||||
"github.com/h44z/wg-portal/internal/app/users"
|
"github.com/h44z/wg-portal/internal/app/users"
|
||||||
"github.com/h44z/wg-portal/internal/app/wireguard"
|
"github.com/h44z/wg-portal/internal/app/wireguard"
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/h44z/wg-portal/internal"
|
"github.com/h44z/wg-portal/internal"
|
||||||
"github.com/h44z/wg-portal/internal/adapters"
|
"github.com/h44z/wg-portal/internal/adapters"
|
||||||
@ -49,6 +50,8 @@ func main() {
|
|||||||
|
|
||||||
mailer := adapters.NewSmtpMailRepo(cfg.Mail)
|
mailer := adapters.NewSmtpMailRepo(cfg.Mail)
|
||||||
|
|
||||||
|
metricsServer := adapters.NewMetricsServer(cfg, database)
|
||||||
|
|
||||||
cfgFileSystem, err := adapters.NewFileSystemRepository(cfg.Advanced.ConfigStoragePath)
|
cfgFileSystem, err := adapters.NewFileSystemRepository(cfg.Advanced.ConfigStoragePath)
|
||||||
internal.AssertNoError(err)
|
internal.AssertNoError(err)
|
||||||
|
|
||||||
@ -75,7 +78,7 @@ func main() {
|
|||||||
wireGuardManager, err := wireguard.NewWireGuardManager(cfg, eventBus, wireGuard, wgQuick, database)
|
wireGuardManager, err := wireguard.NewWireGuardManager(cfg, eventBus, wireGuard, wgQuick, database)
|
||||||
internal.AssertNoError(err)
|
internal.AssertNoError(err)
|
||||||
|
|
||||||
statisticsCollector, err := wireguard.NewStatisticsCollector(cfg, database, wireGuard)
|
statisticsCollector, err := wireguard.NewStatisticsCollector(cfg, database, wireGuard, metricsServer)
|
||||||
internal.AssertNoError(err)
|
internal.AssertNoError(err)
|
||||||
|
|
||||||
cfgFileManager, err := configfile.NewConfigFileManager(cfg, eventBus, database, database, cfgFileSystem)
|
cfgFileManager, err := configfile.NewConfigFileManager(cfg, eventBus, database, database, cfgFileSystem)
|
||||||
@ -103,6 +106,7 @@ func main() {
|
|||||||
webSrv, err := core.NewServer(cfg, apiFrontend)
|
webSrv, err := core.NewServer(cfg, apiFrontend)
|
||||||
internal.AssertNoError(err)
|
internal.AssertNoError(err)
|
||||||
|
|
||||||
|
go metricsServer.Run(ctx)
|
||||||
go webSrv.Run(ctx, cfg.Web.ListeningAddress)
|
go webSrv.Run(ctx, cfg.Web.ListeningAddress)
|
||||||
|
|
||||||
// wait until context gets cancelled
|
// wait until context gets cancelled
|
||||||
|
@ -16,7 +16,7 @@ annotations:
|
|||||||
# This is the chart version. This version number should be incremented each time you make changes
|
# 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.
|
# to the chart and its templates, including the app version.
|
||||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||||
version: 0.2.0
|
version: 0.3.0
|
||||||
|
|
||||||
# This is the version number of the application being deployed. This version number should be
|
# 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
|
# incremented each time you make changes to the application. Versions are not expected to
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# wg-portal
|
# wg-portal
|
||||||
|
|
||||||
  
|
  
|
||||||
|
|
||||||
WireGuard Configuration Portal with LDAP, OAuth, OIDC authentication
|
WireGuard Configuration Portal with LDAP, OAuth, OIDC authentication
|
||||||
|
|
||||||
@ -76,6 +76,7 @@ The [Values](#values) section lists the parameters that can be configured during
|
|||||||
| service.wireguard.annotations | object | `{}` | Annotations for the WireGuard service |
|
| service.wireguard.annotations | object | `{}` | Annotations for the WireGuard service |
|
||||||
| service.wireguard.type | string | `"LoadBalancer"` | Wireguard service type |
|
| service.wireguard.type | string | `"LoadBalancer"` | Wireguard service type |
|
||||||
| service.wireguard.ports | list | `[51820]` | Wireguard service ports. Exposes the WireGuard ports for created interfaces. Lowerest port is selected as start port for the first interface. Increment next port by 1 for each additional interface. |
|
| service.wireguard.ports | list | `[51820]` | Wireguard service ports. Exposes the WireGuard ports for created interfaces. Lowerest port is selected as start port for the first interface. Increment next port by 1 for each additional interface. |
|
||||||
|
| service.metrics.port | int | `8787` | |
|
||||||
| ingress.enabled | bool | `false` | Specifies whether an ingress resource should be created |
|
| ingress.enabled | bool | `false` | Specifies whether an ingress resource should be created |
|
||||||
| ingress.className | string | `""` | Ingress class name |
|
| ingress.className | string | `""` | Ingress class name |
|
||||||
| ingress.annotations | object | `{}` | Ingress annotations |
|
| ingress.annotations | object | `{}` | Ingress annotations |
|
||||||
@ -104,3 +105,14 @@ The [Values](#values) section lists the parameters that can be configured during
|
|||||||
| serviceAccount.annotations | object | `{}` | Service account annotations |
|
| serviceAccount.annotations | object | `{}` | Service account annotations |
|
||||||
| serviceAccount.automount | bool | `false` | Automatically mount a ServiceAccount's API credentials |
|
| serviceAccount.automount | bool | `false` | Automatically mount a ServiceAccount's API credentials |
|
||||||
| serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template |
|
| serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template |
|
||||||
|
| monitoring.enabled | bool | `true` | Enable Prometheus monitoring. |
|
||||||
|
| monitoring.apiVersion | string | `"monitoring.coreos.com/v1"` | API version of the Prometheus resource. Use `azmonitoring.coreos.com/v1` for Azure Managed Prometheus. |
|
||||||
|
| 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.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. |
|
||||||
|
@ -107,3 +107,23 @@ Define hostname
|
|||||||
{{- (urlParse (tpl .Values.config.web.external_url .)).hostname -}}
|
{{- (urlParse (tpl .Values.config.web.external_url .)).hostname -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
wg-portal.util.merge will merge two YAML templates or dict with template and output the result.
|
||||||
|
This takes an array of three values:
|
||||||
|
- the top context
|
||||||
|
- the template name or dict of the overrides (destination)
|
||||||
|
- the template name of the base (source)
|
||||||
|
{{- include "wg-portal.util.merge" (list $ .Values.podLabels "wg-portal.selectorLabels") }}
|
||||||
|
{{- include "wg-portal.util.merge" (list $ "wg-portal.destTemplate" "wg-portal.sourceTemplate") }}
|
||||||
|
*/}}
|
||||||
|
{{- define "wg-portal.util.merge" -}}
|
||||||
|
{{- $top := first . -}}
|
||||||
|
{{- $overrides := index . 1 -}}
|
||||||
|
{{- $base := fromYaml (include (index . 2) $top) | default (dict) -}}
|
||||||
|
{{- if kindIs "string" $overrides -}}
|
||||||
|
{{- $overrides = fromYaml (include $overrides $top) | default (dict) -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- toYaml (merge $overrides $base) -}}
|
||||||
|
{{- end -}}
|
||||||
|
@ -6,11 +6,7 @@ metadata:
|
|||||||
{{- with .Values.podAnnotations }}
|
{{- with .Values.podAnnotations }}
|
||||||
{{- tpl (toYaml .) $ | nindent 4 }}
|
{{- tpl (toYaml .) $ | nindent 4 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
labels:
|
labels: {{- include "wg-portal.util.merge" (list $ .Values.podLabels "wg-portal.selectorLabels") | nindent 4 }}
|
||||||
{{- include "wg-portal.selectorLabels" . | nindent 4 }}
|
|
||||||
{{- with .Values.podLabels }}
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
spec:
|
||||||
{{- with .Values.affinity }}
|
{{- with .Values.affinity }}
|
||||||
affinity: {{- toYaml . | nindent 4 }}
|
affinity: {{- toYaml . | nindent 4 }}
|
||||||
@ -36,6 +32,9 @@ spec:
|
|||||||
envFrom: {{- tpl (toYaml .) $ | nindent 8 }}
|
envFrom: {{- tpl (toYaml .) $ | nindent 8 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
ports:
|
ports:
|
||||||
|
- name: metrics
|
||||||
|
containerPort: {{ .Values.service.metrics.port}}
|
||||||
|
protocol: TCP
|
||||||
- name: web
|
- name: web
|
||||||
containerPort: {{ .Values.service.web.port }}
|
containerPort: {{ .Values.service.web.port }}
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
|
41
deploy/helm/templates/monitoring.yaml
Normal file
41
deploy/helm/templates/monitoring.yaml
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{{- with .Values.monitoring -}}
|
||||||
|
{{- if and .enabled ($.Capabilities.APIVersions.Has .apiVersion) -}}
|
||||||
|
{{- $endpointsKey := (eq .kind "PodMonitor") | ternary "podMetricsEndpoints" "endpoints" -}}
|
||||||
|
apiVersion: {{ .apiVersion }}
|
||||||
|
kind: {{ .kind }}
|
||||||
|
metadata:
|
||||||
|
{{- with .annotations }}
|
||||||
|
annotations: {{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
labels: {{- include "wg-portal.util.merge" (list $ .labels "wg-portal.labels") | nindent 4 }}
|
||||||
|
name: {{ include "wg-portal.fullname" $ }}
|
||||||
|
spec:
|
||||||
|
namespaceSelector:
|
||||||
|
matchNames:
|
||||||
|
- {{ $.Release.Namespace }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "wg-portal.selectorLabels" $ | nindent 6 }}
|
||||||
|
{{ $endpointsKey }}:
|
||||||
|
- port: metrics
|
||||||
|
path: /metrics
|
||||||
|
{{- with .interval }}
|
||||||
|
interval: {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .metricRelabelings }}
|
||||||
|
metricRelabelings: {{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .relabelings }}
|
||||||
|
relabelings: {{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .scrapeTimeout }}
|
||||||
|
scrapeTimeout: {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .jobLabel }}
|
||||||
|
jobLabel: {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .podTargetLabels }}
|
||||||
|
podTargetLabels: {{- toYaml . | nindent 2 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
@ -27,9 +27,12 @@ stringData:
|
|||||||
mail: {{- tpl (toYaml .) $ | nindent 6 }}
|
mail: {{- tpl (toYaml .) $ | nindent 6 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{- with .Values.config.statistics }}
|
statistics:
|
||||||
statistics: {{- tpl (toYaml .) $ | nindent 6 }}
|
listening_address: :{{ .Values.service.metrics.port }}
|
||||||
{{- end }}
|
{{- with .Values.config.statistics }}
|
||||||
|
{{- tpl (toYaml (omit . "listening_address")) $ | nindent 6 }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
web:
|
web:
|
||||||
listening_address: :{{ .Values.service.web.port }}
|
listening_address: :{{ .Values.service.web.port }}
|
||||||
{{- with .Values.config.web }}
|
{{- with .Values.config.web }}
|
||||||
|
@ -12,3 +12,9 @@
|
|||||||
---
|
---
|
||||||
{{ include "wg-portal.service.tpl" (dict "context" . "scope" .Values.service.wireguard "ports" $ports "name" "wireguard") }}
|
{{ include "wg-portal.service.tpl" (dict "context" . "scope" .Values.service.wireguard "ports" $ports "name" "wireguard") }}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- if and .Values.monitoring.enabled (eq .Values.monitoring.kind "ServiceMonitor") }}
|
||||||
|
---
|
||||||
|
{{- $portsMetrics := list (dict "name" "metrics" "port" .Values.service.metrics.port "protocol" "TCP" "targetPort" "metrics") -}}
|
||||||
|
{{- include "wg-portal.service.tpl" (dict "context" . "scope" .Values.service.metrics "ports" $portsWeb "name" "metrics") }}
|
||||||
|
{{- end -}}
|
||||||
|
@ -134,6 +134,8 @@ service:
|
|||||||
# Increment next port by 1 for each additional interface.
|
# Increment next port by 1 for each additional interface.
|
||||||
ports:
|
ports:
|
||||||
- 51820
|
- 51820
|
||||||
|
metrics:
|
||||||
|
port: 8787
|
||||||
|
|
||||||
ingress:
|
ingress:
|
||||||
# -- Specifies whether an ingress resource should be created
|
# -- Specifies whether an ingress resource should be created
|
||||||
@ -202,3 +204,29 @@ serviceAccount:
|
|||||||
# -- The name of the service account to use.
|
# -- The name of the service account to use.
|
||||||
# If not set and create is true, a name is generated using the fullname template
|
# If not set and create is true, a name is generated using the fullname template
|
||||||
name: ''
|
name: ''
|
||||||
|
|
||||||
|
monitoring:
|
||||||
|
# -- Enable Prometheus monitoring.
|
||||||
|
enabled: true
|
||||||
|
# -- API version of the Prometheus resource.
|
||||||
|
# Use `azmonitoring.coreos.com/v1` for Azure Managed Prometheus.
|
||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
# -- Kind of the Prometheus resource.
|
||||||
|
# Could be `PodMonitor` or `ServiceMonitor`.
|
||||||
|
kind: PodMonitor
|
||||||
|
# -- Resource labels.
|
||||||
|
labels: {}
|
||||||
|
# -- Resource annotations.
|
||||||
|
annotations: {}
|
||||||
|
# -- Interval at which metrics should be scraped. If not specified Prometheus' global scrape interval is used.
|
||||||
|
interval: ''
|
||||||
|
# -- Relabelings to samples before ingestion.
|
||||||
|
metricRelabelings: []
|
||||||
|
# -- Relabelings to samples before scraping.
|
||||||
|
relabelings: []
|
||||||
|
# -- Timeout after which the scrape is ended If not specified, the Prometheus global scrape interval is used.
|
||||||
|
scrapeTimeout: ''
|
||||||
|
# -- The label to use to retrieve the job name from.
|
||||||
|
jobLabel: ''
|
||||||
|
# -- Transfers labels on the Kubernetes Pod onto the target.
|
||||||
|
podTargetLabels: {}
|
||||||
|
11
go.mod
11
go.mod
@ -11,6 +11,7 @@ require (
|
|||||||
github.com/glebarez/sqlite v1.11.0
|
github.com/glebarez/sqlite v1.11.0
|
||||||
github.com/go-ldap/ldap/v3 v3.4.8
|
github.com/go-ldap/ldap/v3 v3.4.8
|
||||||
github.com/prometheus-community/pro-bing v0.4.1
|
github.com/prometheus-community/pro-bing v0.4.1
|
||||||
|
github.com/prometheus/client_golang v1.20.4
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.9.0
|
||||||
github.com/swaggo/swag v1.16.3
|
github.com/swaggo/swag v1.16.3
|
||||||
@ -31,6 +32,16 @@ require (
|
|||||||
gorm.io/gorm v1.25.12
|
gorm.io/gorm v1.25.12
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
|
github.com/klauspost/compress v1.17.9 // indirect
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
|
github.com/prometheus/client_model v0.6.1 // indirect
|
||||||
|
github.com/prometheus/common v0.55.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.15.1 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
filippo.io/edwards25519 v1.1.0 // indirect
|
filippo.io/edwards25519 v1.1.0 // indirect
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
||||||
|
16
go.sum
16
go.sum
@ -32,6 +32,8 @@ github.com/a8m/envsubst v1.4.2 h1:4yWIHXOLEJHQEFd4UjrWDrYeYlV7ncFWJOCBRLOZHQg=
|
|||||||
github.com/a8m/envsubst v1.4.2/go.mod h1:MVUTQNGQ3tsjOOtKCNd+fl8RzhsXcDvvAEzkhGtlsbY=
|
github.com/a8m/envsubst v1.4.2/go.mod h1:MVUTQNGQ3tsjOOtKCNd+fl8RzhsXcDvvAEzkhGtlsbY=
|
||||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI=
|
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI=
|
||||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
||||||
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw=
|
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw=
|
||||||
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
|
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
|
||||||
github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20181103040241-659414f458e1/go.mod h1:dkChI7Tbtx7H1Tj7TqGSZMOeGpMP5gLHtjroHd4agiI=
|
github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20181103040241-659414f458e1/go.mod h1:dkChI7Tbtx7H1Tj7TqGSZMOeGpMP5gLHtjroHd4agiI=
|
||||||
@ -40,6 +42,8 @@ github.com/bytedance/sonic v1.12.1/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKz
|
|||||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||||
github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM=
|
github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM=
|
||||||
github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||||
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||||
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||||
@ -173,6 +177,8 @@ github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV
|
|||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b/go.mod h1:g2nVr8KZVXJSS97Jo8pJ0jgq29P6H7dG0oplUA86MQw=
|
github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b/go.mod h1:g2nVr8KZVXJSS97Jo8pJ0jgq29P6H7dG0oplUA86MQw=
|
||||||
|
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||||
|
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
|
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
@ -213,6 +219,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
|||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
|
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
|
||||||
github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||||
@ -224,6 +232,14 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
|||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus-community/pro-bing v0.4.1 h1:aMaJwyifHZO0y+h8+icUz0xbToHbia0wdmzdVZ+Kl3w=
|
github.com/prometheus-community/pro-bing v0.4.1 h1:aMaJwyifHZO0y+h8+icUz0xbToHbia0wdmzdVZ+Kl3w=
|
||||||
github.com/prometheus-community/pro-bing v0.4.1/go.mod h1:aLsw+zqCaDoa2RLVVSX3+UiCkBBXTMtZC3c7EkfWnAE=
|
github.com/prometheus-community/pro-bing v0.4.1/go.mod h1:aLsw+zqCaDoa2RLVVSX3+UiCkBBXTMtZC3c7EkfWnAE=
|
||||||
|
github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI=
|
||||||
|
github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||||
|
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||||
|
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||||
|
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
|
||||||
|
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
|
||||||
|
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||||
|
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||||
github.com/quasoft/memstore v0.0.0-20180925164028-84a050167438/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg=
|
github.com/quasoft/memstore v0.0.0-20180925164028-84a050167438/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg=
|
||||||
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b h1:aUNXCGgukb4gtY99imuIeoh8Vr0GSwAlYxPAhqZrpFc=
|
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b h1:aUNXCGgukb4gtY99imuIeoh8Vr0GSwAlYxPAhqZrpFc=
|
||||||
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg=
|
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg=
|
||||||
|
161
internal/adapters/metrics.go
Normal file
161
internal/adapters/metrics.go
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
package adapters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/h44z/wg-portal/internal"
|
||||||
|
"github.com/h44z/wg-portal/internal/config"
|
||||||
|
"github.com/h44z/wg-portal/internal/domain"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
peerSendBytesTotal *prometheus.GaugeVec
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wireguard metrics labels
|
||||||
|
var (
|
||||||
|
labels = []string{"interface"}
|
||||||
|
ifaceLabels = []string{}
|
||||||
|
peerLabels = []string{"addresses", "id", "name"}
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewMetricsServer returns a new prometheus server
|
||||||
|
func NewMetricsServer(cfg *config.Config, db *SqlRepo) *MetricsServer {
|
||||||
|
reg := prometheus.NewRegistry()
|
||||||
|
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{Registry: reg}))
|
||||||
|
|
||||||
|
return &MetricsServer{
|
||||||
|
Server: &http.Server{
|
||||||
|
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...),
|
||||||
|
),
|
||||||
|
ifaceSendBytesTotal: promauto.With(reg).NewGaugeVec(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Name: "wireguard_interface_sent_bytes_total",
|
||||||
|
Help: "Bytes sent through the interface.",
|
||||||
|
}, append(labels, 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...),
|
||||||
|
),
|
||||||
|
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...),
|
||||||
|
),
|
||||||
|
peerReceivedBytesTotal: promauto.With(reg).NewGaugeVec(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Name: "wireguard_peer_received_bytes_total",
|
||||||
|
Help: "Bytes received from the peer.",
|
||||||
|
}, append(labels, peerLabels...),
|
||||||
|
),
|
||||||
|
peerSendBytesTotal: promauto.With(reg).NewGaugeVec(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Name: "wireguard_peer_sent_bytes_total",
|
||||||
|
Help: "Bytes sent to the peer.",
|
||||||
|
}, append(labels, peerLabels...),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run starts the metrics server
|
||||||
|
func (m *MetricsServer) Run(ctx context.Context) {
|
||||||
|
// Run the metrics server in a goroutine
|
||||||
|
go func() {
|
||||||
|
if err := m.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||||
|
logrus.Errorf("metrics service on %s exited: %v", m.Addr, err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
logrus.Infof("started metrics service on %s", m.Addr)
|
||||||
|
|
||||||
|
// Wait for the context to be done
|
||||||
|
<-ctx.Done()
|
||||||
|
|
||||||
|
// Create a context with timeout for the shutdown process
|
||||||
|
shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// Attempt to gracefully shutdown the metrics server
|
||||||
|
if err := m.Shutdown(shutdownCtx); err != nil {
|
||||||
|
logrus.Errorf("metrics service on %s shutdown failed: %v", m.Addr, err)
|
||||||
|
} else {
|
||||||
|
logrus.Infof("metrics service on %s shutdown gracefully", m.Addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
labels := []string{
|
||||||
|
string(peer.InterfaceIdentifier),
|
||||||
|
string(peer.Interface.AddressStr()),
|
||||||
|
string(status.PeerId),
|
||||||
|
string(peer.DisplayName),
|
||||||
|
}
|
||||||
|
|
||||||
|
m.peerInfo.WithLabelValues(labels...).Set(1)
|
||||||
|
if status.LastHandshake != nil {
|
||||||
|
m.peerLastHandshakeSeconds.WithLabelValues(labels...).Set(float64(status.LastHandshake.Unix()))
|
||||||
|
}
|
||||||
|
m.peerReceivedBytesTotal.WithLabelValues(labels...).Set(float64(status.BytesReceived))
|
||||||
|
m.peerSendBytesTotal.WithLabelValues(labels...).Set(float64(status.BytesTransmitted))
|
||||||
|
m.peerIsConnected.WithLabelValues(labels...).Set(internal.BoolToFloat64(status.IsConnected()))
|
||||||
|
}
|
@ -95,8 +95,6 @@ func NewServer(cfg *config.Config, endpoints ...ApiEndpointSetupFunc) (*Server,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Run(ctx context.Context, listenAddress string) {
|
func (s *Server) Run(ctx context.Context, listenAddress string) {
|
||||||
logrus.Infof("starting web service on %s", listenAddress)
|
|
||||||
|
|
||||||
// Run web service
|
// Run web service
|
||||||
srv := &http.Server{
|
srv := &http.Server{
|
||||||
Addr: listenAddress,
|
Addr: listenAddress,
|
||||||
@ -116,6 +114,7 @@ func (s *Server) Run(ctx context.Context, listenAddress string) {
|
|||||||
cancelFn()
|
cancelFn()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
logrus.Infof("started web service on %s", listenAddress)
|
||||||
|
|
||||||
// Wait for the main context to end
|
// Wait for the main context to end
|
||||||
<-srvContext.Done()
|
<-srvContext.Done()
|
||||||
|
@ -2,6 +2,7 @@ package wireguard
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/h44z/wg-portal/internal/domain"
|
"github.com/h44z/wg-portal/internal/domain"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -27,6 +28,7 @@ type InterfaceAndPeerDatabaseRepo interface {
|
|||||||
type StatisticsDatabaseRepo interface {
|
type StatisticsDatabaseRepo interface {
|
||||||
GetAllInterfaces(ctx context.Context) ([]domain.Interface, error)
|
GetAllInterfaces(ctx context.Context) ([]domain.Interface, error)
|
||||||
GetInterfacePeers(ctx context.Context, id domain.InterfaceIdentifier) ([]domain.Peer, error)
|
GetInterfacePeers(ctx context.Context, id domain.InterfaceIdentifier) ([]domain.Peer, error)
|
||||||
|
GetPeer(ctx context.Context, id domain.PeerIdentifier) (*domain.Peer, error)
|
||||||
|
|
||||||
UpdatePeerStatus(ctx context.Context, id domain.PeerIdentifier, updateFunc func(in *domain.PeerStatus) (*domain.PeerStatus, error)) error
|
UpdatePeerStatus(ctx context.Context, id domain.PeerIdentifier, updateFunc func(in *domain.PeerStatus) (*domain.PeerStatus, error)) error
|
||||||
UpdateInterfaceStatus(ctx context.Context, id domain.InterfaceIdentifier, updateFunc func(in *domain.InterfaceStatus) (*domain.InterfaceStatus, error)) error
|
UpdateInterfaceStatus(ctx context.Context, id domain.InterfaceIdentifier, updateFunc func(in *domain.InterfaceStatus) (*domain.InterfaceStatus, error)) error
|
||||||
@ -48,3 +50,8 @@ type WgQuickController interface {
|
|||||||
SetDNS(id domain.InterfaceIdentifier, dnsStr, dnsSearchStr string) error
|
SetDNS(id domain.InterfaceIdentifier, dnsStr, dnsSearchStr string) error
|
||||||
UnsetDNS(id domain.InterfaceIdentifier) error
|
UnsetDNS(id domain.InterfaceIdentifier) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MetricsServer interface {
|
||||||
|
UpdateInterfaceMetrics(status domain.InterfaceStatus)
|
||||||
|
UpdatePeerMetrics(ctx context.Context, status domain.PeerStatus)
|
||||||
|
}
|
||||||
|
@ -2,12 +2,13 @@ package wireguard
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/h44z/wg-portal/internal/config"
|
|
||||||
"github.com/h44z/wg-portal/internal/domain"
|
|
||||||
"github.com/prometheus-community/pro-bing"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/h44z/wg-portal/internal/config"
|
||||||
|
"github.com/h44z/wg-portal/internal/domain"
|
||||||
|
probing "github.com/prometheus-community/pro-bing"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
type StatisticsCollector struct {
|
type StatisticsCollector struct {
|
||||||
@ -18,14 +19,16 @@ type StatisticsCollector struct {
|
|||||||
|
|
||||||
db StatisticsDatabaseRepo
|
db StatisticsDatabaseRepo
|
||||||
wg InterfaceController
|
wg InterfaceController
|
||||||
|
ms MetricsServer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStatisticsCollector(cfg *config.Config, db StatisticsDatabaseRepo, wg InterfaceController) (*StatisticsCollector, error) {
|
func NewStatisticsCollector(cfg *config.Config, db StatisticsDatabaseRepo, wg InterfaceController, ms MetricsServer) (*StatisticsCollector, error) {
|
||||||
return &StatisticsCollector{
|
return &StatisticsCollector{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
|
|
||||||
db: db,
|
db: db,
|
||||||
wg: wg,
|
wg: wg,
|
||||||
|
ms: ms,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,11 +73,15 @@ func (c *StatisticsCollector) collectInterfaceData(ctx context.Context) {
|
|||||||
i.UpdatedAt = time.Now()
|
i.UpdatedAt = time.Now()
|
||||||
i.BytesReceived = physicalInterface.BytesDownload
|
i.BytesReceived = physicalInterface.BytesDownload
|
||||||
i.BytesTransmitted = physicalInterface.BytesUpload
|
i.BytesTransmitted = physicalInterface.BytesUpload
|
||||||
|
|
||||||
|
// Update prometheus metrics
|
||||||
|
go c.ms.UpdateInterfaceMetrics(*i)
|
||||||
return i, nil
|
return i, nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Warnf("failed to update interface status for %s: %v", in.Identifier, err)
|
logrus.Warnf("failed to update interface status for %s: %v", in.Identifier, err)
|
||||||
}
|
}
|
||||||
|
logrus.Tracef("updated interface status for %s", in.Identifier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,11 +133,15 @@ func (c *StatisticsCollector) collectPeerData(ctx context.Context) {
|
|||||||
p.Endpoint = peer.Endpoint
|
p.Endpoint = peer.Endpoint
|
||||||
p.LastHandshake = lastHandshake
|
p.LastHandshake = lastHandshake
|
||||||
|
|
||||||
|
// Update prometheus metrics
|
||||||
|
go c.ms.UpdatePeerMetrics(ctx, *p)
|
||||||
|
|
||||||
return p, nil
|
return p, nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Warnf("failed to update interface status for %s: %v", in.Identifier, err)
|
logrus.Warnf("failed to update interface status for %s: %v", in.Identifier, err)
|
||||||
}
|
}
|
||||||
|
logrus.Tracef("updated peer status for %s", peer.Identifier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -234,7 +245,7 @@ func (c *StatisticsCollector) pingWorker(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *StatisticsCollector) isPeerPingable(ctx context.Context, peer domain.Peer) bool {
|
func (c *StatisticsCollector) isPeerPingable(ctx context.Context, peer domain.Peer) bool {
|
||||||
if c.cfg.Statistics.UsePingChecks == false {
|
if !c.cfg.Statistics.UsePingChecks {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@ type Config struct {
|
|||||||
CollectInterfaceData bool `yaml:"collect_interface_data"`
|
CollectInterfaceData bool `yaml:"collect_interface_data"`
|
||||||
CollectPeerData bool `yaml:"collect_peer_data"`
|
CollectPeerData bool `yaml:"collect_peer_data"`
|
||||||
CollectAuditData bool `yaml:"collect_audit_data"`
|
CollectAuditData bool `yaml:"collect_audit_data"`
|
||||||
|
ListeningAddress string `yaml:"listening_address"`
|
||||||
} `yaml:"statistics"`
|
} `yaml:"statistics"`
|
||||||
|
|
||||||
Mail MailConfig `yaml:"mail"`
|
Mail MailConfig `yaml:"mail"`
|
||||||
@ -117,10 +118,11 @@ func defaultConfig() *Config {
|
|||||||
cfg.Statistics.PingCheckWorkers = 10
|
cfg.Statistics.PingCheckWorkers = 10
|
||||||
cfg.Statistics.PingUnprivileged = false
|
cfg.Statistics.PingUnprivileged = false
|
||||||
cfg.Statistics.PingCheckInterval = 1 * time.Minute
|
cfg.Statistics.PingCheckInterval = 1 * time.Minute
|
||||||
cfg.Statistics.DataCollectionInterval = 10 * time.Second
|
cfg.Statistics.DataCollectionInterval = 1 * time.Minute
|
||||||
cfg.Statistics.CollectInterfaceData = true
|
cfg.Statistics.CollectInterfaceData = true
|
||||||
cfg.Statistics.CollectPeerData = true
|
cfg.Statistics.CollectPeerData = true
|
||||||
cfg.Statistics.CollectAuditData = true
|
cfg.Statistics.CollectAuditData = true
|
||||||
|
cfg.Statistics.ListeningAddress = ":8787"
|
||||||
|
|
||||||
cfg.Mail = MailConfig{
|
cfg.Mail = MailConfig{
|
||||||
Host: "127.0.0.1",
|
Host: "127.0.0.1",
|
||||||
|
@ -126,3 +126,10 @@ func TruncateString(s string, max int) string {
|
|||||||
}
|
}
|
||||||
return s[:max]
|
return s[:max]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BoolToFloat64(b bool) float64 {
|
||||||
|
if b {
|
||||||
|
return 1.0
|
||||||
|
}
|
||||||
|
return 0.0
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user