generated from sendnrw/template_golang
init
Some checks failed
build-binaries / build (, amd64, linux) (push) Has been skipped
build-binaries / build (, arm, 7, linux) (push) Has been skipped
build-binaries / build (, arm64, linux) (push) Has been skipped
build-binaries / build (.exe, amd64, windows) (push) Has been skipped
build-binaries / release (push) Has been skipped
build-binaries / publish-agent (push) Has been skipped
release-tag / release-image (push) Has been cancelled
Some checks failed
build-binaries / build (, amd64, linux) (push) Has been skipped
build-binaries / build (, arm, 7, linux) (push) Has been skipped
build-binaries / build (, arm64, linux) (push) Has been skipped
build-binaries / build (.exe, amd64, windows) (push) Has been skipped
build-binaries / release (push) Has been skipped
build-binaries / publish-agent (push) Has been skipped
release-tag / release-image (push) Has been cancelled
This commit is contained in:
8
Dockerfile
Normal file
8
Dockerfile
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
FROM golang:1.25
|
||||||
|
WORKDIR /app
|
||||||
|
COPY go.* ./
|
||||||
|
RUN go mod download
|
||||||
|
COPY *.go ./
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux go build -o /goprg
|
||||||
|
EXPOSE 8080
|
||||||
|
CMD ["/goprg"]
|
||||||
15
compose.yml
Normal file
15
compose.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
ping-exporter:
|
||||||
|
image: ping-exporter:latest
|
||||||
|
container_name: ping-exporter
|
||||||
|
volumes:
|
||||||
|
- ./config.yaml:/config.yaml:ro
|
||||||
|
ports:
|
||||||
|
- "9101:9101"
|
||||||
|
# Variante 1: mit Cap
|
||||||
|
cap_add:
|
||||||
|
- NET_RAW
|
||||||
|
- NET_ADMIN
|
||||||
|
command: ["-config", "/config.yaml"]
|
||||||
0
config.example.yaml
Normal file
0
config.example.yaml
Normal file
66
config.go
Normal file
66
config.go
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
ListenAddr string `yaml:"listen_addr"`
|
||||||
|
Defaults TargetSettings `yaml:"defaults"`
|
||||||
|
Targets []TargetConfig `yaml:"targets"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TargetSettings struct {
|
||||||
|
Interval time.Duration `yaml:"interval"`
|
||||||
|
Timeout time.Duration `yaml:"timeout"`
|
||||||
|
Size int `yaml:"size"`
|
||||||
|
HistorySize int `yaml:"history_size"`
|
||||||
|
DNSServer string `yaml:"dns_server"`
|
||||||
|
DisableIPv6 bool `yaml:"disable_ipv6"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TargetConfig struct {
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
Host string `yaml:"host"`
|
||||||
|
|
||||||
|
// optional overrides
|
||||||
|
Interval *time.Duration `yaml:"interval"`
|
||||||
|
Timeout *time.Duration `yaml:"timeout"`
|
||||||
|
Size *int `yaml:"size"`
|
||||||
|
HistorySize *int `yaml:"history_size"`
|
||||||
|
DNSServer *string `yaml:"dns_server"`
|
||||||
|
DisableIPv6 *bool `yaml:"disable_ipv6"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadConfig(path string) (*Config, error) {
|
||||||
|
b, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var cfg Config
|
||||||
|
if err := yaml.Unmarshal(b, &cfg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaults setzen, falls nicht da
|
||||||
|
if cfg.ListenAddr == "" {
|
||||||
|
cfg.ListenAddr = ":9101"
|
||||||
|
}
|
||||||
|
if cfg.Defaults.Interval == 0 {
|
||||||
|
cfg.Defaults.Interval = 5 * time.Second
|
||||||
|
}
|
||||||
|
if cfg.Defaults.Timeout == 0 {
|
||||||
|
cfg.Defaults.Timeout = 1 * time.Second
|
||||||
|
}
|
||||||
|
if cfg.Defaults.Size == 0 {
|
||||||
|
cfg.Defaults.Size = 56
|
||||||
|
}
|
||||||
|
if cfg.Defaults.HistorySize == 0 {
|
||||||
|
cfg.Defaults.HistorySize = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cfg, nil
|
||||||
|
}
|
||||||
135
exporter.go
Normal file
135
exporter.go
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TargetRunner struct {
|
||||||
|
name string
|
||||||
|
host string
|
||||||
|
config TargetSettings
|
||||||
|
|
||||||
|
history []float64
|
||||||
|
hidx int
|
||||||
|
mu sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTargetRunner(name, host string, cfg TargetSettings) *TargetRunner {
|
||||||
|
return &TargetRunner{
|
||||||
|
name: name,
|
||||||
|
host: host,
|
||||||
|
config: cfg,
|
||||||
|
history: make([]float64, cfg.HistorySize),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prometheus-Metrics
|
||||||
|
var (
|
||||||
|
pingUp = prometheus.NewGaugeVec(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Name: "ping_up",
|
||||||
|
Help: "Whether the last ping was successful (1) or not (0)",
|
||||||
|
},
|
||||||
|
[]string{"target"},
|
||||||
|
)
|
||||||
|
pingRTT = prometheus.NewGaugeVec(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Name: "ping_rtt_seconds",
|
||||||
|
Help: "Last ping round trip time in seconds",
|
||||||
|
},
|
||||||
|
[]string{"target"},
|
||||||
|
)
|
||||||
|
pingRTTAvg = prometheus.NewGaugeVec(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Name: "ping_rtt_seconds_avg",
|
||||||
|
Help: "Average ping round trip time in seconds (over history)",
|
||||||
|
},
|
||||||
|
[]string{"target"},
|
||||||
|
)
|
||||||
|
pingPacketsSent = prometheus.NewCounterVec(
|
||||||
|
prometheus.CounterOpts{
|
||||||
|
Name: "ping_packets_sent_total",
|
||||||
|
Help: "Total number of ping packets sent",
|
||||||
|
},
|
||||||
|
[]string{"target"},
|
||||||
|
)
|
||||||
|
pingPacketsRecv = prometheus.NewCounterVec(
|
||||||
|
prometheus.CounterOpts{
|
||||||
|
Name: "ping_packets_received_total",
|
||||||
|
Help: "Total number of ping packets received",
|
||||||
|
},
|
||||||
|
[]string{"target"},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
prometheus.MustRegister(pingUp, pingRTT, pingRTTAvg, pingPacketsSent, pingPacketsRecv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TargetRunner) Run(stop <-chan struct{}) {
|
||||||
|
lbl := prometheus.Labels{"target": t.name}
|
||||||
|
|
||||||
|
ticker := time.NewTicker(t.config.Interval)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
pingPacketsSent.With(lbl).Inc()
|
||||||
|
|
||||||
|
res := doPing(t.host, PingOptions{
|
||||||
|
Timeout: t.config.Timeout,
|
||||||
|
Size: t.config.Size,
|
||||||
|
DisableIPv6: t.config.DisableIPv6,
|
||||||
|
DNSServer: t.config.DNSServer,
|
||||||
|
})
|
||||||
|
|
||||||
|
if res.Alive {
|
||||||
|
pingUp.With(lbl).Set(1)
|
||||||
|
pingPacketsRecv.With(lbl).Inc()
|
||||||
|
|
||||||
|
sec := res.RTT.Seconds()
|
||||||
|
pingRTT.With(lbl).Set(sec)
|
||||||
|
|
||||||
|
avg := t.addToHistoryAndAvg(sec)
|
||||||
|
pingRTTAvg.With(lbl).Set(avg)
|
||||||
|
} else {
|
||||||
|
pingUp.With(lbl).Set(0)
|
||||||
|
// RTT nicht ändern oder auf 0 setzen?
|
||||||
|
pingRTT.With(lbl).Set(0)
|
||||||
|
log.Printf("ping to %s failed: %v", t.name, res.Err)
|
||||||
|
}
|
||||||
|
case <-stop:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TargetRunner) addToHistoryAndAvg(v float64) float64 {
|
||||||
|
t.mu.Lock()
|
||||||
|
defer t.mu.Unlock()
|
||||||
|
|
||||||
|
if len(t.history) == 0 {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
t.history[t.hidx] = v
|
||||||
|
t.hidx = (t.hidx + 1) % len(t.history)
|
||||||
|
|
||||||
|
var sum float64
|
||||||
|
var cnt int
|
||||||
|
for _, x := range t.history {
|
||||||
|
if x > 0 {
|
||||||
|
sum += x
|
||||||
|
cnt++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cnt == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return sum / float64(cnt)
|
||||||
|
}
|
||||||
31
go.mod
Normal file
31
go.mod
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
module git.send.nrw/sendnrw/prom-ping
|
||||||
|
|
||||||
|
go 1.25.3
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/prometheus-community/pro-bing v0.7.0
|
||||||
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
|
github.com/kr/text v0.2.0 // indirect
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
|
github.com/prometheus/client_model v0.6.2 // indirect
|
||||||
|
github.com/prometheus/common v0.66.1 // indirect
|
||||||
|
github.com/prometheus/procfs v0.16.1 // indirect
|
||||||
|
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||||
|
golang.org/x/mod v0.24.0 // indirect
|
||||||
|
golang.org/x/tools v0.33.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.36.8 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
github.com/miekg/dns v1.1.68
|
||||||
|
github.com/prometheus/client_golang v1.23.2
|
||||||
|
golang.org/x/net v0.43.0 // indirect
|
||||||
|
golang.org/x/sync v0.14.0 // indirect
|
||||||
|
golang.org/x/sys v0.35.0 // indirect
|
||||||
|
)
|
||||||
60
go.sum
Normal file
60
go.sum
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
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.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
|
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.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||||
|
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
|
github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA=
|
||||||
|
github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
|
||||||
|
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/prometheus-community/pro-bing v0.7.0 h1:KFYFbxC2f2Fp6c+TyxbCOEarf7rbnzr9Gw8eIb0RfZA=
|
||||||
|
github.com/prometheus-community/pro-bing v0.7.0/go.mod h1:Moob9dvlY50Bfq6i88xIwfyw7xLFHH69LUgx9n5zqCE=
|
||||||
|
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
|
||||||
|
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
|
||||||
|
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||||
|
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||||
|
github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
|
||||||
|
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
|
||||||
|
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
|
||||||
|
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
||||||
|
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||||
|
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||||
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
|
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
|
||||||
|
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
|
||||||
|
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||||
|
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||||
|
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||||
|
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||||
|
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||||
|
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
|
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||||
|
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
|
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
|
||||||
|
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
|
||||||
|
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||||
|
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
72
main.go
Normal file
72
main.go
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cfgFile := flag.String("config", "config.yaml", "path to config file")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
cfg, err := LoadConfig(*cfgFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error loading config: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTP server für Prometheus
|
||||||
|
http.Handle("/metrics", promhttp.Handler())
|
||||||
|
go func() {
|
||||||
|
log.Printf("listening on %s", cfg.ListenAddr)
|
||||||
|
if err := http.ListenAndServe(cfg.ListenAddr, nil); err != nil {
|
||||||
|
log.Fatalf("http server error: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Targets starten
|
||||||
|
stop := make(chan struct{})
|
||||||
|
for _, t := range cfg.Targets {
|
||||||
|
settings := mergeSettings(cfg.Defaults, t)
|
||||||
|
r := NewTargetRunner(t.Name, t.Host, settings)
|
||||||
|
go r.Run(stop)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sauber beenden
|
||||||
|
sig := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
|
||||||
|
<-sig
|
||||||
|
close(stop)
|
||||||
|
fmt.Println("shutting down...")
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeSettings(def TargetSettings, t TargetConfig) TargetSettings {
|
||||||
|
out := def
|
||||||
|
|
||||||
|
if t.Interval != nil {
|
||||||
|
out.Interval = *t.Interval
|
||||||
|
}
|
||||||
|
if t.Timeout != nil {
|
||||||
|
out.Timeout = *t.Timeout
|
||||||
|
}
|
||||||
|
if t.Size != nil {
|
||||||
|
out.Size = *t.Size
|
||||||
|
}
|
||||||
|
if t.HistorySize != nil {
|
||||||
|
out.HistorySize = *t.HistorySize
|
||||||
|
}
|
||||||
|
if t.DNSServer != nil {
|
||||||
|
out.DNSServer = *t.DNSServer
|
||||||
|
}
|
||||||
|
if t.DisableIPv6 != nil {
|
||||||
|
out.DisableIPv6 = *t.DisableIPv6
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
116
pinger.go
Normal file
116
pinger.go
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
probing "github.com/prometheus-community/pro-bing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PingResult struct {
|
||||||
|
RTT time.Duration
|
||||||
|
Alive bool
|
||||||
|
Err error
|
||||||
|
IP string
|
||||||
|
}
|
||||||
|
|
||||||
|
type PingOptions struct {
|
||||||
|
Timeout time.Duration
|
||||||
|
Size int
|
||||||
|
DisableIPv6 bool
|
||||||
|
DNSServer string
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveWithCustomDNS(server, host string) (string, error) {
|
||||||
|
c := new(dns.Client)
|
||||||
|
m := new(dns.Msg)
|
||||||
|
m.SetQuestion(dns.Fqdn(host), dns.TypeA)
|
||||||
|
|
||||||
|
resp, _, err := c.Exchange(m, server)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ans := range resp.Answer {
|
||||||
|
if a, ok := ans.(*dns.A); ok {
|
||||||
|
return a.A.String(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", errors.New("no A record found")
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveHost(host, dnsServer string, disableIPv6 bool) (string, error) {
|
||||||
|
if ip := net.ParseIP(host); ip != nil {
|
||||||
|
return host, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if dnsServer != "" {
|
||||||
|
if _, _, err := net.SplitHostPort(dnsServer); err != nil {
|
||||||
|
dnsServer = net.JoinHostPort(dnsServer, "53")
|
||||||
|
}
|
||||||
|
return resolveWithCustomDNS(dnsServer, host)
|
||||||
|
}
|
||||||
|
|
||||||
|
if disableIPv6 {
|
||||||
|
ips, err := net.LookupIP(host)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
for _, ip := range ips {
|
||||||
|
if ip.To4() != nil {
|
||||||
|
return ip.String(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", errors.New("no IPv4 address found")
|
||||||
|
}
|
||||||
|
|
||||||
|
ip, err := net.ResolveIPAddr("ip", host)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return ip.IP.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func doPing(host string, opts PingOptions) PingResult {
|
||||||
|
ip, err := resolveHost(host, opts.DNSServer, opts.DisableIPv6)
|
||||||
|
if err != nil {
|
||||||
|
return PingResult{Alive: false, Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
pinger, err := probing.NewPinger(ip)
|
||||||
|
if err != nil {
|
||||||
|
return PingResult{Alive: false, Err: err, IP: ip}
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.DisableIPv6 {
|
||||||
|
pinger.SetNetwork("ip4")
|
||||||
|
}
|
||||||
|
|
||||||
|
pinger.Count = 1
|
||||||
|
pinger.Timeout = opts.Timeout
|
||||||
|
pinger.Size = opts.Size
|
||||||
|
|
||||||
|
// falls du im Container kein CAP_NET_RAW gibst:
|
||||||
|
pinger.SetPrivileged(false) // oder aus Config
|
||||||
|
// wenn du CAP_NET_RAW vergibst:
|
||||||
|
// pinger.SetPrivileged(true)
|
||||||
|
|
||||||
|
if err := pinger.Run(); err != nil {
|
||||||
|
return PingResult{Alive: false, Err: err, IP: ip}
|
||||||
|
}
|
||||||
|
|
||||||
|
stats := pinger.Statistics()
|
||||||
|
if stats.PacketsRecv < 1 {
|
||||||
|
return PingResult{Alive: false, Err: errors.New("no reply"), IP: ip}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PingResult{
|
||||||
|
RTT: stats.AvgRtt,
|
||||||
|
Alive: true,
|
||||||
|
IP: ip,
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user