Skip to content

Commit

Permalink
Allow to configure log level, don't try to parse output of nft exit…
Browse files Browse the repository at this point in the history
…ed with non-zero status (#29)
  • Loading branch information
auvred authored Feb 5, 2025
1 parent 0f88df0 commit 3ba0acb
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 18 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,14 @@ nftables_exporter:
url_path: "/metrics"
nft_location: /sbin/nft
fake_nft_json: /path/to/nft.json
log_level: warn
```
`fake_nft_json` used for debugging. I create this file with the command `nft -j list ruleset > /path/to/nft.json`. For normal exporter usage, this option is not needed.

`log_level` can be one of the following: `debug`, `info`, `warn`, `error`.
Default: `warn`.

## Example metrics

```config
Expand Down
16 changes: 10 additions & 6 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package main

import (
"log"
"errors"
"log/slog"
"net/http"
"os"
Expand Down Expand Up @@ -32,7 +32,7 @@ func (i nftablesManagerCollector) Describe(ch chan<- *prometheus.Desc) {
func (i nftablesManagerCollector) Collect(ch chan<- prometheus.Metric) {
json, err := readData(i.opts)
if err != nil {
log.Printf("failed parsing nftables data: %s", err)
slog.Error("failed to parse nftables data", "error", err)
ch <- prometheus.MustNewConstMetric(upDesc, prometheus.GaugeValue, 0)
} else {
ch <- prometheus.MustNewConstMetric(upDesc, prometheus.GaugeValue, 1)
Expand All @@ -42,8 +42,6 @@ func (i nftablesManagerCollector) Collect(ch chan<- prometheus.Metric) {
}

func main() {
// set json logger as default for all log statements
slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stdout, nil)))
opts := loadOptions()
reg := prometheus.NewPedanticRegistry()
reg.MustRegister(
Expand All @@ -53,11 +51,17 @@ func main() {

prometheus.WrapRegistererWithPrefix("", reg).MustRegister(nftablesManagerCollector{opts: opts})

log.Printf("starting on %s%s", opts.Nft.BindTo, opts.Nft.URLPath)
slog.Info("starting http server", "bind_to", opts.Nft.BindTo, "url_path", opts.Nft.URLPath)
http.Handle(opts.Nft.URLPath, promhttp.HandlerFor(reg, promhttp.HandlerOpts{}))
server := http.Server{
Addr: opts.Nft.BindTo,
ReadHeaderTimeout: 1 * time.Minute,
}
log.Fatal(server.ListenAndServe())

err := server.ListenAndServe()
// ListenAndServe always returns non-nil error
if !errors.Is(err, http.ErrServerClosed) {
slog.Error("http server exited", "error", err)
os.Exit(1)
}
}
4 changes: 2 additions & 2 deletions nftables.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package main

import (
"fmt"
"log"
"log/slog"
"strings"

"github.com/prometheus/client_golang/prometheus"
Expand All @@ -17,7 +17,7 @@ type nftables struct {

// newNFTables is NFTables constructor
func newNFTables(json gjson.Result, ch chan<- prometheus.Metric) nftables {
log.Print("collecting metrics")
slog.Debug("collecting metrics")
return nftables{
ch: ch,
json: json,
Expand Down
25 changes: 21 additions & 4 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"flag"
"log"
"log/slog"
"os"

"github.com/metal-stack/v"
Expand All @@ -20,6 +21,7 @@ type nftOptions struct {
URLPath string `yaml:"url_path"`
FakeNftJSON string `yaml:"fake_nft_json"`
NFTLocation string `yaml:"nft_location"`
LogLevel string `yaml:"log_level"`
}

// Parse options from yaml config file
Expand All @@ -33,10 +35,15 @@ func loadOptions() options {
os.Exit(0)
}

log.Printf("read options from %s\n", *configFile)
logLevel := new(slog.LevelVar)
slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: logLevel,
})))
slog.Info("reading options from config file", "path", *configFile)
yamlFile, err := os.ReadFile(*configFile)
if err != nil {
log.Fatalf("failed read %s: %s", *configFile, err)
slog.Error("failed to read config file", "path", *configFile, "error", err)
os.Exit(1)
}

opts := options{
Expand All @@ -45,12 +52,22 @@ func loadOptions() options {
URLPath: "/metrics",
FakeNftJSON: "",
NFTLocation: "/sbin/nft",
LogLevel: "warn",
},
}

if yaml.Unmarshal(yamlFile, &opts) != nil {
log.Fatalf("failed parse %s: %s", *configFile, err)
slog.Error("failed to parse config file", "path", *configFile, "error", err)
os.Exit(1)
}
log.Printf("parsed options: %#v", opts)

err = logLevel.UnmarshalText([]byte(opts.Nft.LogLevel))
if err != nil {
slog.Error("cannot parse log level", "error", err)
os.Exit(1)
}

slog.Info("parsed options", "opts", opts)

return opts
}
13 changes: 7 additions & 6 deletions readjson.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ package main

import (
"errors"
"log"
"fmt"
"log/slog"
"os"
"os/exec"

Expand All @@ -12,28 +13,28 @@ import (
// Parse json to gjson object
func parseJSON(data string) (gjson.Result, error) {
if !gjson.Valid(data) {
return gjson.Parse("{}"), errors.New("invalid JSON")
return gjson.Result{}, errors.New("invalid JSON")
}
return gjson.Get(data, "nftables"), nil
}

// Reading fake nftables json
func readFakeNFTables(opts options) (gjson.Result, error) {
log.Printf("read fake nftables data from json: %s", opts.Nft.FakeNftJSON)
slog.Debug("read fake nftables data from json", "path", opts.Nft.FakeNftJSON)
jsonFile, err := os.ReadFile(opts.Nft.FakeNftJSON)
if err != nil {
log.Printf("fake nftables data reading error: %s", err)
return gjson.Result{}, fmt.Errorf("fake nftables data reading error: %w", err)
}
return parseJSON(string(jsonFile))
}

// Get json from nftables and parse it
func readNFTables(opts options) (gjson.Result, error) {
log.Print("collecting nftables counters...")
slog.Debug("collecting nftables counters...")
nft := opts.Nft.NFTLocation
out, err := exec.Command(nft, "-j", "list", "ruleset").Output()
if err != nil {
log.Printf("nftables reading error: %s", err)
return gjson.Result{}, fmt.Errorf("nftables reading error: %w", err)
}
return parseJSON(string(out))
}
Expand Down

0 comments on commit 3ba0acb

Please sign in to comment.