Skip to content

Commit 685e2e8

Browse files
authored
Merge pull request #144 from Luzilla/adhoc-prober
Update: implement an adhoc scraper
2 parents e352312 + 673c600 commit 685e2e8

File tree

19 files changed

+422
-196
lines changed

19 files changed

+422
-196
lines changed

.github/workflows/goreleaser.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ jobs:
1313
- uses: actions/checkout@v3
1414
with:
1515
fetch-depth: 0
16-
- uses: actions/setup-go@v3
16+
- uses: actions/setup-go@v4
1717
with:
1818
go-version-file: go.mod
19+
cache: false
1920
- uses: docker/setup-qemu-action@v2
2021
- uses: docker/setup-buildx-action@v2
2122
- uses: docker/login-action@v1

.github/workflows/integration.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ jobs:
1313
with:
1414
fetch-depth: 0
1515
- name: Set up Go
16-
uses: actions/setup-go@v3
16+
uses: actions/setup-go@v4
1717
with:
1818
go-version-file: go.mod
19+
cache: false
1920
- name: Run GoReleaser
2021
uses: goreleaser/goreleaser-action@v2
2122
with:

.github/workflows/pr.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,25 @@ jobs:
77
test:
88
strategy:
99
matrix:
10-
go-version: [1.19.x, 1.20.x]
10+
go-version: [1.20.x]
1111
runs-on: ubuntu-latest
1212
steps:
1313
- uses: actions/checkout@v3
14-
- uses: actions/setup-go@v3
14+
- uses: actions/setup-go@v4
1515
with:
1616
go-version: ${{ matrix.go-version }}
17+
cache: false
1718
- run: go test ./...
1819

1920
release_test:
2021
needs: test
2122
runs-on: ubuntu-latest
2223
steps:
2324
- uses: actions/checkout@v3
24-
- uses: actions/setup-go@v3
25+
- uses: actions/setup-go@v4
2526
with:
2627
go-version-file: go.mod
28+
cache: false
2729
- uses: docker/setup-qemu-action@v2
2830
- uses: docker/setup-buildx-action@v2
2931
- run: docker buildx ls

Makefile

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,15 @@
1-
GO_VERSION:=1.16
2-
31
.PHONY: build
42
build:
5-
goreleaser build --snapshot --single-target --rm-dist
3+
goreleaser build --snapshot --single-target --clean
4+
5+
.PHONY: run-dev
6+
run-dev:
7+
go run dnsbl_exporter.go --log.debug
68

79
.PHONY: snapshot
810
snapshot:
9-
goreleaser build --snapshot --rm-dist
11+
goreleaser build --snapshot --clean
1012

1113
.PHONY: test
1214
test:
13-
docker run \
14-
-it \
15-
--rm \
16-
-v $(CURDIR):/src/github.com/Luzilla/dnsbl_exporter \
17-
-w /src/github.com/Luzilla/dnsbl_exporter \
18-
golang:$(GO_VERSION) \
19-
sh -c "go mod download && go test ./..."
15+
act "pull_request" -j test

app/app.go

Lines changed: 127 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,153 +1,195 @@
11
package app
22

33
import (
4+
"errors"
5+
"fmt"
6+
"io"
47
"net/http"
58
"os"
9+
"strings"
610

7-
"github.com/Luzilla/dnsbl_exporter/collector"
811
"github.com/Luzilla/dnsbl_exporter/config"
12+
"github.com/Luzilla/dnsbl_exporter/internal/index"
13+
"github.com/Luzilla/dnsbl_exporter/internal/metrics"
14+
"github.com/Luzilla/dnsbl_exporter/internal/prober"
15+
"github.com/Luzilla/dnsbl_exporter/internal/setup"
916
"github.com/prometheus/client_golang/prometheus"
10-
"github.com/prometheus/client_golang/prometheus/promhttp"
11-
"github.com/urfave/cli"
12-
13-
log "github.com/sirupsen/logrus"
17+
"github.com/urfave/cli/v2"
18+
"golang.org/x/exp/slog"
1419
)
1520

1621
type DNSBLApp struct {
1722
App *cli.App
1823
}
1924

