Skip to content

Commit

Permalink
Init DEV commit (#1)
Browse files Browse the repository at this point in the history
Init dev commit

Add README.md

Add README.md

Co-authored-by: Роман <rorudzhov@mac.local>
  • Loading branch information
rorudzhov and Роман authored Jul 7, 2024
1 parent aebe30d commit 56c4eac
Show file tree
Hide file tree
Showing 9 changed files with 419 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@
# Go workspace file
go.work
go.work.sum


build.sh
106 changes: 106 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Prometheus WireGuard Exporter

A Prometheus exporter for [WireGuard](https://www.wireguard.com), written in GoLang. This tool execute command `sudo /usr/bin/wg show all dump` and parse results in a format [OpenMetrics](https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md) that [Prometheus](https://prometheus.io/) can understand.

### Metrics

All metrics are aveliable on `/metrics` path. As example you can use `curl 127.0.0.1:9172/metrics`

```ebnf
# HELP wireguard_keep_alive Number of keep alive seconds
# TYPE wireguard_keep_alive gauge
wireguard_keep_alive{ifname="wg0",publicKey="5CL0j1HMDxK0ftLz2ANXaZ5w2y5aOe9dV3tKF4llhlI="} 5
# HELP wireguard_last_handshake Timestamp of last handshake
# TYPE wireguard_last_handshake counter
wireguard_last_handshake{ifname="wg0",publicKey="5CL0j1HMDxK0ftLz2ANXaZ5w2y5aOe9dV3tKF4llhlI="} 2.9867196e+07
# HELP wireguard_peers_count Number of active peers
# TYPE wireguard_peers_count gauge
wireguard_peers_count{ifname="wg0"} 1
# HELP wireguard_rx_bytes Number of received bytes
# TYPE wireguard_rx_bytes counter
wireguard_rx_bytes{ifname="wg0",publicKey="5CL0j1HMDxK0ftLz2ANXaZ5w2y5aOe9dV3tKF4llhlI="} 2.9867196e+07
# HELP wireguard_tx_bytes Number of transferred bytes
# TYPE wireguard_tx_bytes counter
wireguard_tx_bytes{ifname="wg0",publicKey="5CL0j1HMDxK0ftLz2ANXaZ5w2y5aOe9dV3tKF4llhlI="} 2.746656e+06
```

For example this is how you edit your WireGuard configuration file:

```ini
[Interface]
Address = 192.168.0.8/24
PrivateKey = ******uWogB6cn/Mw********j3dZeB54C1SIn4iG2k=

[Peer]
PublicKey = 5CL0j1HMDxK0ftLz2ANXaZ5w2y5aOe9dV3tKF4llhlI=
AllowedIPs = 192.168.0.0/24,192.168.1.0/24
PersistentKeepalive = 5
Endpoint = wg0.example.com:443
```

## Flags
❗SUDO RULES❗️
If the `wireguard-exporter` is not launched as `root`, then the user must have sudo rights
```shell
someuser ALL=(root) NOPASSWD: /usr/bin/wg
```
You can simply run the `wireguard-exporter` file with standard settings on any host that has utility `wg`

You can call `wireguard-exporter -h` to print all available flags

```shell
root@myhost:~# ./wireguard-exporter -h
Usage of ./wireguard-exporter-linux-amd64:
--log.format string
Output format of log messages. One of: [text, json] (default "text")
--log.level string
Only log messages with the given severity or above. One of: [debug, info, warn, error] (default "info")
--web.listem.address string
Address to listen (default "0.0.0.0:9172")
```

### Build for another platform
If your platform is not in the releases, you can build it yourself, for this you only need a Go compiler. Just execute this shell script by changing `GOOS` and `GOARCH` with according [GoLang specification](https://gist.github.com/asukakenji/f15ba7e588ac42795f421b48b8aede63)
```shell
GOOS=linux # REQUIRED REPLACE
GOARCH=amd64 # REQUIRED REPLACE

export GOARCH=$GOARCH
export GOOS=$GOOS
file="wireguard-exporter-$GOOS-$GOARCH"
go build -ldflags "-s -w" -o $file main.go
```
If everything went well, just transfer the file `wireguard-exporter-...-...` to your host and execute him


### Simple systemd service file

❗SUDO RULES❗️
If the `wireguard-exporter` is not launched as `root`, then the user must have sudo rights
```shell
someuser ALL=(root) NOPASSWD: /usr/bin/wg
```

Now add the exporter to the Prometheus exporters as usual. I recommend to start it as a service. It's necessary to run it as root or configure a sudo rule (if there is a non-root way to call `wg show all dump` please let me know). My systemd service file is like this one:

```ini
[Unit]
Description=Prometheus WireGuard Exporter
Wants=network-online.target
After=network-online.target

[Service]
User=someuser
Group=someuser
Type=simple
ExecStart=/usr/local/bin/wireguard-exporter \
--log.format text \
--log.level info \
--web.listem.address 0.0.0.0:9172
Restart=on-failure
RestartSec=15s

[Install]
WantedBy=multi-user.target
```

15 changes: 15 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module main

go 1.22.2

require github.com/prometheus/client_golang v1.19.1

require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.48.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
golang.org/x/sys v0.17.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
)
20 changes: 20 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
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/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
37 changes: 37 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package main

import (
"flag"
"main/src"
"net/http"
"os"
)

var (
webListenAddress = flag.String("web.listem.address", "0.0.0.0:9172", "Address to listen")
logLevel = flag.String("log.level", "info", "Only log messages with the given severity or above. One of: [debug, info, warn, error]")
logFormat = flag.String("log.format", "text", "Output format of log messages. One of: [text, json]")
)

func main() {
// Parse flags
flag.Parse()

// Init logger
src.Init(logLevel, logFormat)
logger := src.GetLogger()

logger.Info("Exporter is started")

// Start HTTP server
server := http.NewServeMux()
server.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
src.Router(writer, request, logger)
})
logger.Info("Starting HTTP server on " + *webListenAddress + "")
err := http.ListenAndServe(*webListenAddress, server)
if err != nil {
logger.Error(err.Error())
os.Exit(1)
}
}
38 changes: 38 additions & 0 deletions src/logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package src

import (
"log/slog"
"os"
)

var (
mylogger *slog.Logger
)

func Init(level *string, format *string) {
var l_level slog.Level
switch *level {
case "debug":
l_level = slog.LevelDebug
case "warn":
l_level = slog.LevelWarn
case "error":
l_level = slog.LevelError
default:
l_level = slog.LevelInfo
}

// Select format
var handler slog.Handler
switch *format {
case "json":
handler = slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: l_level})
default:
handler = slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: l_level})
}
mylogger = slog.New(handler)
}

func GetLogger() *slog.Logger {
return mylogger
}
18 changes: 18 additions & 0 deletions src/router.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package src

import (
"log/slog"
"main/src/routes"
"net/http"
)

// Router routes handler
func Router(writer http.ResponseWriter, request *http.Request, logger *slog.Logger) {
switch request.RequestURI {
case "/metrics":
routes.Metrics(writer, request, logger)
default:
routes.NotFound(writer, request, logger)
}

}
Loading

0 comments on commit 56c4eac

Please sign in to comment.