25+
var (
26+
appName, appVersion, appPath string
27+
resolver string
28+
)
29+
2030
// NewApp ...
2131
func NewApp(name string, version string) DNSBLApp {
22-
23-
cli.VersionFlag = cli.BoolFlag{
24-
Name: "version, V",
25-
Usage: "Print the version information.",
26-
}
27-
28-
app := cli.NewApp()
29-
app.Name = name
30-
app.Version = version
31-
app.Flags = []cli.Flag{
32-
cli.StringFlag{
33-
Name: "config.dns-resolver",
34-
Value: "127.0.0.1:53",
35-
Usage: "IP address[:port] of the resolver to use.",
36-
EnvVar: "DNSBL_EXP_RESOLVER",
32+
appName = name
33+
appVersion = version
34+
35+
a := cli.NewApp()
36+
a.Name = appName
37+
a.Version = appVersion
38+
a.Flags = []cli.Flag{
39+
&cli.StringFlag{
40+
Name: "config.dns-resolver",
41+
Value: "127.0.0.1:53",
42+
Usage: "IP address[:port] of the resolver to use.",
43+
EnvVars: []string{"DNSBL_EXP_RESOLVER"},
44+
Destination: &resolver,
3745
},
38-
cli.StringFlag{
39-
Name: "config.rbls",
40-
Value: "./rbls.ini",
41-
Usage: "Configuration file which contains RBLs",
42-
EnvVar: "DNSBL_EXP_RBLS",
46+
&cli.StringFlag{
47+
Name: "config.rbls",
48+
Value: "./rbls.ini",
49+
Usage: "Configuration file which contains RBLs",
50+
EnvVars: []string{"DNSBL_EXP_RBLS"},
4351
},
44-
cli.StringFlag{
45-
Name: "config.targets",
46-
Value: "./targets.ini",
47-
Usage: "Configuration file which contains the targets to check.",
48-
EnvVar: "DNSBL_EXP_TARGETS",
52+
&cli.StringFlag{
53+
Name: "config.targets",
54+
Value: "./targets.ini",
55+
Usage: "Configuration file which contains the targets to check.",
56+
EnvVars: []string{"DNSBL_EXP_TARGETS"},
4957
},
50-
cli.StringFlag{
51-
Name: "web.listen-address",
52-
Value: ":9211",
53-
Usage: "Address to listen on for web interface and telemetry.",
54-
EnvVar: "DNSBL_EXP_LISTEN",
58+
&cli.StringFlag{
59+
Name: "web.listen-address",
60+
Value: ":9211",
61+
Usage: "Address to listen on for web interface and telemetry.",
62+
EnvVars: []string{"DNSBL_EXP_LISTEN"},
5563
},
56-
cli.StringFlag{
57-
Name: "web.telemetry-path",
58-
Value: "/metrics",
59-
Usage: "Path under which to expose metrics.",
64+
&cli.StringFlag{
65+
Name: "web.telemetry-path",
66+
Value: "/metrics",
67+
Usage: "Path under which to expose metrics.",
68+
Destination: &appPath,
69+
Action: func(cCtx *cli.Context, v string) error {
70+
if !strings.HasPrefix(v, "/") {
71+
return cli.Exit("Missing / to prefix the path: --web.telemetry-path", 2)
72+
}
73+
return nil
74+
},
6075
},
61-
cli.BoolFlag{
76+
&cli.BoolFlag{
6277
Name: "web.include-exporter-metrics",
6378
Usage: "Include metrics about the exporter itself (promhttp_*, process_*, go_*).",
79+
Value: false,
6480
},
65-
cli.BoolFlag{
81+
&cli.BoolFlag{
6682
Name: "log.debug",
6783
Usage: "Enable more output in the logs, otherwise INFO.",
84+
Value: false,
6885
},
69-
cli.StringFlag{
86+
&cli.StringFlag{
7087
Name: "log.output",
7188
Value: "stdout",
7289
Usage: "Destination of our logs: stdout, stderr",
90+
Action: func(cCtx *cli.Context, v string) error {
91+
if v != "stdout" && v != "stderr" {
92+
return cli.Exit("We currently support only stdout and stderr: --log.output", 2)
93+
}
94+
return nil
95+
},
7396
},
7497
}
7598

7699
return DNSBLApp{
77-
App: app,
100+
App: a,
78101
}
79102
}
80103

81-
func (app *DNSBLApp) Bootstrap() {
82-
app.App.Action = func(ctx *cli.Context) error {
104+
func (a *DNSBLApp) Bootstrap() {
105+
a.App.Action = func(ctx *cli.Context) error {
83106
// setup logging
107+
fmt.Println("VERSION: " + appVersion)
108+
handler := &slog.HandlerOptions{}
109+
var writer io.Writer
110+
111+
if ctx.Bool("log.debug") {
112+
handler.Level = slog.LevelDebug
113+
}
114+
84115
switch ctx.String("log.output") {
85116
case "stdout":
86-
log.SetOutput(os.Stdout)
117+
writer = os.Stdout
87118
case "stderr":
88-
log.SetOutput(os.Stderr)
89-
default:
90-
cli.ShowAppHelp(ctx)
91-
return cli.NewExitError("We currently support only stdout and stderr: --log.output", 2)
119+
writer = os.Stderr
92120
}
93-
if ctx.Bool("log.debug") {
94-
log.SetLevel(log.DebugLevel)
121+
122+
log := slog.New(handler.NewTextHandler(writer))
123+
124+
c := config.Config{
125+
Logger: log.With("area", "config"),
95126
}
96127

97-
cfgRbls, err := config.LoadFile(ctx.String("config.rbls"), "rbl")
128+
cfgRbls, err := c.LoadFile(ctx.String("config.rbls"))
98129
if err != nil {
99130
return err
100131
}
101132

102-
cfgTargets, err := config.LoadFile(ctx.String("config.targets"), "targets")
133+
err = c.ValidateConfig(cfgRbls, "rbl")
134+
if err != nil {
135+
return fmt.Errorf("unable to load the rbls from the config: %w", err)
136+
}
137+
138+
cfgTargets, err := c.LoadFile(ctx.String("config.targets"))
103139
if err != nil {
104140
return err
105141
}
106142

107-
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
108-
w.Write([]byte(`<html>
109-
<head><title>` + app.App.Name + `</title></head>
110-
<body>
111-
<h1>` + app.App.Name + ` @ ` + app.App.Version + `</h1>
112-
<p><a href="` + ctx.String("web.telemetry-path") + `">Metrics</a></p>
113-
<p><a href="https://github.com/Luzilla/dnsbl_exporter">Code on Github</a></p>
114-
</body>
115-
</html>`))
116-
})
143+
err = c.ValidateConfig(cfgTargets, "targets")
144+
if err != nil {
145+
if !errors.Is(err, config.ErrNoServerEntries) && !errors.Is(err, config.ErrNoSuchSection) {
146+
return err
147+
}
148+
log.Info("starting exporter without targets — check the /prober endpoint or correct the .ini file")
149+
}
150+
151+
iHandler := index.IndexHandler{
152+
Name: appName,
153+
Version: appVersion,
154+
Path: appPath,
155+
}
156+
157+
http.HandleFunc("/", iHandler.Handler)
117158

118-
rbls := config.GetRbls(cfgRbls)
119-
targets := config.GetTargets(cfgTargets)
159+
rbls := c.GetRbls(cfgRbls)
160+
targets := c.GetTargets(cfgTargets)
120161

121-
registry := createRegistry()
162+
registry := setup.CreateRegistry()
122163

123-
collector := createCollector(rbls, targets, ctx.String("config.dns-resolver"))
124-
registry.MustRegister(collector)
164+
rblCollector := setup.CreateCollector(rbls, targets, resolver, log.With("area", "metrics"))
165+
registry.MustRegister(rblCollector)
125166

126-
registryExporter := createRegistry()
167+
registryExporter := setup.CreateRegistry()
127168

128169
if ctx.Bool("web.include-exporter-metrics") {
129-
log.Infoln("Exposing exporter metrics")
170+
log.Info("Exposing exporter metrics")
130171

131172
registryExporter.MustRegister(
132173
prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}),
133174
prometheus.NewGoCollector(),
134175
)
135176
}
136177

137-
handler := promhttp.HandlerFor(
138-
prometheus.Gatherers{
139-
registry,
140-
registryExporter,
141-
},
142-
promhttp.HandlerOpts{
143-
ErrorHandling: promhttp.ContinueOnError,
144-
Registry: registry,
145-
},
146-
)
178+
mHandler := metrics.MetricsHandler{
179+
Registry: registry,
180+
RegistryExporter: registryExporter,
181+
}
147182

148-
http.Handle(ctx.String("web.telemetry-path"), handler)
183+
http.Handle(ctx.String("web.telemetry-path"), mHandler.Handler())
184+
185+
pHandler := prober.ProberHandler{
186+
Resolver: resolver,
187+
Rbls: rbls,
188+
Logger: log.With("area", "prober"),
189+
}
190+
http.Handle("/prober", pHandler)
149191

150-
log.Infoln("Starting on: ", ctx.String("web.listen-address"))
192+
log.Info("Starting on: " + ctx.String("web.listen-address"))
151193
err = http.ListenAndServe(ctx.String("web.listen-address"), nil)
152194
if err != nil {
153195
return err
@@ -157,14 +199,6 @@ func (app *DNSBLApp) Bootstrap() {
157199
}
158200
}
159201

160-
func (app *DNSBLApp) Run(args []string) error {
161-
return app.App.Run(args)
162-
}
163-
164-
func createCollector(rbls []string, targets []string, resolver string) *collector.RblCollector {
165-
return collector.NewRblCollector(rbls, targets, resolver)
166-
}
167-
168-
func createRegistry() *prometheus.Registry {
169-
return prometheus.NewRegistry()
202+
func (a *DNSBLApp) Run(args []string) error {
203+
return a.App.Run(args)
170204
}

0 commit comments

Comments
 (0)