From 73cc86f9c453582f0347867358a2eb04a6ab61f6 Mon Sep 17 00:00:00 2001 From: TJ Hoplock <33664289+tjhop@users.noreply.github.com> Date: Sat, 26 Oct 2024 15:35:51 -0400 Subject: [PATCH] chore!: adopt log/slog, drop go-kit/log (#1311) * chore!: adopt log/slog, drop go-kit/log The bulk of this change set was automated by the following script which is being used to aid in converting the various exporters/projects to use slog: https://gist.github.com/tjhop/49f96fb7ebbe55b12deee0b0312d8434 Other changes included: - upgrade go in ci to 1.23 - update client_golang, common, exporter-toolkit Signed-off-by: TJ Hoplock * build: don't specify toolchain in go.mod Address PR feedback, not necessary. Can always be re-added. Signed-off-by: TJ Hoplock --------- Signed-off-by: TJ Hoplock --- .circleci/config.yml | 4 +- .golangci.yml | 1 + .promu.yml | 2 +- config/config.go | 7 ++- go.mod | 22 ++++----- go.sum | 40 +++++++-------- main.go | 53 ++++++++++---------- prober/dns.go | 71 ++++++++++++++------------- prober/dns_test.go | 18 +++---- prober/grpc.go | 28 +++++------ prober/grpc_test.go | 18 +++---- prober/handler.go | 107 +++++++++++++++++++++++++++++++++-------- prober/handler_test.go | 13 +++-- prober/http.go | 77 +++++++++++++++-------------- prober/http_test.go | 98 ++++++++++++++++++++----------------- prober/icmp.go | 61 ++++++++++++----------- prober/prober.go | 4 +- prober/tcp.go | 47 +++++++++--------- prober/tcp_test.go | 39 ++++++++------- prober/utils.go | 20 ++++---- prober/utils_test.go | 7 +-- 21 files changed, 400 insertions(+), 337 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index add55617..959d31d2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,7 @@ executors: # Whenever the Go version is updated here, .promu.yml should also be updated. golang: docker: - - image: cimg/go:1.22 + - image: cimg/go:1.23 jobs: test: executor: golang @@ -22,7 +22,7 @@ jobs: working_directory: /home/circleci/.go_workspace/src/github.com/prometheus/blackbox_exporter # Whenever the Go version is updated here, .promu.yml should also be updated. environment: - DOCKER_TEST_IMAGE_NAME: quay.io/prometheus/golang-builder:1.22-base + DOCKER_TEST_IMAGE_NAME: quay.io/prometheus/golang-builder:1.23-base steps: - checkout - run: diff --git a/.golangci.yml b/.golangci.yml index eac1e3db..14fd8da4 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -4,3 +4,4 @@ linters: enable: - misspell - staticcheck + - sloglint diff --git a/.promu.yml b/.promu.yml index a06b791b..acb28a4c 100644 --- a/.promu.yml +++ b/.promu.yml @@ -1,6 +1,6 @@ go: # Whenever the Go version is updated here, .circle/config.yml should also be updated. - version: 1.22 + version: 1.23 repository: path: github.com/prometheus/blackbox_exporter build: diff --git a/config/config.go b/config/config.go index 559dbf56..143095d5 100644 --- a/config/config.go +++ b/config/config.go @@ -16,6 +16,7 @@ package config import ( "errors" "fmt" + "log/slog" "math" "net/textproto" "os" @@ -30,8 +31,6 @@ import ( yaml "gopkg.in/yaml.v3" "github.com/alecthomas/units" - "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/miekg/dns" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -104,7 +103,7 @@ func NewSafeConfig(reg prometheus.Registerer) *SafeConfig { return &SafeConfig{C: &Config{}, configReloadSuccess: configReloadSuccess, configReloadSeconds: configReloadSeconds} } -func (sc *SafeConfig) ReloadConfig(confFile string, logger log.Logger) (err error) { +func (sc *SafeConfig) ReloadConfig(confFile string, logger *slog.Logger) (err error) { var c = &Config{} defer func() { if err != nil { @@ -133,7 +132,7 @@ func (sc *SafeConfig) ReloadConfig(confFile string, logger log.Logger) (err erro module.HTTP.NoFollowRedirects = nil c.Modules[name] = module if logger != nil { - level.Warn(logger).Log("msg", "no_follow_redirects is deprecated and will be removed in the next release. It is replaced by follow_redirects.", "module", name) + logger.Warn("no_follow_redirects is deprecated and will be removed in the next release. It is replaced by follow_redirects.", "module", name) } } } diff --git a/go.mod b/go.mod index 7e62fb90..9d0e2961 100644 --- a/go.mod +++ b/go.mod @@ -1,18 +1,17 @@ module github.com/prometheus/blackbox_exporter -go 1.21 +go 1.22 require ( github.com/alecthomas/kingpin/v2 v2.4.0 github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 github.com/andybalholm/brotli v1.1.0 - github.com/go-kit/log v0.2.1 github.com/miekg/dns v1.1.62 - github.com/prometheus/client_golang v1.20.4 + github.com/prometheus/client_golang v1.20.5 github.com/prometheus/client_model v0.6.1 - github.com/prometheus/common v0.57.0 - github.com/prometheus/exporter-toolkit v0.11.0 - golang.org/x/net v0.28.0 + github.com/prometheus/common v0.60.1 + github.com/prometheus/exporter-toolkit v0.13.0 + golang.org/x/net v0.29.0 google.golang.org/grpc v1.67.0 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 @@ -22,19 +21,20 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect - github.com/go-logfmt/logfmt v0.5.1 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/klauspost/compress v1.17.9 // indirect + github.com/mdlayher/socket v0.4.1 // indirect + github.com/mdlayher/vsock v1.2.1 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect - golang.org/x/crypto v0.26.0 // indirect + golang.org/x/crypto v0.27.0 // indirect golang.org/x/mod v0.18.0 // indirect - golang.org/x/oauth2 v0.22.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.18.0 // indirect golang.org/x/tools v0.22.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect google.golang.org/protobuf v1.34.2 // indirect diff --git a/go.sum b/go.sum index aee2d748..c6d8cd67 100644 --- a/go.sum +++ b/go.sum @@ -13,10 +13,6 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= -github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -30,6 +26,10 @@ 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/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= +github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= +github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ= +github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE= github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= @@ -38,14 +38,14 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 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/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_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= +github.com/prometheus/client_golang v1.20.5/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.57.0 h1:Ro/rKjwdq9mZn1K5QPctzh+MA4Lp0BuYk5ZZEVhoNcY= -github.com/prometheus/common v0.57.0/go.mod h1:7uRPFSUTbfZWsJ7MHY56sqt7hLQu3bxXHDnNhl8E9qI= -github.com/prometheus/exporter-toolkit v0.11.0 h1:yNTsuZ0aNCNFQ3aFTD2uhPOvr4iD7fdBvKPAEGkNf+g= -github.com/prometheus/exporter-toolkit v0.11.0/go.mod h1:BVnENhnNecpwoTLiABx7mrPB/OLRIgN74qlQbV+FK1Q= +github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc= +github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= +github.com/prometheus/exporter-toolkit v0.13.0 h1:lmA0Q+8IaXgmFRKw09RldZmZdnvu9wwcDLIXGmTPw1c= +github.com/prometheus/exporter-toolkit v0.13.0/go.mod h1:2uop99EZl80KdXhv/MxVI2181fMcwlsumFOqBecGkG0= 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/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= @@ -56,20 +56,20 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= -golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= diff --git a/main.go b/main.go index 7f86caa4..61336c76 100644 --- a/main.go +++ b/main.go @@ -29,13 +29,12 @@ import ( "syscall" "github.com/alecthomas/kingpin/v2" - "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" versioncollector "github.com/prometheus/client_golang/prometheus/collectors/version" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/prometheus/common/promlog" - "github.com/prometheus/common/promlog/flag" + "github.com/prometheus/common/promslog" + "github.com/prometheus/common/promslog/flag" "github.com/prometheus/common/version" "github.com/prometheus/exporter-toolkit/web" webflag "github.com/prometheus/exporter-toolkit/web/kingpinflag" @@ -51,7 +50,7 @@ var ( configFile = kingpin.Flag("config.file", "Blackbox exporter configuration file.").Default("blackbox.yml").String() timeoutOffset = kingpin.Flag("timeout-offset", "Offset to subtract from timeout in seconds.").Default("0.5").Float64() configCheck = kingpin.Flag("config.check", "If true validate the config file and then exit.").Default().Bool() - logLevelProber = kingpin.Flag("log.prober", "Log level from probe requests. One of: [debug, info, warn, error, none]").Default("none").String() + logLevelProber = kingpin.Flag("log.prober", "Log level from probe requests. One of: [debug, info, warn, error]").Default("info").String() historyLimit = kingpin.Flag("history.limit", "The maximum amount of items to keep in the history.").Default("100").Uint() externalURL = kingpin.Flag("web.external-url", "The URL under which Blackbox exporter is externally reachable (for example, if Blackbox exporter is served via a reverse proxy). Used for generating relative and absolute links back to Blackbox exporter itself. If the URL has a path portion, it will be used to prefix all HTTP endpoints served by Blackbox exporter. If omitted, relevant URL components will be derived automatically.").PlaceHolder("").String() routePrefix = kingpin.Flag("web.route-prefix", "Prefix for the internal routes of web endpoints. Defaults to path of --web.external-url.").PlaceHolder("").String() @@ -73,46 +72,46 @@ func main() { func run() int { kingpin.CommandLine.UsageWriter(os.Stdout) - promlogConfig := &promlog.Config{} - flag.AddFlags(kingpin.CommandLine, promlogConfig) + promslogConfig := &promslog.Config{} + flag.AddFlags(kingpin.CommandLine, promslogConfig) kingpin.Version(version.Print("blackbox_exporter")) kingpin.HelpFlag.Short('h') kingpin.Parse() - logger := promlog.New(promlogConfig) + logger := promslog.New(promslogConfig) rh := &prober.ResultHistory{MaxResults: *historyLimit} - logLevelProberValue, _ := level.Parse(*logLevelProber) - logLevelProber := level.Allow(logLevelProberValue) + allowedLevel := &promslog.AllowedLevel{} + _ = allowedLevel.Set(*logLevelProber) - level.Info(logger).Log("msg", "Starting blackbox_exporter", "version", version.Info()) - level.Info(logger).Log("build_context", version.BuildContext()) + logger.Info("Starting blackbox_exporter", "version", version.Info()) + logger.Info(version.BuildContext()) if err := sc.ReloadConfig(*configFile, logger); err != nil { - level.Error(logger).Log("msg", "Error loading config", "err", err) + logger.Error("Error loading config", "err", err) return 1 } if *configCheck { - level.Info(logger).Log("msg", "Config file is ok exiting...") + logger.Info("Config file is ok exiting...") return 0 } - level.Info(logger).Log("msg", "Loaded config file") + logger.Info("Loaded config file") // Infer or set Blackbox exporter externalURL listenAddrs := toolkitFlags.WebListenAddresses if *externalURL == "" && *toolkitFlags.WebSystemdSocket { - level.Error(logger).Log("msg", "Cannot automatically infer external URL with systemd socket listener. Please provide --web.external-url") + logger.Error("Cannot automatically infer external URL with systemd socket listener. Please provide --web.external-url") return 1 } else if *externalURL == "" && len(*listenAddrs) > 1 { - level.Info(logger).Log("msg", "Inferring external URL from first provided listen address") + logger.Info("Inferring external URL from first provided listen address") } beURL, err := computeExternalURL(*externalURL, (*listenAddrs)[0]) if err != nil { - level.Error(logger).Log("msg", "failed to determine external URL", "err", err) + logger.Error("failed to determine external URL", "err", err) return 1 } - level.Debug(logger).Log("externalURL", beURL.String()) + logger.Debug(beURL.String()) // Default -web.route-prefix to path of -web.external-url. if *routePrefix == "" { @@ -126,7 +125,7 @@ func run() int { if *routePrefix != "/" { *routePrefix = *routePrefix + "/" } - level.Debug(logger).Log("routePrefix", *routePrefix) + logger.Debug(*routePrefix) hup := make(chan os.Signal, 1) reloadCh := make(chan chan error) @@ -136,16 +135,16 @@ func run() int { select { case <-hup: if err := sc.ReloadConfig(*configFile, logger); err != nil { - level.Error(logger).Log("msg", "Error reloading config", "err", err) + logger.Error("Error reloading config", "err", err) continue } - level.Info(logger).Log("msg", "Reloaded config file") + logger.Info("Reloaded config file") case rc := <-reloadCh: if err := sc.ReloadConfig(*configFile, logger); err != nil { - level.Error(logger).Log("msg", "Error reloading config", "err", err) + logger.Error("Error reloading config", "err", err) rc <- err } else { - level.Info(logger).Log("msg", "Reloaded config file") + logger.Info("Reloaded config file") rc <- nil } } @@ -187,7 +186,7 @@ func run() int { sc.Lock() conf := sc.C sc.Unlock() - prober.Handler(w, r, conf, logger, rh, *timeoutOffset, nil, moduleUnknownCounter, logLevelProber) + prober.Handler(w, r, conf, logger, rh, *timeoutOffset, nil, moduleUnknownCounter, allowedLevel) }) http.HandleFunc(*routePrefix, func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html") @@ -256,7 +255,7 @@ func run() int { c, err := yaml.Marshal(sc.C) sc.RUnlock() if err != nil { - level.Warn(logger).Log("msg", "Error marshalling configuration", "err", err) + logger.Warn("Error marshalling configuration", "err", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -271,7 +270,7 @@ func run() int { go func() { if err := web.ListenAndServe(srv, toolkitFlags, logger); err != nil { - level.Error(logger).Log("msg", "Error starting HTTP server", "err", err) + logger.Error("Error starting HTTP server", "err", err) close(srvc) } }() @@ -279,7 +278,7 @@ func run() int { for { select { case <-term: - level.Info(logger).Log("msg", "Received SIGTERM, exiting gracefully...") + logger.Info("Received SIGTERM, exiting gracefully...") return 0 case <-srvc: return 1 diff --git a/prober/dns.go b/prober/dns.go index 6bf2e465..184fa949 100644 --- a/prober/dns.go +++ b/prober/dns.go @@ -15,12 +15,11 @@ package prober import ( "context" + "log/slog" "net" "regexp" "time" - "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/miekg/dns" "github.com/prometheus/client_golang/prometheus" pconfig "github.com/prometheus/common/config" @@ -29,36 +28,36 @@ import ( ) // validRRs checks a slice of RRs received from the server against a DNSRRValidator. -func validRRs(rrs *[]dns.RR, v *config.DNSRRValidator, logger log.Logger) bool { +func validRRs(rrs *[]dns.RR, v *config.DNSRRValidator, logger *slog.Logger) bool { var anyMatch bool = false var allMatch bool = true // Fail the probe if there are no RRs of a given type, but a regexp match is required // (i.e. FailIfNotMatchesRegexp or FailIfNoneMatchesRegexp is set). if len(*rrs) == 0 && len(v.FailIfNotMatchesRegexp) > 0 { - level.Error(logger).Log("msg", "fail_if_not_matches_regexp specified but no RRs returned") + logger.Error("fail_if_not_matches_regexp specified but no RRs returned") return false } if len(*rrs) == 0 && len(v.FailIfNoneMatchesRegexp) > 0 { - level.Error(logger).Log("msg", "fail_if_none_matches_regexp specified but no RRs returned") + logger.Error("fail_if_none_matches_regexp specified but no RRs returned") return false } for _, rr := range *rrs { - level.Info(logger).Log("msg", "Validating RR", "rr", rr) + logger.Info("Validating RR", "rr", rr) for _, re := range v.FailIfMatchesRegexp { match, err := regexp.MatchString(re, rr.String()) if err != nil { - level.Error(logger).Log("msg", "Error matching regexp", "regexp", re, "err", err) + logger.Error("Error matching regexp", "regexp", re, "err", err) return false } if match { - level.Error(logger).Log("msg", "At least one RR matched regexp", "regexp", re, "rr", rr) + logger.Error("At least one RR matched regexp", "regexp", re, "rr", rr) return false } } for _, re := range v.FailIfAllMatchRegexp { match, err := regexp.MatchString(re, rr.String()) if err != nil { - level.Error(logger).Log("msg", "Error matching regexp", "regexp", re, "err", err) + logger.Error("Error matching regexp", "regexp", re, "err", err) return false } if !match { @@ -68,18 +67,18 @@ func validRRs(rrs *[]dns.RR, v *config.DNSRRValidator, logger log.Logger) bool { for _, re := range v.FailIfNotMatchesRegexp { match, err := regexp.MatchString(re, rr.String()) if err != nil { - level.Error(logger).Log("msg", "Error matching regexp", "regexp", re, "err", err) + logger.Error("Error matching regexp", "regexp", re, "err", err) return false } if !match { - level.Error(logger).Log("msg", "At least one RR did not match regexp", "regexp", re, "rr", rr) + logger.Error("At least one RR did not match regexp", "regexp", re, "rr", rr) return false } } for _, re := range v.FailIfNoneMatchesRegexp { match, err := regexp.MatchString(re, rr.String()) if err != nil { - level.Error(logger).Log("msg", "Error matching regexp", "regexp", re, "err", err) + logger.Error("Error matching regexp", "regexp", re, "err", err) return false } if match { @@ -88,18 +87,18 @@ func validRRs(rrs *[]dns.RR, v *config.DNSRRValidator, logger log.Logger) bool { } } if len(v.FailIfAllMatchRegexp) > 0 && !allMatch { - level.Error(logger).Log("msg", "Not all RRs matched regexp") + logger.Error("Not all RRs matched regexp") return false } if len(v.FailIfNoneMatchesRegexp) > 0 && !anyMatch { - level.Error(logger).Log("msg", "None of the RRs did matched any regexp") + logger.Error("None of the RRs did matched any regexp") return false } return true } // validRcode checks rcode in the response against a list of valid rcodes. -func validRcode(rcode int, valid []string, logger log.Logger) bool { +func validRcode(rcode int, valid []string, logger *slog.Logger) bool { var validRcodes []int // If no list of valid rcodes is specified, only NOERROR is considered valid. if valid == nil { @@ -108,7 +107,7 @@ func validRcode(rcode int, valid []string, logger log.Logger) bool { for _, rcode := range valid { rc, ok := dns.StringToRcode[rcode] if !ok { - level.Error(logger).Log("msg", "Invalid rcode", "rcode", rcode, "known_rcode", dns.RcodeToString) + logger.Error("Invalid rcode", "rcode", rcode, "known_rcode", dns.RcodeToString) return false } validRcodes = append(validRcodes, rc) @@ -116,15 +115,15 @@ func validRcode(rcode int, valid []string, logger log.Logger) bool { } for _, rc := range validRcodes { if rcode == rc { - level.Info(logger).Log("msg", "Rcode is valid", "rcode", rcode, "string_rcode", dns.RcodeToString[rcode]) + logger.Info("Rcode is valid", "rcode", rcode, "string_rcode", dns.RcodeToString[rcode]) return true } } - level.Error(logger).Log("msg", "Rcode is not one of the valid rcodes", "rcode", rcode, "string_rcode", dns.RcodeToString[rcode], "valid_rcodes", validRcodes) + logger.Error("Rcode is not one of the valid rcodes", "rcode", rcode, "string_rcode", dns.RcodeToString[rcode], "valid_rcodes", validRcodes) return false } -func ProbeDNS(ctx context.Context, target string, module config.Module, registry *prometheus.Registry, logger log.Logger) bool { +func ProbeDNS(ctx context.Context, target string, module config.Module, registry *prometheus.Registry, logger *slog.Logger) bool { var dialProtocol string probeDNSDurationGaugeVec := prometheus.NewGaugeVec(prometheus.GaugeOpts{ Name: "probe_dns_duration_seconds", @@ -162,7 +161,7 @@ func ProbeDNS(ctx context.Context, target string, module config.Module, registry var ok bool qc, ok = dns.StringToClass[module.DNS.QueryClass] if !ok { - level.Error(logger).Log("msg", "Invalid query class", "Class seen", module.DNS.QueryClass, "Existing classes", dns.ClassToString) + logger.Error("Invalid query class", "Class seen", module.DNS.QueryClass, "Existing classes", dns.ClassToString) return false } } @@ -172,7 +171,7 @@ func ProbeDNS(ctx context.Context, target string, module config.Module, registry var ok bool qt, ok = dns.StringToType[module.DNS.QueryType] if !ok { - level.Error(logger).Log("msg", "Invalid query type", "Type seen", module.DNS.QueryType, "Existing types", dns.TypeToString) + logger.Error("Invalid query type", "Type seen", module.DNS.QueryType, "Existing types", dns.TypeToString) return false } } @@ -183,7 +182,7 @@ func ProbeDNS(ctx context.Context, target string, module config.Module, registry module.DNS.TransportProtocol = "udp" } if !(module.DNS.TransportProtocol == "udp" || module.DNS.TransportProtocol == "tcp") { - level.Error(logger).Log("msg", "Configuration error: Expected transport protocol udp or tcp", "protocol", module.DNS.TransportProtocol) + logger.Error("Configuration error: Expected transport protocol udp or tcp", "protocol", module.DNS.TransportProtocol) return false } @@ -199,7 +198,7 @@ func ProbeDNS(ctx context.Context, target string, module config.Module, registry } ip, lookupTime, err := chooseProtocol(ctx, module.DNS.IPProtocol, module.DNS.IPProtocolFallback, targetAddr, registry, logger) if err != nil { - level.Error(logger).Log("msg", "Error resolving address", "err", err) + logger.Error("Error resolving address", "err", err) return false } probeDNSDurationGaugeVec.WithLabelValues("resolve").Add(lookupTime) @@ -215,7 +214,7 @@ func ProbeDNS(ctx context.Context, target string, module config.Module, registry if module.DNS.TransportProtocol == "tcp" { dialProtocol += "-tls" } else { - level.Error(logger).Log("msg", "Configuration error: Expected transport protocol tcp for DoT", "protocol", module.DNS.TransportProtocol) + logger.Error("Configuration error: Expected transport protocol tcp for DoT", "protocol", module.DNS.TransportProtocol) return false } } @@ -226,7 +225,7 @@ func ProbeDNS(ctx context.Context, target string, module config.Module, registry if module.DNS.DNSOverTLS { tlsConfig, err := pconfig.NewTLSConfig(&module.DNS.TLSConfig) if err != nil { - level.Error(logger).Log("msg", "Failed to create TLS configuration", "err", err) + logger.Error("Failed to create TLS configuration", "err", err) return false } if tlsConfig.ServerName == "" { @@ -241,10 +240,10 @@ func ProbeDNS(ctx context.Context, target string, module config.Module, registry if len(module.DNS.SourceIPAddress) > 0 { srcIP := net.ParseIP(module.DNS.SourceIPAddress) if srcIP == nil { - level.Error(logger).Log("msg", "Error parsing source ip address", "srcIP", module.DNS.SourceIPAddress) + logger.Error("Error parsing source ip address", "srcIP", module.DNS.SourceIPAddress) return false } - level.Info(logger).Log("msg", "Using local address", "srcIP", srcIP) + logger.Info("Using local address", "srcIP", srcIP) client.Dialer = &net.Dialer{} if module.DNS.TransportProtocol == "tcp" { client.Dialer.LocalAddr = &net.TCPAddr{IP: srcIP} @@ -259,7 +258,7 @@ func ProbeDNS(ctx context.Context, target string, module config.Module, registry msg.Question = make([]dns.Question, 1) msg.Question[0] = dns.Question{dns.Fqdn(module.DNS.QueryName), qt, qc} - level.Info(logger).Log("msg", "Making DNS query", "target", targetIP, "dial_protocol", dialProtocol, "query", module.DNS.QueryName, "type", qt, "class", qc) + logger.Info("Making DNS query", "target", targetIP, "dial_protocol", dialProtocol, "query", module.DNS.QueryName, "type", qt, "class", qc) timeoutDeadline, _ := ctx.Deadline() client.Timeout = time.Until(timeoutDeadline) requestStart := time.Now() @@ -271,10 +270,10 @@ func ProbeDNS(ctx context.Context, target string, module config.Module, registry probeDNSDurationGaugeVec.WithLabelValues("connect").Set((time.Since(requestStart) - rtt).Seconds()) probeDNSDurationGaugeVec.WithLabelValues("request").Set(rtt.Seconds()) if err != nil { - level.Error(logger).Log("msg", "Error while sending a DNS query", "err", err) + logger.Error("Error while sending a DNS query", "err", err) return false } - level.Info(logger).Log("msg", "Got response", "response", response) + logger.Info("Got response", "response", response) probeDNSAnswerRRSGauge.Set(float64(len(response.Answer))) probeDNSAuthorityRRSGauge.Set(float64(len(response.Ns))) @@ -298,19 +297,19 @@ func ProbeDNS(ctx context.Context, target string, module config.Module, registry if !validRcode(response.Rcode, module.DNS.ValidRcodes, logger) { return false } - level.Info(logger).Log("msg", "Validating Answer RRs") + logger.Info("Validating Answer RRs") if !validRRs(&response.Answer, &module.DNS.ValidateAnswer, logger) { - level.Error(logger).Log("msg", "Answer RRs validation failed") + logger.Error("Answer RRs validation failed") return false } - level.Info(logger).Log("msg", "Validating Authority RRs") + logger.Info("Validating Authority RRs") if !validRRs(&response.Ns, &module.DNS.ValidateAuthority, logger) { - level.Error(logger).Log("msg", "Authority RRs validation failed") + logger.Error("Authority RRs validation failed") return false } - level.Info(logger).Log("msg", "Validating Additional RRs") + logger.Info("Validating Additional RRs") if !validRRs(&response.Extra, &module.DNS.ValidateAdditional, logger) { - level.Error(logger).Log("msg", "Additional RRs validation failed") + logger.Error("Additional RRs validation failed") return false } return true diff --git a/prober/dns_test.go b/prober/dns_test.go index 22f702cf..4e4fdff2 100644 --- a/prober/dns_test.go +++ b/prober/dns_test.go @@ -21,9 +21,9 @@ import ( "testing" "time" - "github.com/go-kit/log" "github.com/miekg/dns" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/common/promslog" "github.com/prometheus/blackbox_exporter/config" ) @@ -170,7 +170,7 @@ func TestRecursiveDNSResponse(t *testing.T) { testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - result := ProbeDNS(testCTX, addr.String(), config.Module{Timeout: time.Second, DNS: test.Probe}, registry, log.NewNopLogger()) + result := ProbeDNS(testCTX, addr.String(), config.Module{Timeout: time.Second, DNS: test.Probe}, registry, promslog.NewNopLogger()) if result != test.ShouldSucceed { t.Fatalf("Test %d had unexpected result: %v", i, result) } @@ -374,7 +374,7 @@ func TestAuthoritativeDNSResponse(t *testing.T) { registry := prometheus.NewRegistry() testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - result := ProbeDNS(testCTX, addr.String(), config.Module{Timeout: time.Second, DNS: test.Probe}, registry, log.NewNopLogger()) + result := ProbeDNS(testCTX, addr.String(), config.Module{Timeout: time.Second, DNS: test.Probe}, registry, promslog.NewNopLogger()) if result != test.ShouldSucceed { t.Fatalf("Test %d had unexpected result: %v", i, result) } @@ -449,7 +449,7 @@ func TestServfailDNSResponse(t *testing.T) { registry := prometheus.NewRegistry() testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - result := ProbeDNS(testCTX, addr.String(), config.Module{Timeout: time.Second, DNS: test.Probe}, registry, log.NewNopLogger()) + result := ProbeDNS(testCTX, addr.String(), config.Module{Timeout: time.Second, DNS: test.Probe}, registry, promslog.NewNopLogger()) if result != test.ShouldSucceed { t.Fatalf("Test %d had unexpected result: %v", i, result) } @@ -509,7 +509,7 @@ func TestDNSProtocol(t *testing.T) { registry := prometheus.NewRegistry() testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - result := ProbeDNS(testCTX, net.JoinHostPort("localhost", port), module, registry, log.NewNopLogger()) + result := ProbeDNS(testCTX, net.JoinHostPort("localhost", port), module, registry, promslog.NewNopLogger()) if !result { t.Fatalf("DNS protocol: \"%v\", preferred \"ip6\" connection test failed, expected success.", protocol) } @@ -535,7 +535,7 @@ func TestDNSProtocol(t *testing.T) { registry = prometheus.NewRegistry() testCTX, cancel = context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - result = ProbeDNS(testCTX, net.JoinHostPort("localhost", port), module, registry, log.NewNopLogger()) + result = ProbeDNS(testCTX, net.JoinHostPort("localhost", port), module, registry, promslog.NewNopLogger()) if !result { t.Fatalf("DNS protocol: \"%v\", preferred \"ip4\" connection test failed, expected success.", protocol) } @@ -561,7 +561,7 @@ func TestDNSProtocol(t *testing.T) { registry = prometheus.NewRegistry() testCTX, cancel = context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - result = ProbeDNS(testCTX, net.JoinHostPort("localhost", port), module, registry, log.NewNopLogger()) + result = ProbeDNS(testCTX, net.JoinHostPort("localhost", port), module, registry, promslog.NewNopLogger()) if !result { t.Fatalf("DNS protocol: \"%v\" connection test failed, expected success.", protocol) } @@ -586,7 +586,7 @@ func TestDNSProtocol(t *testing.T) { registry = prometheus.NewRegistry() testCTX, cancel = context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - result = ProbeDNS(testCTX, net.JoinHostPort("localhost", port), module, registry, log.NewNopLogger()) + result = ProbeDNS(testCTX, net.JoinHostPort("localhost", port), module, registry, promslog.NewNopLogger()) if protocol == "udp" { if !result { t.Fatalf("DNS test connection with protocol %s failed, expected success.", protocol) @@ -629,7 +629,7 @@ func TestDNSMetrics(t *testing.T) { registry := prometheus.NewRegistry() testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - result := ProbeDNS(testCTX, net.JoinHostPort("localhost", port), module, registry, log.NewNopLogger()) + result := ProbeDNS(testCTX, net.JoinHostPort("localhost", port), module, registry, promslog.NewNopLogger()) if !result { t.Fatalf("DNS test connection failed, expected success.") } diff --git a/prober/grpc.go b/prober/grpc.go index 9f1493ed..64c54dec 100644 --- a/prober/grpc.go +++ b/prober/grpc.go @@ -15,8 +15,12 @@ package prober import ( "context" - "github.com/go-kit/log" - "github.com/go-kit/log/level" + "log/slog" + "net" + "net/url" + "strings" + "time" + "github.com/prometheus/blackbox_exporter/config" "github.com/prometheus/client_golang/prometheus" pconfig "github.com/prometheus/common/config" @@ -27,10 +31,6 @@ import ( "google.golang.org/grpc/health/grpc_health_v1" "google.golang.org/grpc/peer" "google.golang.org/grpc/status" - "net" - "net/url" - "strings" - "time" ) type GRPCHealthCheck interface { @@ -74,7 +74,7 @@ func (c *gRPCHealthCheckClient) Check(ctx context.Context, service string) (bool return false, returnStatus.Code(), nil, "", err } -func ProbeGRPC(ctx context.Context, target string, module config.Module, registry *prometheus.Registry, logger log.Logger) (success bool) { +func ProbeGRPC(ctx context.Context, target string, module config.Module, registry *prometheus.Registry, logger *slog.Logger) (success bool) { var ( durationGaugeVec = prometheus.NewGaugeVec(prometheus.GaugeOpts{ @@ -131,7 +131,7 @@ func ProbeGRPC(ctx context.Context, target string, module config.Module, registr targetURL, err := url.Parse(target) if err != nil { - level.Error(logger).Log("msg", "Could not parse target URL", "err", err) + logger.Error("Could not parse target URL", "err", err) return false } @@ -143,13 +143,13 @@ func ProbeGRPC(ctx context.Context, target string, module config.Module, registr tlsConfig, err := pconfig.NewTLSConfig(&module.GRPC.TLSConfig) if err != nil { - level.Error(logger).Log("msg", "Error creating TLS configuration", "err", err) + logger.Error("Error creating TLS configuration", "err", err) return false } ip, lookupTime, err := chooseProtocol(ctx, module.GRPC.PreferredIPProtocol, module.GRPC.IPProtocolFallback, targetHost, registry, logger) if err != nil { - level.Error(logger).Log("msg", "Error resolving address", "err", err) + logger.Error("Error resolving address", "err", err) return false } durationGaugeVec.WithLabelValues("resolve").Add(lookupTime) @@ -169,7 +169,7 @@ func ProbeGRPC(ctx context.Context, target string, module config.Module, registr var opts []grpc.DialOption target = targetHost + ":" + targetPort if !module.GRPC.TLS { - level.Debug(logger).Log("msg", "Dialing GRPC without TLS") + logger.Debug("Dialing GRPC without TLS") opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) if len(targetPort) == 0 { target = targetHost + ":80" @@ -185,7 +185,7 @@ func ProbeGRPC(ctx context.Context, target string, module config.Module, registr conn, err := grpc.NewClient(target, opts...) if err != nil { - level.Error(logger).Log("did not connect: %v", err) + logger.Error("did not connect", "err", err) } client := NewGrpcHealthCheckClient(conn) @@ -214,10 +214,10 @@ func ProbeGRPC(ctx context.Context, target string, module config.Module, registr statusCodeGauge.Set(float64(statusCode)) if !ok || err != nil { - level.Error(logger).Log("msg", "can't connect grpc server:", "err", err) + logger.Error("can't connect grpc server:", "err", err) success = false } else { - level.Debug(logger).Log("connect the grpc server successfully") + logger.Debug("connect the grpc server successfully") success = true } diff --git a/prober/grpc_test.go b/prober/grpc_test.go index 1fd14020..d1ab870f 100644 --- a/prober/grpc_test.go +++ b/prober/grpc_test.go @@ -24,10 +24,10 @@ import ( "testing" "time" - "github.com/go-kit/log" "github.com/prometheus/blackbox_exporter/config" "github.com/prometheus/client_golang/prometheus" pconfig "github.com/prometheus/common/config" + "github.com/prometheus/common/promslog" "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/health" @@ -67,7 +67,7 @@ func TestGRPCConnection(t *testing.T) { config.Module{Timeout: time.Second, GRPC: config.GRPCProbe{ IPProtocolFallback: false, }, - }, registry, log.NewNopLogger()) + }, registry, promslog.NewNopLogger()) if !result { t.Fatalf("GRPC probe failed") @@ -134,7 +134,7 @@ func TestMultipleGRPCservices(t *testing.T) { IPProtocolFallback: false, Service: "service1", }, - }, registryService1, log.NewNopLogger()) + }, registryService1, promslog.NewNopLogger()) if !resultService1 { t.Fatalf("GRPC probe failed for service1") @@ -146,7 +146,7 @@ func TestMultipleGRPCservices(t *testing.T) { IPProtocolFallback: false, Service: "service2", }, - }, registryService2, log.NewNopLogger()) + }, registryService2, promslog.NewNopLogger()) if resultService2 { t.Fatalf("GRPC probe succeed for service2") @@ -158,7 +158,7 @@ func TestMultipleGRPCservices(t *testing.T) { IPProtocolFallback: false, Service: "service3", }, - }, registryService3, log.NewNopLogger()) + }, registryService3, promslog.NewNopLogger()) if resultService3 { t.Fatalf("GRPC probe succeed for service3") @@ -231,7 +231,7 @@ func TestGRPCTLSConnection(t *testing.T) { TLSConfig: pconfig.TLSConfig{InsecureSkipVerify: true}, IPProtocolFallback: false, }, - }, registry, log.NewNopLogger()) + }, registry, promslog.NewNopLogger()) if !result { t.Fatalf("GRPC probe failed") @@ -292,7 +292,7 @@ func TestNoTLSConnection(t *testing.T) { TLSConfig: pconfig.TLSConfig{InsecureSkipVerify: true}, IPProtocolFallback: false, }, - }, registry, log.NewNopLogger()) + }, registry, promslog.NewNopLogger()) if result { t.Fatalf("GRPC probe succeed") @@ -346,7 +346,7 @@ func TestGRPCServiceNotFound(t *testing.T) { IPProtocolFallback: false, Service: "NonExistingService", }, - }, registry, log.NewNopLogger()) + }, registry, promslog.NewNopLogger()) if result { t.Fatalf("GRPC probe succeed") @@ -396,7 +396,7 @@ func TestGRPCHealthCheckUnimplemented(t *testing.T) { IPProtocolFallback: false, Service: "NonExistingService", }, - }, registry, log.NewNopLogger()) + }, registry, promslog.NewNopLogger()) if result { t.Fatalf("GRPC probe succeed") diff --git a/prober/handler.go b/prober/handler.go index 180a076b..50346ff2 100644 --- a/prober/handler.go +++ b/prober/handler.go @@ -16,19 +16,20 @@ package prober import ( "bytes" "context" + "errors" "fmt" + "log/slog" "net/http" "net/textproto" "net/url" "strconv" "time" - "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/prometheus/blackbox_exporter/config" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/common/expfmt" + "github.com/prometheus/common/promslog" "gopkg.in/yaml.v2" ) @@ -42,9 +43,9 @@ var ( } ) -func Handler(w http.ResponseWriter, r *http.Request, c *config.Config, logger log.Logger, rh *ResultHistory, timeoutOffset float64, params url.Values, +func Handler(w http.ResponseWriter, r *http.Request, c *config.Config, logger *slog.Logger, rh *ResultHistory, timeoutOffset float64, params url.Values, moduleUnknownCounter prometheus.Counter, - logLevelProber level.Option) { + logLevelProber *promslog.AllowedLevel) { if params == nil { params = r.URL.Query() @@ -56,7 +57,7 @@ func Handler(w http.ResponseWriter, r *http.Request, c *config.Config, logger lo module, ok := c.Modules[moduleName] if !ok { http.Error(w, fmt.Sprintf("Unknown module %q", moduleName), http.StatusBadRequest) - level.Debug(logger).Log("msg", "Unknown module", "module", moduleName) + logger.Debug("Unknown module", "module", moduleName) if moduleUnknownCounter != nil { moduleUnknownCounter.Add(1) } @@ -109,21 +110,29 @@ func Handler(w http.ResponseWriter, r *http.Request, c *config.Config, logger lo } } + if logLevelProber == nil { + logLevelProber = &promslog.AllowedLevel{} + } + if logLevelProber.String() == "" { + _ = logLevelProber.Set("info") + } sl := newScrapeLogger(logger, moduleName, target, logLevelProber) - level.Info(sl).Log("msg", "Beginning probe", "probe", module.Prober, "timeout_seconds", timeoutSeconds) + slLogger := slog.New(sl) + + slLogger.Info("Beginning probe", "probe", module.Prober, "timeout_seconds", timeoutSeconds) start := time.Now() registry := prometheus.NewRegistry() registry.MustRegister(probeSuccessGauge) registry.MustRegister(probeDurationGauge) - success := prober(ctx, target, module, registry, sl) + success := prober(ctx, target, module, registry, slLogger) duration := time.Since(start).Seconds() probeDurationGauge.Set(duration) if success { probeSuccessGauge.Set(1) - level.Info(sl).Log("msg", "Probe succeeded", "duration_seconds", duration) + slLogger.Info("Probe succeeded", "duration_seconds", duration) } else { - level.Error(sl).Log("msg", "Probe failed", "duration_seconds", duration) + slLogger.Error("Probe failed", "duration_seconds", duration) } debugOutput := DebugOutput(&module, &sl.buffer, registry) @@ -157,28 +166,84 @@ func setHTTPHost(hostname string, module *config.Module) error { } type scrapeLogger struct { - next log.Logger + next *slog.Logger buffer bytes.Buffer - bufferLogger log.Logger - logLevel level.Option + bufferLogger *slog.Logger + logLevel *promslog.AllowedLevel +} + +// Enabled returns true if both A) the scrapeLogger's internal `next` logger +// and B) the scrapeLogger's internal `bufferLogger` are enabled at the +// provided context/log level, and returns false otherwise. It implements +// slog.Handler. +func (sl *scrapeLogger) Enabled(ctx context.Context, level slog.Level) bool { + nextEnabled := sl.next.Enabled(ctx, level) + bufEnabled := sl.bufferLogger.Enabled(ctx, level) + + return nextEnabled && bufEnabled +} + +// Handle writes the provided log record to the internal logger, and then to +// the internal bufferLogger for use with serving debug output. It implements +// slog.Handler. +func (sl *scrapeLogger) Handle(ctx context.Context, r slog.Record) error { + var errs []error + + errs = append(errs, sl.next.Handler().Handle(ctx, r.Clone())) + + if sl.bufferLogger.Enabled(context.Background(), getSlogLevel(sl.logLevel.String())) { + errs = append(errs, sl.bufferLogger.Handler().Handle(ctx, r.Clone())) + } + + return errors.Join(errs...) +} + +// WithAttrs adds the provided attributes to the scrapeLogger's internal logger and +// bufferLogger. It implements slog.Handler. +func (sl *scrapeLogger) WithAttrs(attrs []slog.Attr) slog.Handler { + return &scrapeLogger{ + next: slog.New(sl.next.Handler().WithAttrs(attrs)), + buffer: sl.buffer, + bufferLogger: slog.New(sl.bufferLogger.Handler().WithAttrs(attrs)), + logLevel: sl.logLevel, + } } -func newScrapeLogger(logger log.Logger, module string, target string, logLevel level.Option) *scrapeLogger { - logger = log.With(logger, "module", module, "target", target) +// WithGroup adds the provided group name to the scrapeLogger's internal logger +// and bufferLogger. It implements slog.Handler. +func (sl *scrapeLogger) WithGroup(name string) slog.Handler { + return &scrapeLogger{ + next: slog.New(sl.next.Handler().WithGroup(name)), + buffer: sl.buffer, + bufferLogger: slog.New(sl.bufferLogger.Handler().WithGroup(name)), + logLevel: sl.logLevel, + } +} + +func newScrapeLogger(logger *slog.Logger, module string, target string, logLevel *promslog.AllowedLevel) *scrapeLogger { sl := &scrapeLogger{ - next: logger, + next: logger.With("module", module, "target", target), buffer: bytes.Buffer{}, logLevel: logLevel, } - bl := log.NewLogfmtLogger(&sl.buffer) - sl.bufferLogger = log.With(bl, "ts", log.DefaultTimestampUTC, "caller", log.Caller(6), "module", module, "target", target) + bl := promslog.New(&promslog.Config{Writer: &sl.buffer, Level: logLevel}) + sl.bufferLogger = bl.With("module", module, "target", target) return sl } -func (sl scrapeLogger) Log(keyvals ...interface{}) error { - sl.bufferLogger.Log(keyvals...) - - return level.NewFilter(sl.next, sl.logLevel).Log(keyvals...) +func getSlogLevel(level string) slog.Level { + switch level { + case "info": + return slog.LevelInfo + case "debug": + return slog.LevelDebug + case "error": + return slog.LevelError + case "warn": + return slog.LevelWarn + default: + return slog.LevelInfo + } } // DebugOutput returns plaintext debug output for a probe. diff --git a/prober/handler_test.go b/prober/handler_test.go index e9897ab3..c00c87bb 100644 --- a/prober/handler_test.go +++ b/prober/handler_test.go @@ -24,10 +24,9 @@ import ( "testing" "time" - "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" pconfig "github.com/prometheus/common/config" + "github.com/prometheus/common/promslog" "github.com/prometheus/blackbox_exporter/config" ) @@ -60,7 +59,7 @@ func TestPrometheusTimeoutHTTP(t *testing.T) { rr := httptest.NewRecorder() handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - Handler(w, r, c, log.NewNopLogger(), &ResultHistory{}, 0.5, nil, nil, level.AllowNone()) + Handler(w, r, c, promslog.NewNopLogger(), &ResultHistory{}, 0.5, nil, nil, &promslog.AllowedLevel{}) }) handler.ServeHTTP(rr, req) @@ -82,7 +81,7 @@ func TestPrometheusConfigSecretsHidden(t *testing.T) { } rr := httptest.NewRecorder() handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - Handler(w, r, c, log.NewNopLogger(), &ResultHistory{}, 0.5, nil, nil, level.AllowNone()) + Handler(w, r, c, promslog.NewNopLogger(), &ResultHistory{}, 0.5, nil, nil, &promslog.AllowedLevel{}) }) handler.ServeHTTP(rr, req) @@ -178,7 +177,7 @@ func TestHostnameParam(t *testing.T) { rr := httptest.NewRecorder() handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - Handler(w, r, c, log.NewNopLogger(), &ResultHistory{}, 0.5, nil, nil, level.AllowNone()) + Handler(w, r, c, promslog.NewNopLogger(), &ResultHistory{}, 0.5, nil, nil, &promslog.AllowedLevel{}) }) handler.ServeHTTP(rr, req) @@ -196,7 +195,7 @@ func TestHostnameParam(t *testing.T) { c.Modules["http_2xx"].HTTP.Headers["Host"] = hostname + ".something" handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - Handler(w, r, c, log.NewNopLogger(), &ResultHistory{}, 0.5, nil, nil, level.AllowNone()) + Handler(w, r, c, promslog.NewNopLogger(), &ResultHistory{}, 0.5, nil, nil, &promslog.AllowedLevel{}) }) rr = httptest.NewRecorder() @@ -243,7 +242,7 @@ func TestTCPHostnameParam(t *testing.T) { rr := httptest.NewRecorder() handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - Handler(w, r, c, log.NewNopLogger(), &ResultHistory{}, 0.5, nil, nil, level.AllowNone()) + Handler(w, r, c, promslog.NewNopLogger(), &ResultHistory{}, 0.5, nil, nil, &promslog.AllowedLevel{}) }) handler.ServeHTTP(rr, req) diff --git a/prober/http.go b/prober/http.go index d79e8e1c..5ffc029f 100644 --- a/prober/http.go +++ b/prober/http.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "io" + "log/slog" "net" "net/http" "net/http/cookiejar" @@ -34,8 +35,6 @@ import ( "time" "github.com/andybalholm/brotli" - "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" pconfig "github.com/prometheus/common/config" "github.com/prometheus/common/version" @@ -44,33 +43,33 @@ import ( "github.com/prometheus/blackbox_exporter/config" ) -func matchRegularExpressions(reader io.Reader, httpConfig config.HTTPProbe, logger log.Logger) bool { +func matchRegularExpressions(reader io.Reader, httpConfig config.HTTPProbe, logger *slog.Logger) bool { body, err := io.ReadAll(reader) if err != nil { - level.Error(logger).Log("msg", "Error reading HTTP body", "err", err) + logger.Error("Error reading HTTP body", "err", err) return false } for _, expression := range httpConfig.FailIfBodyMatchesRegexp { if expression.Regexp.Match(body) { - level.Error(logger).Log("msg", "Body matched regular expression", "regexp", expression) + logger.Error("Body matched regular expression", "regexp", expression) return false } } for _, expression := range httpConfig.FailIfBodyNotMatchesRegexp { if !expression.Regexp.Match(body) { - level.Error(logger).Log("msg", "Body did not match regular expression", "regexp", expression) + logger.Error("Body did not match regular expression", "regexp", expression) return false } } return true } -func matchRegularExpressionsOnHeaders(header http.Header, httpConfig config.HTTPProbe, logger log.Logger) bool { +func matchRegularExpressionsOnHeaders(header http.Header, httpConfig config.HTTPProbe, logger *slog.Logger) bool { for _, headerMatchSpec := range httpConfig.FailIfHeaderMatchesRegexp { values := header[textproto.CanonicalMIMEHeaderKey(headerMatchSpec.Header)] if len(values) == 0 { if !headerMatchSpec.AllowMissing { - level.Error(logger).Log("msg", "Missing required header", "header", headerMatchSpec.Header) + logger.Error("Missing required header", "header", headerMatchSpec.Header) return false } else { continue // No need to match any regex on missing headers. @@ -79,7 +78,7 @@ func matchRegularExpressionsOnHeaders(header http.Header, httpConfig config.HTTP for _, val := range values { if headerMatchSpec.Regexp.MatchString(val) { - level.Error(logger).Log("msg", "Header matched regular expression", "header", headerMatchSpec.Header, + logger.Error("Header matched regular expression", "header", headerMatchSpec.Header, "regexp", headerMatchSpec.Regexp, "value_count", len(values)) return false } @@ -89,7 +88,7 @@ func matchRegularExpressionsOnHeaders(header http.Header, httpConfig config.HTTP values := header[textproto.CanonicalMIMEHeaderKey(headerMatchSpec.Header)] if len(values) == 0 { if !headerMatchSpec.AllowMissing { - level.Error(logger).Log("msg", "Missing required header", "header", headerMatchSpec.Header) + logger.Error("Missing required header", "header", headerMatchSpec.Header) return false } else { continue // No need to match any regex on missing headers. @@ -106,7 +105,7 @@ func matchRegularExpressionsOnHeaders(header http.Header, httpConfig config.HTTP } if !anyHeaderValueMatched { - level.Error(logger).Log("msg", "Header did not match regular expression", "header", headerMatchSpec.Header, + logger.Error("Header did not match regular expression", "header", headerMatchSpec.Header, "regexp", headerMatchSpec.Regexp, "value_count", len(values)) return false } @@ -133,14 +132,14 @@ type transport struct { Transport http.RoundTripper NoServerNameTransport http.RoundTripper firstHost string - logger log.Logger + logger *slog.Logger mu sync.Mutex traces []*roundTripTrace current *roundTripTrace } -func newTransport(rt, noServerName http.RoundTripper, logger log.Logger) *transport { +func newTransport(rt, noServerName http.RoundTripper, logger *slog.Logger) *transport { return &transport{ Transport: rt, NoServerNameTransport: noServerName, @@ -151,7 +150,7 @@ func newTransport(rt, noServerName http.RoundTripper, logger log.Logger) *transp // RoundTrip switches to a new trace, then runs embedded RoundTripper. func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) { - level.Info(t.logger).Log("msg", "Making HTTP request", "url", req.URL.String(), "host", req.Host) + t.logger.Info("Making HTTP request", "url", req.URL.String(), "host", req.Host) trace := &roundTripTrace{} if req.URL.Scheme == "https" { @@ -167,7 +166,7 @@ func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) { if t.firstHost != req.URL.Host { // This is a redirect to something other than the initial host, // so TLS ServerName should not be set. - level.Info(t.logger).Log("msg", "Address does not match first address, not sending TLS ServerName", "first", t.firstHost, "address", req.URL.Host) + t.logger.Info("Address does not match first address, not sending TLS ServerName", "first", t.firstHost, "address", req.URL.Host) return t.NoServerNameTransport.RoundTrip(req) } @@ -235,7 +234,7 @@ func (bc *byteCounter) Read(p []byte) (int, error) { var userAgentDefaultHeader = fmt.Sprintf("Blackbox Exporter/%s", version.Version) -func ProbeHTTP(ctx context.Context, target string, module config.Module, registry *prometheus.Registry, logger log.Logger) (success bool) { +func ProbeHTTP(ctx context.Context, target string, module config.Module, registry *prometheus.Registry, logger *slog.Logger) (success bool) { var redirects int var ( durationGaugeVec = prometheus.NewGaugeVec(prometheus.GaugeOpts{ @@ -320,7 +319,7 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr targetURL, err := url.Parse(target) if err != nil { - level.Error(logger).Log("msg", "Could not parse target URL", "err", err) + logger.Error("Could not parse target URL", "err", err) return false } @@ -333,7 +332,7 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr ip, lookupTime, err = chooseProtocol(ctx, module.HTTP.IPProtocol, module.HTTP.IPProtocolFallback, targetHost, registry, logger) durationGaugeVec.WithLabelValues("resolve").Add(lookupTime) if err != nil { - level.Error(logger).Log("msg", "Error resolving address", "err", err) + logger.Error("Error resolving address", "err", err) return false } } @@ -355,20 +354,20 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr } client, err := pconfig.NewClientFromConfig(httpClientConfig, "http_probe", pconfig.WithKeepAlivesDisabled()) if err != nil { - level.Error(logger).Log("msg", "Error generating HTTP client", "err", err) + logger.Error("Error generating HTTP client", "err", err) return false } httpClientConfig.TLSConfig.ServerName = "" noServerName, err := pconfig.NewRoundTripperFromConfig(httpClientConfig, "http_probe", pconfig.WithKeepAlivesDisabled()) if err != nil { - level.Error(logger).Log("msg", "Error generating HTTP client without ServerName", "err", err) + logger.Error("Error generating HTTP client without ServerName", "err", err) return false } jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List}) if err != nil { - level.Error(logger).Log("msg", "Error generating cookiejar", "err", err) + logger.Error("Error generating cookiejar", "err", err) return false } client.Jar = jar @@ -379,10 +378,10 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr client.Transport = tt client.CheckRedirect = func(r *http.Request, via []*http.Request) error { - level.Info(logger).Log("msg", "Received redirect", "location", r.Response.Header.Get("Location")) + logger.Info("Received redirect", "location", r.Response.Header.Get("Location")) redirects = len(via) if redirects > 10 || !httpConfig.HTTPClientConfig.FollowRedirects { - level.Info(logger).Log("msg", "Not following redirect") + logger.Info("Not following redirect") return errors.New("don't follow redirects") } return nil @@ -418,7 +417,7 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr if httpConfig.BodyFile != "" { body_file, err := os.Open(httpConfig.BodyFile) if err != nil { - level.Error(logger).Log("msg", "Error creating request", "err", err) + logger.Error("Error creating request", "err", err) return } defer body_file.Close() @@ -427,7 +426,7 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr request, err := http.NewRequest(httpConfig.Method, targetURL.String(), body) if err != nil { - level.Error(logger).Log("msg", "Error creating request", "err", err) + logger.Error("Error creating request", "err", err) return } request.Host = origHost @@ -472,12 +471,12 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr if resp == nil { resp = &http.Response{} if err != nil { - level.Error(logger).Log("msg", "Error for HTTP request", "err", err) + logger.Error("Error for HTTP request", "err", err) } } else { requestErrored := (err != nil) - level.Info(logger).Log("msg", "Received HTTP response", "status_code", resp.StatusCode) + logger.Info("Received HTTP response", "status_code", resp.StatusCode) if len(httpConfig.ValidStatusCodes) != 0 { for _, code := range httpConfig.ValidStatusCodes { if resp.StatusCode == code { @@ -486,13 +485,13 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr } } if !success { - level.Info(logger).Log("msg", "Invalid HTTP response status code", "status_code", resp.StatusCode, + logger.Info("Invalid HTTP response status code", "status_code", resp.StatusCode, "valid_status_codes", fmt.Sprintf("%v", httpConfig.ValidStatusCodes)) } } else if 200 <= resp.StatusCode && resp.StatusCode < 300 { success = true } else { - level.Info(logger).Log("msg", "Invalid HTTP response status code, wanted 2xx", "status_code", resp.StatusCode) + logger.Info("Invalid HTTP response status code, wanted 2xx", "status_code", resp.StatusCode) } if success && (len(httpConfig.FailIfHeaderMatchesRegexp) > 0 || len(httpConfig.FailIfHeaderNotMatchesRegexp) > 0) { @@ -510,7 +509,7 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr if httpConfig.Compression != "" { dec, err := getDecompressionReader(httpConfig.Compression, resp.Body) if err != nil { - level.Info(logger).Log("msg", "Failed to get decompressor for HTTP response body", "err", err) + logger.Info("Failed to get decompressor for HTTP response body", "err", err) success = false } else if dec != nil { // Since we are replacing the original resp.Body with the decoder, we need to make sure @@ -521,7 +520,7 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr if err != nil { // At this point we cannot really do anything with this error, but log // it in case it contains useful information as to what's the problem. - level.Info(logger).Log("msg", "Error while closing response from server", "err", err) + logger.Info("Error while closing response from server", "err", err) } }(resp.Body) @@ -551,7 +550,7 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr if !requestErrored { _, err = io.Copy(io.Discard, byteCounter) if err != nil { - level.Info(logger).Log("msg", "Failed to read HTTP response body", "err", err) + logger.Info("Failed to read HTTP response body", "err", err) success = false } @@ -561,7 +560,7 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr // We have already read everything we could from the server, maybe even uncompressed the // body. The error here might be either a decompression error or a TCP error. Log it in // case it contains useful information as to what's the problem. - level.Info(logger).Log("msg", "Error while closing response from server", "error", err.Error()) + logger.Info("Error while closing response from server", "error", err.Error()) } } @@ -577,7 +576,7 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr var httpVersionNumber float64 httpVersionNumber, err = strconv.ParseFloat(strings.TrimPrefix(resp.Proto, "HTTP/"), 64) if err != nil { - level.Error(logger).Log("msg", "Error parsing version number from HTTP version", "err", err) + logger.Error("Error parsing version number from HTTP version", "err", err) } probeHTTPVersionGauge.Set(httpVersionNumber) @@ -590,7 +589,7 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr } } if !found { - level.Error(logger).Log("msg", "Invalid HTTP version number", "version", resp.Proto) + logger.Error("Invalid HTTP version number", "version", resp.Proto) success = false } } @@ -599,8 +598,8 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr tt.mu.Lock() defer tt.mu.Unlock() for i, trace := range tt.traces { - level.Info(logger).Log( - "msg", "Response timings for roundtrip", + logger.Info( + "Response timings for roundtrip", "roundtrip", i, "start", trace.start, "dnsDone", trace.dnsDone, @@ -650,11 +649,11 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr probeSSLLastChainExpiryTimestampSeconds.Set(float64(getLastChainExpiry(resp.TLS).Unix())) probeSSLLastInformation.WithLabelValues(getFingerprint(resp.TLS), getSubject(resp.TLS), getIssuer(resp.TLS), getDNSNames(resp.TLS)).Set(1) if httpConfig.FailIfSSL { - level.Error(logger).Log("msg", "Final request was over SSL") + logger.Error("Final request was over SSL") success = false } } else if httpConfig.FailIfNotSSL && success { - level.Error(logger).Log("msg", "Final request was not over SSL") + logger.Error("Final request was not over SSL") success = false } diff --git a/prober/http_test.go b/prober/http_test.go index da700eb8..0f14816b 100644 --- a/prober/http_test.go +++ b/prober/http_test.go @@ -23,6 +23,7 @@ import ( "encoding/pem" "fmt" "io" + "log/slog" "net" "net/http" "net/http/httptest" @@ -35,9 +36,9 @@ import ( "time" "github.com/andybalholm/brotli" - "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" pconfig "github.com/prometheus/common/config" + "github.com/prometheus/common/promslog" "github.com/prometheus/blackbox_exporter/config" ) @@ -69,7 +70,7 @@ func TestHTTPStatusCodes(t *testing.T) { testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() result := ProbeHTTP(testCTX, ts.URL, - config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, ValidStatusCodes: test.ValidStatusCodes}}, registry, log.NewNopLogger()) + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, ValidStatusCodes: test.ValidStatusCodes}}, registry, promslog.NewNopLogger()) body := recorder.Body.String() if result != test.ShouldSucceed { t.Fatalf("Test %d had unexpected result: %s", i, body) @@ -97,7 +98,7 @@ func TestValidHTTPVersion(t *testing.T) { config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{ IPProtocolFallback: true, ValidHTTPVersions: test.ValidHTTPVersions, - }}, registry, log.NewNopLogger()) + }}, registry, promslog.NewNopLogger()) body := recorder.Body.String() if result != test.ShouldSucceed { t.Fatalf("Test %v had unexpected result: %s", i, body) @@ -241,7 +242,7 @@ func TestContentLength(t *testing.T) { HTTP: config.HTTPProbe{IPProtocolFallback: true}, }, registry, - log.NewLogfmtLogger(&logbuf)) + promslog.New(&promslog.Config{Writer: &logbuf})) if !tc.expectFailure && !result { t.Fatalf("probe failed unexpectedly: %s", logbuf.String()) } else if tc.expectFailure && result { @@ -495,7 +496,7 @@ func TestHandlingOfCompressionSetting(t *testing.T) { HTTP: tc.httpConfig, }, registry, - log.NewLogfmtLogger(&logbuf)) + promslog.New(&promslog.Config{Writer: &logbuf})) if !tc.expectFailure && !result { t.Fatalf("probe failed unexpectedly: %s", logbuf.String()) } else if tc.expectFailure && result { @@ -616,7 +617,7 @@ func TestMaxResponseLength(t *testing.T) { }, }, registry, - log.NewNopLogger(), + promslog.NewNopLogger(), ) switch { @@ -649,7 +650,7 @@ func TestRedirectFollowed(t *testing.T) { registry := prometheus.NewRegistry() testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - result := ProbeHTTP(testCTX, ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, HTTPClientConfig: pconfig.DefaultHTTPClientConfig}}, registry, log.NewNopLogger()) + result := ProbeHTTP(testCTX, ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, HTTPClientConfig: pconfig.DefaultHTTPClientConfig}}, registry, promslog.NewNopLogger()) body := recorder.Body.String() if !result { t.Fatalf("Redirect test failed unexpectedly, got %s", body) @@ -677,7 +678,7 @@ func TestRedirectNotFollowed(t *testing.T) { testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() result := ProbeHTTP(testCTX, ts.URL, - config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, HTTPClientConfig: pconfig.HTTPClientConfig{FollowRedirects: false}, ValidStatusCodes: []int{302}}}, registry, log.NewNopLogger()) + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, HTTPClientConfig: pconfig.HTTPClientConfig{FollowRedirects: false}, ValidStatusCodes: []int{302}}}, registry, promslog.NewNopLogger()) body := recorder.Body.String() if !result { t.Fatalf("Redirect test failed unexpectedly, got %s", body) @@ -726,7 +727,7 @@ func TestRedirectionLimit(t *testing.T) { ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, HTTPClientConfig: pconfig.DefaultHTTPClientConfig}}, registry, - log.NewNopLogger()) + promslog.NewNopLogger()) if result { t.Fatalf("Probe succeeded unexpectedly") } @@ -760,7 +761,7 @@ func TestPost(t *testing.T) { testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() result := ProbeHTTP(testCTX, ts.URL, - config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, Method: "POST"}}, registry, log.NewNopLogger()) + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, Method: "POST"}}, registry, promslog.NewNopLogger()) body := recorder.Body.String() if !result { t.Fatalf("Post test failed unexpectedly, got %s", body) @@ -783,7 +784,7 @@ func TestBasicAuth(t *testing.T) { TLSConfig: pconfig.TLSConfig{InsecureSkipVerify: false}, BasicAuth: &pconfig.BasicAuth{Username: "username", Password: "password"}, }, - }}, registry, log.NewNopLogger()) + }}, registry, promslog.NewNopLogger()) body := recorder.Body.String() if !result { t.Fatalf("HTTP probe failed, got %s", body) @@ -805,7 +806,7 @@ func TestBearerToken(t *testing.T) { HTTPClientConfig: pconfig.HTTPClientConfig{ BearerToken: pconfig.Secret("mysecret"), }, - }}, registry, log.NewNopLogger()) + }}, registry, promslog.NewNopLogger()) body := recorder.Body.String() if !result { t.Fatalf("HTTP probe failed, got %s", body) @@ -822,7 +823,7 @@ func TestFailIfNotSSL(t *testing.T) { testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() result := ProbeHTTP(testCTX, ts.URL, - config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfNotSSL: true}}, registry, log.NewNopLogger()) + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfNotSSL: true}}, registry, promslog.NewNopLogger()) body := recorder.Body.String() if result { t.Fatalf("Fail if not SSL test succeeded unexpectedly, got %s", body) @@ -839,23 +840,32 @@ func TestFailIfNotSSL(t *testing.T) { type logRecorder struct { msgs map[string]bool + next *slog.Logger } -func (r *logRecorder) Log(keyvals ...interface{}) error { - if r.msgs == nil { - r.msgs = make(map[string]bool) - } - for i := 0; i < len(keyvals)-1; i += 2 { - if keyvals[i] == "msg" { - msg, ok := keyvals[i+1].(string) - if ok { - r.msgs[msg] = true - } - } +func (lr *logRecorder) Enabled(ctx context.Context, level slog.Level) bool { + return lr.next.Enabled(ctx, level) +} + +func (lr *logRecorder) Handle(ctx context.Context, r slog.Record) error { + if lr.msgs == nil { + lr.msgs = make(map[string]bool) } + + lr.msgs[r.Message] = true return nil } +func (lr *logRecorder) WithAttrs(attrs []slog.Attr) slog.Handler { + lr.next = slog.New(lr.next.Handler().WithAttrs(attrs)) + return lr +} + +func (lr *logRecorder) WithGroup(name string) slog.Handler { + lr.next = slog.New(lr.next.Handler().WithGroup(name)) + return lr +} + func TestFailIfNotSSLLogMsg(t *testing.T) { const ( Msg = "Final request was not over SSL" @@ -910,12 +920,12 @@ func TestFailIfNotSSLLogMsg(t *testing.T) { }, } { t.Run(title, func(t *testing.T) { - recorder := logRecorder{} + recorder := logRecorder{next: promslog.NewNopLogger()} registry := prometheus.NewRegistry() testCTX, cancel := context.WithTimeout(context.Background(), Timeout) defer cancel() - result := ProbeHTTP(testCTX, tc.URL, tc.Config, registry, &recorder) + result := ProbeHTTP(testCTX, tc.URL, tc.Config, registry, slog.New(&recorder)) if result != tc.Success { t.Fatalf("Expected success=%v, got=%v", tc.Success, result) } @@ -968,7 +978,7 @@ func TestFailIfBodyMatchesRegexp(t *testing.T) { registry := prometheus.NewRegistry() testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - result := ProbeHTTP(testCTX, ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfBodyMatchesRegexp: testcase.regexps}}, registry, log.NewNopLogger()) + result := ProbeHTTP(testCTX, ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfBodyMatchesRegexp: testcase.regexps}}, registry, promslog.NewNopLogger()) if testcase.expectedResult && !result { t.Fatalf("Regexp test failed unexpectedly, got %s", recorder.Body.String()) } else if !testcase.expectedResult && result { @@ -1005,7 +1015,7 @@ func TestFailIfBodyNotMatchesRegexp(t *testing.T) { testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() result := ProbeHTTP(testCTX, ts.URL, - config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfBodyNotMatchesRegexp: []config.Regexp{config.MustNewRegexp("Download the latest version here")}}}, registry, log.NewNopLogger()) + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfBodyNotMatchesRegexp: []config.Regexp{config.MustNewRegexp("Download the latest version here")}}}, registry, promslog.NewNopLogger()) body := recorder.Body.String() if result { t.Fatalf("Regexp test succeeded unexpectedly, got %s", body) @@ -1019,7 +1029,7 @@ func TestFailIfBodyNotMatchesRegexp(t *testing.T) { recorder = httptest.NewRecorder() registry = prometheus.NewRegistry() result = ProbeHTTP(testCTX, ts.URL, - config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfBodyNotMatchesRegexp: []config.Regexp{config.MustNewRegexp("Download the latest version here")}}}, registry, log.NewNopLogger()) + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfBodyNotMatchesRegexp: []config.Regexp{config.MustNewRegexp("Download the latest version here")}}}, registry, promslog.NewNopLogger()) body = recorder.Body.String() if !result { t.Fatalf("Regexp test failed unexpectedly, got %s", body) @@ -1035,7 +1045,7 @@ func TestFailIfBodyNotMatchesRegexp(t *testing.T) { recorder = httptest.NewRecorder() registry = prometheus.NewRegistry() result = ProbeHTTP(testCTX, ts.URL, - config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfBodyNotMatchesRegexp: []config.Regexp{config.MustNewRegexp("Download the latest version here"), config.MustNewRegexp("Copyright 2015")}}}, registry, log.NewNopLogger()) + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfBodyNotMatchesRegexp: []config.Regexp{config.MustNewRegexp("Download the latest version here"), config.MustNewRegexp("Copyright 2015")}}}, registry, promslog.NewNopLogger()) body = recorder.Body.String() if result { t.Fatalf("Regexp test succeeded unexpectedly, got %s", body) @@ -1049,7 +1059,7 @@ func TestFailIfBodyNotMatchesRegexp(t *testing.T) { recorder = httptest.NewRecorder() registry = prometheus.NewRegistry() result = ProbeHTTP(testCTX, ts.URL, - config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfBodyNotMatchesRegexp: []config.Regexp{config.MustNewRegexp("Download the latest version here"), config.MustNewRegexp("Copyright 2015")}}}, registry, log.NewNopLogger()) + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfBodyNotMatchesRegexp: []config.Regexp{config.MustNewRegexp("Download the latest version here"), config.MustNewRegexp("Copyright 2015")}}}, registry, promslog.NewNopLogger()) body = recorder.Body.String() if !result { t.Fatalf("Regexp test failed unexpectedly, got %s", body) @@ -1084,7 +1094,7 @@ func TestFailIfHeaderMatchesRegexp(t *testing.T) { testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - result := ProbeHTTP(testCTX, ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfHeaderMatchesRegexp: []config.HeaderMatch{test.Rule}}}, registry, log.NewNopLogger()) + result := ProbeHTTP(testCTX, ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfHeaderMatchesRegexp: []config.HeaderMatch{test.Rule}}}, registry, promslog.NewNopLogger()) if result != test.ShouldSucceed { t.Fatalf("Test %d had unexpected result: succeeded: %t, expected: %+v", i, result, test) } @@ -1132,7 +1142,7 @@ func TestFailIfHeaderNotMatchesRegexp(t *testing.T) { testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - result := ProbeHTTP(testCTX, ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfHeaderNotMatchesRegexp: []config.HeaderMatch{test.Rule}}}, registry, log.NewNopLogger()) + result := ProbeHTTP(testCTX, ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfHeaderNotMatchesRegexp: []config.HeaderMatch{test.Rule}}}, registry, promslog.NewNopLogger()) if result != test.ShouldSucceed { t.Fatalf("Test %d had unexpected result: succeeded: %t, expected: %+v", i, result, test) } @@ -1180,7 +1190,7 @@ func TestHTTPHeaders(t *testing.T) { result := ProbeHTTP(testCTX, ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{ IPProtocolFallback: true, Headers: headers, - }}, registry, log.NewNopLogger()) + }}, registry, promslog.NewNopLogger()) if !result { t.Fatalf("Probe failed unexpectedly.") } @@ -1201,7 +1211,7 @@ func TestFailIfSelfSignedCA(t *testing.T) { HTTPClientConfig: pconfig.HTTPClientConfig{ TLSConfig: pconfig.TLSConfig{InsecureSkipVerify: false}, }, - }}, registry, log.NewNopLogger()) + }}, registry, promslog.NewNopLogger()) body := recorder.Body.String() if result { t.Fatalf("Fail if selfsigned CA test succeeded unexpectedly, got %s", body) @@ -1231,7 +1241,7 @@ func TestSucceedIfSelfSignedCA(t *testing.T) { HTTPClientConfig: pconfig.HTTPClientConfig{ TLSConfig: pconfig.TLSConfig{InsecureSkipVerify: true}, }, - }}, registry, log.NewNopLogger()) + }}, registry, promslog.NewNopLogger()) body := recorder.Body.String() if !result { t.Fatalf("Fail if (not strict) selfsigned CA test fails unexpectedly, got %s", body) @@ -1261,7 +1271,7 @@ func TestTLSConfigIsIgnoredForPlainHTTP(t *testing.T) { HTTPClientConfig: pconfig.HTTPClientConfig{ TLSConfig: pconfig.TLSConfig{InsecureSkipVerify: false}, }, - }}, registry, log.NewNopLogger()) + }}, registry, promslog.NewNopLogger()) body := recorder.Body.String() if !result { t.Fatalf("Fail if InsecureSkipVerify affects simple http fails unexpectedly, got %s", body) @@ -1328,7 +1338,7 @@ func TestHTTPUsesTargetAsTLSServerName(t *testing.T) { url := strings.Replace(ts.URL, "127.0.0.1", "localhost", -1) url = strings.Replace(url, "[::1]", "localhost", -1) - result := ProbeHTTP(context.Background(), url, module, registry, log.NewNopLogger()) + result := ProbeHTTP(context.Background(), url, module, registry, promslog.NewNopLogger()) if !result { t.Fatalf("TLS probe failed unexpectedly") } @@ -1348,7 +1358,7 @@ func TestRedirectToTLSHostWorks(t *testing.T) { testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() result := ProbeHTTP(testCTX, ts.URL, - config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, HTTPClientConfig: pconfig.DefaultHTTPClientConfig}}, registry, log.NewNopLogger()) + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, HTTPClientConfig: pconfig.DefaultHTTPClientConfig}}, registry, promslog.NewNopLogger()) if !result { t.Fatalf("Redirect test failed unexpectedly") } @@ -1371,7 +1381,7 @@ func TestHTTPPhases(t *testing.T) { HTTPClientConfig: pconfig.HTTPClientConfig{ TLSConfig: pconfig.TLSConfig{InsecureSkipVerify: true}, }, - }}, registry, log.NewNopLogger()) + }}, registry, promslog.NewNopLogger()) body := recorder.Body.String() if !result { t.Fatalf("HTTP Phases test failed unexpectedly, got %s", body) @@ -1421,7 +1431,7 @@ func TestCookieJar(t *testing.T) { registry := prometheus.NewRegistry() testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - result := ProbeHTTP(testCTX, ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, HTTPClientConfig: pconfig.DefaultHTTPClientConfig}}, registry, log.NewNopLogger()) + result := ProbeHTTP(testCTX, ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, HTTPClientConfig: pconfig.DefaultHTTPClientConfig}}, registry, promslog.NewNopLogger()) body := recorder.Body.String() if !result { t.Fatalf("Redirect test failed unexpectedly, got %s", body) @@ -1442,7 +1452,7 @@ func TestSkipResolvePhase(t *testing.T) { testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() result := ProbeHTTP(testCTX, ts.URL, - config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, HTTPClientConfig: pconfig.DefaultHTTPClientConfig, SkipResolvePhaseWithProxy: true}}, registry, log.NewNopLogger()) + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, HTTPClientConfig: pconfig.DefaultHTTPClientConfig, SkipResolvePhaseWithProxy: true}}, registry, promslog.NewNopLogger()) if !result { t.Fatalf("Probe unsuccessful") } @@ -1477,7 +1487,7 @@ func TestSkipResolvePhase(t *testing.T) { URL: u, } ProbeHTTP(testCTX, ts.URL, - config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, HTTPClientConfig: httpCfg, SkipResolvePhaseWithProxy: true}}, registry, log.NewNopLogger()) + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, HTTPClientConfig: httpCfg, SkipResolvePhaseWithProxy: true}}, registry, promslog.NewNopLogger()) mfs, err := registry.Gather() if err != nil { t.Fatal(err) @@ -1537,7 +1547,7 @@ func TestBody(t *testing.T) { Timeout: time.Second, HTTP: test}, registry, - log.NewNopLogger(), + promslog.NewNopLogger(), ) if !result { t.Fatalf("Body test %d failed unexpectedly.", i) diff --git a/prober/icmp.go b/prober/icmp.go index f7807528..883fbcf7 100644 --- a/prober/icmp.go +++ b/prober/icmp.go @@ -16,6 +16,7 @@ package prober import ( "bytes" "context" + "log/slog" "math/rand" "net" "os" @@ -23,8 +24,6 @@ import ( "sync" "time" - "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" "golang.org/x/net/icmp" "golang.org/x/net/ipv4" @@ -63,7 +62,7 @@ func getICMPSequence() uint16 { return icmpSequence } -func ProbeICMP(ctx context.Context, target string, module config.Module, registry *prometheus.Registry, logger log.Logger) (success bool) { +func ProbeICMP(ctx context.Context, target string, module config.Module, registry *prometheus.Registry, logger *slog.Logger) (success bool) { var ( requestType icmp.Type replyType icmp.Type @@ -91,7 +90,7 @@ func ProbeICMP(ctx context.Context, target string, module config.Module, registr dstIPAddr, lookupTime, err := chooseProtocol(ctx, module.ICMP.IPProtocol, module.ICMP.IPProtocolFallback, target, registry, logger) if err != nil { - level.Error(logger).Log("msg", "Error resolving address", "err", err) + logger.Error("Error resolving address", "err", err) return false } durationGaugeVec.WithLabelValues("resolve").Add(lookupTime) @@ -99,14 +98,14 @@ func ProbeICMP(ctx context.Context, target string, module config.Module, registr var srcIP net.IP if len(module.ICMP.SourceIPAddress) > 0 { if srcIP = net.ParseIP(module.ICMP.SourceIPAddress); srcIP == nil { - level.Error(logger).Log("msg", "Error parsing source ip address", "srcIP", module.ICMP.SourceIPAddress) + logger.Error("Error parsing source ip address", "srcIP", module.ICMP.SourceIPAddress) return false } - level.Info(logger).Log("msg", "Using source address", "srcIP", srcIP) + logger.Info("Using source address", "srcIP", srcIP) } setupStart := time.Now() - level.Info(logger).Log("msg", "Creating socket") + logger.Info("Creating socket") privileged := true // Unprivileged sockets are supported on Darwin and Linux only. @@ -124,7 +123,7 @@ func ProbeICMP(ctx context.Context, target string, module config.Module, registr // "udp" here means unprivileged -- not the protocol "udp". icmpConn, err = icmp.ListenPacket("udp6", srcIP.String()) if err != nil { - level.Debug(logger).Log("msg", "Unable to do unprivileged listen on socket, will attempt privileged", "err", err) + logger.Debug("Unable to do unprivileged listen on socket, will attempt privileged", "err", err) } else { privileged = false } @@ -133,14 +132,14 @@ func ProbeICMP(ctx context.Context, target string, module config.Module, registr if privileged { icmpConn, err = icmp.ListenPacket("ip6:ipv6-icmp", srcIP.String()) if err != nil { - level.Error(logger).Log("msg", "Error listening to socket", "err", err) + logger.Error("Error listening to socket", "err", err) return } } defer icmpConn.Close() if err := icmpConn.IPv6PacketConn().SetControlMessage(ipv6.FlagHopLimit, true); err != nil { - level.Debug(logger).Log("msg", "Failed to set Control Message for retrieving Hop Limit", "err", err) + logger.Debug("Failed to set Control Message for retrieving Hop Limit", "err", err) hopLimitFlagSet = false } } else { @@ -156,27 +155,27 @@ func ProbeICMP(ctx context.Context, target string, module config.Module, registr // sockets as it is not possible to set IP header level options. netConn, err := net.ListenPacket("ip4:icmp", srcIP.String()) if err != nil { - level.Error(logger).Log("msg", "Error listening to socket", "err", err) + logger.Error("Error listening to socket", "err", err) return } defer netConn.Close() v4RawConn, err = ipv4.NewRawConn(netConn) if err != nil { - level.Error(logger).Log("msg", "Error creating raw connection", "err", err) + logger.Error("Error creating raw connection", "err", err) return } defer v4RawConn.Close() if err := v4RawConn.SetControlMessage(ipv4.FlagTTL, true); err != nil { - level.Debug(logger).Log("msg", "Failed to set Control Message for retrieving TTL", "err", err) + logger.Debug("Failed to set Control Message for retrieving TTL", "err", err) hopLimitFlagSet = false } } else { if tryUnprivileged { icmpConn, err = icmp.ListenPacket("udp4", srcIP.String()) if err != nil { - level.Debug(logger).Log("msg", "Unable to do unprivileged listen on socket, will attempt privileged", "err", err) + logger.Debug("Unable to do unprivileged listen on socket, will attempt privileged", "err", err) } else { privileged = false } @@ -185,14 +184,14 @@ func ProbeICMP(ctx context.Context, target string, module config.Module, registr if privileged { icmpConn, err = icmp.ListenPacket("ip4:icmp", srcIP.String()) if err != nil { - level.Error(logger).Log("msg", "Error listening to socket", "err", err) + logger.Error("Error listening to socket", "err", err) return } } defer icmpConn.Close() if err := icmpConn.IPv4PacketConn().SetControlMessage(ipv4.FlagTTL, true); err != nil { - level.Debug(logger).Log("msg", "Failed to set Control Message for retrieving TTL", "err", err) + logger.Debug("Failed to set Control Message for retrieving TTL", "err", err) hopLimitFlagSet = false } } @@ -216,7 +215,7 @@ func ProbeICMP(ctx context.Context, target string, module config.Module, registr Seq: int(getICMPSequence()), Data: data, } - level.Info(logger).Log("msg", "Creating ICMP packet", "seq", body.Seq, "id", body.ID) + logger.Info("Creating ICMP packet", "seq", body.Seq, "id", body.ID) wm := icmp.Message{ Type: requestType, Code: 0, @@ -225,23 +224,23 @@ func ProbeICMP(ctx context.Context, target string, module config.Module, registr wb, err := wm.Marshal(nil) if err != nil { - level.Error(logger).Log("msg", "Error marshalling packet", "err", err) + logger.Error("Error marshalling packet", "err", err) return } durationGaugeVec.WithLabelValues("setup").Add(time.Since(setupStart).Seconds()) - level.Info(logger).Log("msg", "Writing out packet") + logger.Info("Writing out packet") rttStart := time.Now() if icmpConn != nil { ttl := module.ICMP.TTL if ttl > 0 { if c4 := icmpConn.IPv4PacketConn(); c4 != nil { - level.Debug(logger).Log("msg", "Setting TTL (IPv4 unprivileged)", "ttl", ttl) + logger.Debug("Setting TTL (IPv4 unprivileged)", "ttl", ttl) c4.SetTTL(ttl) } if c6 := icmpConn.IPv6PacketConn(); c6 != nil { - level.Debug(logger).Log("msg", "Setting TTL (IPv6 unprivileged)", "ttl", ttl) + logger.Debug("Setting TTL (IPv6 unprivileged)", "ttl", ttl) c6.SetHopLimit(ttl) } } @@ -249,7 +248,7 @@ func ProbeICMP(ctx context.Context, target string, module config.Module, registr } else { ttl := config.DefaultICMPTTL if module.ICMP.TTL > 0 { - level.Debug(logger).Log("msg", "Overriding TTL (raw IPv4)", "ttl", ttl) + logger.Debug("Overriding TTL (raw IPv4)", "ttl", ttl) ttl = module.ICMP.TTL } // Only for IPv4 raw. Needed for setting DontFragment flag. @@ -268,7 +267,7 @@ func ProbeICMP(ctx context.Context, target string, module config.Module, registr err = v4RawConn.WriteTo(header, wb, nil) } if err != nil { - level.Warn(logger).Log("msg", "Error writing to socket", "err", err) + logger.Warn("Error writing to socket", "err", err) return } @@ -282,7 +281,7 @@ func ProbeICMP(ctx context.Context, target string, module config.Module, registr } wb, err = wm.Marshal(nil) if err != nil { - level.Error(logger).Log("msg", "Error marshalling packet", "err", err) + logger.Error("Error marshalling packet", "err", err) return } @@ -301,10 +300,10 @@ func ProbeICMP(ctx context.Context, target string, module config.Module, registr err = v4RawConn.SetReadDeadline(deadline) } if err != nil { - level.Error(logger).Log("msg", "Error setting socket deadline", "err", err) + logger.Error("Error setting socket deadline", "err", err) return } - level.Info(logger).Log("msg", "Waiting for reply packets") + logger.Info("Waiting for reply packets") for { var n int var peer net.Addr @@ -318,7 +317,7 @@ func ProbeICMP(ctx context.Context, target string, module config.Module, registr if cm != nil && hopLimitFlagSet { hopLimit = float64(cm.HopLimit) } else { - level.Debug(logger).Log("msg", "Cannot get Hop Limit from the received packet. 'probe_icmp_reply_hop_limit' will be missing.") + logger.Debug("Cannot get Hop Limit from the received packet. 'probe_icmp_reply_hop_limit' will be missing.") } } else { var cm *ipv4.ControlMessage @@ -338,15 +337,15 @@ func ProbeICMP(ctx context.Context, target string, module config.Module, registr // Not really Hop Limit, but it is in practice. hopLimit = float64(cm.TTL) } else { - level.Debug(logger).Log("msg", "Cannot get TTL from the received packet. 'probe_icmp_reply_hop_limit' will be missing.") + logger.Debug("Cannot get TTL from the received packet. 'probe_icmp_reply_hop_limit' will be missing.") } } if err != nil { if nerr, ok := err.(net.Error); ok && nerr.Timeout() { - level.Warn(logger).Log("msg", "Timeout reading from socket", "err", err) + logger.Warn("Timeout reading from socket", "err", err) return } - level.Error(logger).Log("msg", "Error reading from socket", "err", err) + logger.Error("Error reading from socket", "err", err) continue } if peer.String() != dst.String() { @@ -369,7 +368,7 @@ func ProbeICMP(ctx context.Context, target string, module config.Module, registr hopLimitGauge.Set(hopLimit) registry.MustRegister(hopLimitGauge) } - level.Info(logger).Log("msg", "Found matching reply packet") + logger.Info("Found matching reply packet") return true } } diff --git a/prober/prober.go b/prober/prober.go index 93d4e3d6..5988c032 100644 --- a/prober/prober.go +++ b/prober/prober.go @@ -15,14 +15,14 @@ package prober import ( "context" + "log/slog" - "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/blackbox_exporter/config" ) -type ProbeFn func(ctx context.Context, target string, config config.Module, registry *prometheus.Registry, logger log.Logger) bool +type ProbeFn func(ctx context.Context, target string, config config.Module, registry *prometheus.Registry, logger *slog.Logger) bool const ( helpSSLEarliestCertExpiry = "Returns last SSL chain expiry in unixtime" diff --git a/prober/tcp.go b/prober/tcp.go index 47f68d70..98262813 100644 --- a/prober/tcp.go +++ b/prober/tcp.go @@ -18,28 +18,27 @@ import ( "context" "crypto/tls" "fmt" + "log/slog" "net" - "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" pconfig "github.com/prometheus/common/config" "github.com/prometheus/blackbox_exporter/config" ) -func dialTCP(ctx context.Context, target string, module config.Module, registry *prometheus.Registry, logger log.Logger) (net.Conn, error) { +func dialTCP(ctx context.Context, target string, module config.Module, registry *prometheus.Registry, logger *slog.Logger) (net.Conn, error) { var dialProtocol, dialTarget string dialer := &net.Dialer{} targetAddress, port, err := net.SplitHostPort(target) if err != nil { - level.Error(logger).Log("msg", "Error splitting target address and port", "err", err) + logger.Error("Error splitting target address and port", "err", err) return nil, err } ip, _, err := chooseProtocol(ctx, module.TCP.IPProtocol, module.TCP.IPProtocolFallback, targetAddress, registry, logger) if err != nil { - level.Error(logger).Log("msg", "Error resolving address", "err", err) + logger.Error("Error resolving address", "err", err) return nil, err } @@ -52,22 +51,22 @@ func dialTCP(ctx context.Context, target string, module config.Module, registry if len(module.TCP.SourceIPAddress) > 0 { srcIP := net.ParseIP(module.TCP.SourceIPAddress) if srcIP == nil { - level.Error(logger).Log("msg", "Error parsing source ip address", "srcIP", module.TCP.SourceIPAddress) + logger.Error("Error parsing source ip address", "srcIP", module.TCP.SourceIPAddress) return nil, fmt.Errorf("error parsing source ip address: %s", module.TCP.SourceIPAddress) } - level.Info(logger).Log("msg", "Using local address", "srcIP", srcIP) + logger.Info("Using local address", "srcIP", srcIP) dialer.LocalAddr = &net.TCPAddr{IP: srcIP} } dialTarget = net.JoinHostPort(ip.String(), port) if !module.TCP.TLS { - level.Info(logger).Log("msg", "Dialing TCP without TLS") + logger.Info("Dialing TCP without TLS") return dialer.DialContext(ctx, dialProtocol, dialTarget) } tlsConfig, err := pconfig.NewTLSConfig(&module.TCP.TLSConfig) if err != nil { - level.Error(logger).Log("msg", "Error creating TLS configuration", "err", err) + logger.Error("Error creating TLS configuration", "err", err) return nil, err } @@ -84,7 +83,7 @@ func dialTCP(ctx context.Context, target string, module config.Module, registry timeoutDeadline, _ := ctx.Deadline() dialer.Deadline = timeoutDeadline - level.Info(logger).Log("msg", "Dialing TCP with TLS") + logger.Info("Dialing TCP with TLS") return tls.DialWithDialer(dialer, dialProtocol, dialTarget, tlsConfig) } @@ -106,7 +105,7 @@ func probeExpectInfo(registry *prometheus.Registry, qr *config.QueryResponse, by metric.WithLabelValues(values...).Set(1) } -func ProbeTCP(ctx context.Context, target string, module config.Module, registry *prometheus.Registry, logger log.Logger) bool { +func ProbeTCP(ctx context.Context, target string, module config.Module, registry *prometheus.Registry, logger *slog.Logger) bool { probeSSLEarliestCertExpiry := prometheus.NewGauge(sslEarliestCertExpiryGaugeOpts) probeSSLLastChainExpiryTimestampSeconds := prometheus.NewGauge(sslChainExpiryInTimeStampGaugeOpts) probeSSLLastInformation := prometheus.NewGaugeVec( @@ -129,17 +128,17 @@ func ProbeTCP(ctx context.Context, target string, module config.Module, registry conn, err := dialTCP(ctx, target, module, registry, logger) if err != nil { - level.Error(logger).Log("msg", "Error dialing TCP", "err", err) + logger.Error("Error dialing TCP", "err", err) return false } defer conn.Close() - level.Info(logger).Log("msg", "Successfully dialed") + logger.Info("Successfully dialed") // Set a deadline to prevent the following code from blocking forever. // If a deadline cannot be set, better fail the probe by returning an error // now rather than blocking forever. if err := conn.SetDeadline(deadline); err != nil { - level.Error(logger).Log("msg", "Error setting deadline", "err", err) + logger.Error("Error setting deadline", "err", err) return false } if module.TCP.TLS { @@ -152,26 +151,26 @@ func ProbeTCP(ctx context.Context, target string, module config.Module, registry } scanner := bufio.NewScanner(conn) for i, qr := range module.TCP.QueryResponse { - level.Info(logger).Log("msg", "Processing query response entry", "entry_number", i) + logger.Info("Processing query response entry", "entry_number", i) send := qr.Send if qr.Expect.Regexp != nil { var match []int // Read lines until one of them matches the configured regexp. for scanner.Scan() { - level.Debug(logger).Log("msg", "Read line", "line", scanner.Text()) + logger.Debug("Read line", "line", scanner.Text()) match = qr.Expect.Regexp.FindSubmatchIndex(scanner.Bytes()) if match != nil { - level.Info(logger).Log("msg", "Regexp matched", "regexp", qr.Expect.Regexp, "line", scanner.Text()) + logger.Info("Regexp matched", "regexp", qr.Expect.Regexp, "line", scanner.Text()) break } } if scanner.Err() != nil { - level.Error(logger).Log("msg", "Error reading from connection", "err", scanner.Err().Error()) + logger.Error("Error reading from connection", "err", scanner.Err().Error()) return false } if match == nil { probeFailedDueToRegex.Set(1) - level.Error(logger).Log("msg", "Regexp did not match", "regexp", qr.Expect.Regexp, "line", scanner.Text()) + logger.Error("Regexp did not match", "regexp", qr.Expect.Regexp, "line", scanner.Text()) return false } probeFailedDueToRegex.Set(0) @@ -181,9 +180,9 @@ func ProbeTCP(ctx context.Context, target string, module config.Module, registry } } if send != "" { - level.Debug(logger).Log("msg", "Sending line", "line", send) + logger.Debug("Sending line", "line", send) if _, err := fmt.Fprintf(conn, "%s\n", send); err != nil { - level.Error(logger).Log("msg", "Failed to send", "err", err) + logger.Error("Failed to send", "err", err) return false } } @@ -191,7 +190,7 @@ func ProbeTCP(ctx context.Context, target string, module config.Module, registry // Upgrade TCP connection to TLS. tlsConfig, err := pconfig.NewTLSConfig(&module.TCP.TLSConfig) if err != nil { - level.Error(logger).Log("msg", "Failed to create TLS configuration", "err", err) + logger.Error("Failed to create TLS configuration", "err", err) return false } if tlsConfig.ServerName == "" { @@ -204,10 +203,10 @@ func ProbeTCP(ctx context.Context, target string, module config.Module, registry // Initiate TLS handshake (required here to get TLS state). if err := tlsConn.Handshake(); err != nil { - level.Error(logger).Log("msg", "TLS Handshake (client) failed", "err", err) + logger.Error("TLS Handshake (client) failed", "err", err) return false } - level.Info(logger).Log("msg", "TLS Handshake (client) succeeded.") + logger.Info("TLS Handshake (client) succeeded.") conn = net.Conn(tlsConn) scanner = bufio.NewScanner(conn) diff --git a/prober/tcp_test.go b/prober/tcp_test.go index 6b43fca8..94709a0f 100644 --- a/prober/tcp_test.go +++ b/prober/tcp_test.go @@ -28,10 +28,9 @@ import ( "testing" "time" - "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" pconfig "github.com/prometheus/common/config" + "github.com/prometheus/common/promslog" "github.com/prometheus/blackbox_exporter/config" ) @@ -55,7 +54,7 @@ func TestTCPConnection(t *testing.T) { testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() registry := prometheus.NewRegistry() - if !ProbeTCP(testCTX, ln.Addr().String(), config.Module{TCP: config.TCPProbe{IPProtocolFallback: true}}, registry, log.NewNopLogger()) { + if !ProbeTCP(testCTX, ln.Addr().String(), config.Module{TCP: config.TCPProbe{IPProtocolFallback: true}}, registry, promslog.NewNopLogger()) { t.Fatalf("TCP module failed, expected success.") } <-ch @@ -66,7 +65,7 @@ func TestTCPConnectionFails(t *testing.T) { registry := prometheus.NewRegistry() testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - if ProbeTCP(testCTX, ":0", config.Module{TCP: config.TCPProbe{}}, registry, log.NewNopLogger()) { + if ProbeTCP(testCTX, ":0", config.Module{TCP: config.TCPProbe{}}, registry, promslog.NewNopLogger()) { t.Fatalf("TCP module succeeded, expected failure.") } } @@ -106,7 +105,7 @@ func TestTCPConnectionWithTLS(t *testing.T) { defer os.Remove(tmpCaFile.Name()) ch := make(chan (struct{})) - logger := log.NewNopLogger() + logger := promslog.NewNopLogger() // Handle server side of this test. serverFunc := func() { conn, err := ln.Accept() @@ -131,7 +130,7 @@ func TestTCPConnectionWithTLS(t *testing.T) { tlsConn := tls.Server(conn, tlsConfig) defer tlsConn.Close() if err := tlsConn.Handshake(); err != nil { - level.Error(logger).Log("msg", "Error TLS Handshake (server) failed", "err", err) + logger.Error("Error TLS Handshake (server) failed", "err", err) } else { // Send some bytes before terminating the connection. fmt.Fprintf(tlsConn, "Hello World!\n") @@ -155,7 +154,7 @@ func TestTCPConnectionWithTLS(t *testing.T) { registry := prometheus.NewRegistry() go serverFunc() // Test name-verification failure (IP without IPs in cert's SAN). - if ProbeTCP(testCTX, ln.Addr().String(), module, registry, log.NewNopLogger()) { + if ProbeTCP(testCTX, ln.Addr().String(), module, registry, promslog.NewNopLogger()) { t.Fatalf("TCP module succeeded, expected failure.") } <-ch @@ -164,7 +163,7 @@ func TestTCPConnectionWithTLS(t *testing.T) { go serverFunc() // Test name-verification with name from target. target := net.JoinHostPort("localhost", listenPort) - if !ProbeTCP(testCTX, target, module, registry, log.NewNopLogger()) { + if !ProbeTCP(testCTX, target, module, registry, promslog.NewNopLogger()) { t.Fatalf("TCP module failed, expected success.") } <-ch @@ -173,7 +172,7 @@ func TestTCPConnectionWithTLS(t *testing.T) { go serverFunc() // Test name-verification against name from tls_config. module.TCP.TLSConfig.ServerName = "localhost" - if !ProbeTCP(testCTX, ln.Addr().String(), module, registry, log.NewNopLogger()) { + if !ProbeTCP(testCTX, ln.Addr().String(), module, registry, promslog.NewNopLogger()) { t.Fatalf("TCP module failed, expected success.") } <-ch @@ -252,7 +251,7 @@ func TestTCPConnectionWithTLSAndVerifiedCertificateChain(t *testing.T) { defer os.Remove(tmpCaFile.Name()) ch := make(chan (struct{})) - logger := log.NewNopLogger() + logger := promslog.NewNopLogger() // Handle server side of this test. serverFunc := func() { conn, err := ln.Accept() @@ -279,7 +278,7 @@ func TestTCPConnectionWithTLSAndVerifiedCertificateChain(t *testing.T) { tlsConn := tls.Server(conn, tlsConfig) defer tlsConn.Close() if err := tlsConn.Handshake(); err != nil { - level.Error(logger).Log("msg", "Error TLS Handshake (server) failed", "err", err) + logger.Error("Error TLS Handshake (server) failed", "err", err) } else { // Send some bytes before terminating the connection. fmt.Fprintf(tlsConn, "Hello World!\n") @@ -304,7 +303,7 @@ func TestTCPConnectionWithTLSAndVerifiedCertificateChain(t *testing.T) { go serverFunc() // Test name-verification with name from target. target := net.JoinHostPort("localhost", listenPort) - if !ProbeTCP(testCTX, target, module, registry, log.NewNopLogger()) { + if !ProbeTCP(testCTX, target, module, registry, promslog.NewNopLogger()) { t.Fatalf("TCP module failed, expected success.") } <-ch @@ -425,7 +424,7 @@ func TestTCPConnectionQueryResponseStartTLS(t *testing.T) { // Do the client side of this test. registry := prometheus.NewRegistry() - if !ProbeTCP(testCTX, ln.Addr().String(), module, registry, log.NewNopLogger()) { + if !ProbeTCP(testCTX, ln.Addr().String(), module, registry, promslog.NewNopLogger()) { t.Fatalf("TCP module failed, expected success.") } <-ch @@ -477,7 +476,7 @@ func TestTCPConnectionQueryResponseIRC(t *testing.T) { ch <- struct{}{} }() registry := prometheus.NewRegistry() - if !ProbeTCP(testCTX, ln.Addr().String(), module, registry, log.NewNopLogger()) { + if !ProbeTCP(testCTX, ln.Addr().String(), module, registry, promslog.NewNopLogger()) { t.Fatalf("TCP module failed, expected success.") } <-ch @@ -496,7 +495,7 @@ func TestTCPConnectionQueryResponseIRC(t *testing.T) { ch <- struct{}{} }() registry = prometheus.NewRegistry() - if ProbeTCP(testCTX, ln.Addr().String(), module, registry, log.NewNopLogger()) { + if ProbeTCP(testCTX, ln.Addr().String(), module, registry, promslog.NewNopLogger()) { t.Fatalf("TCP module succeeded, expected failure.") } mfs, err := registry.Gather() @@ -556,7 +555,7 @@ func TestTCPConnectionQueryResponseMatching(t *testing.T) { ch <- version }() registry := prometheus.NewRegistry() - if !ProbeTCP(testCTX, ln.Addr().String(), module, registry, log.NewNopLogger()) { + if !ProbeTCP(testCTX, ln.Addr().String(), module, registry, promslog.NewNopLogger()) { t.Fatalf("TCP module failed, expected success.") } if got, want := <-ch, "OpenSSH_6.9p1"; got != want { @@ -616,7 +615,7 @@ func TestTCPConnectionProtocol(t *testing.T) { } registry := prometheus.NewRegistry() - result := ProbeTCP(testCTX, net.JoinHostPort("localhost", port), module, registry, log.NewNopLogger()) + result := ProbeTCP(testCTX, net.JoinHostPort("localhost", port), module, registry, promslog.NewNopLogger()) if !result { t.Fatalf("TCP protocol: \"tcp\", prefer: \"ip4\" connection test failed, expected success.") } @@ -637,7 +636,7 @@ func TestTCPConnectionProtocol(t *testing.T) { } registry = prometheus.NewRegistry() - result = ProbeTCP(testCTX, net.JoinHostPort("localhost", port), module, registry, log.NewNopLogger()) + result = ProbeTCP(testCTX, net.JoinHostPort("localhost", port), module, registry, promslog.NewNopLogger()) if !result { t.Fatalf("TCP protocol: \"tcp\", prefer: \"ip6\" connection test failed, expected success.") } @@ -656,7 +655,7 @@ func TestTCPConnectionProtocol(t *testing.T) { } registry = prometheus.NewRegistry() - result = ProbeTCP(testCTX, net.JoinHostPort("localhost", port), module, registry, log.NewNopLogger()) + result = ProbeTCP(testCTX, net.JoinHostPort("localhost", port), module, registry, promslog.NewNopLogger()) if !result { t.Fatalf("TCP protocol: \"tcp\" connection test failed, expected success.") } @@ -696,7 +695,7 @@ func TestPrometheusTimeoutTCP(t *testing.T) { Expect: config.MustNewRegexp("SSH-2.0-(OpenSSH_6.9p1) Debian-2"), }, }, - }}, registry, log.NewNopLogger()) { + }}, registry, promslog.NewNopLogger()) { t.Fatalf("TCP module succeeded, expected timeout failure.") } <-ch diff --git a/prober/utils.go b/prober/utils.go index cde1f3ed..3dc4153c 100644 --- a/prober/utils.go +++ b/prober/utils.go @@ -17,12 +17,10 @@ import ( "context" "fmt" "hash/fnv" + "log/slog" "net" "time" - "github.com/go-kit/log" - "github.com/go-kit/log/level" - "github.com/prometheus/client_golang/prometheus" ) @@ -32,7 +30,7 @@ var protocolToGauge = map[string]float64{ } // Returns the IP for the IPProtocol and lookup time. -func chooseProtocol(ctx context.Context, IPProtocol string, fallbackIPProtocol bool, target string, registry *prometheus.Registry, logger log.Logger) (ip *net.IPAddr, lookupTime float64, err error) { +func chooseProtocol(ctx context.Context, IPProtocol string, fallbackIPProtocol bool, target string, registry *prometheus.Registry, logger *slog.Logger) (ip *net.IPAddr, lookupTime float64, err error) { var fallbackProtocol string probeDNSLookupTimeSeconds := prometheus.NewGauge(prometheus.GaugeOpts{ Name: "probe_dns_lookup_time_seconds", @@ -60,7 +58,7 @@ func chooseProtocol(ctx context.Context, IPProtocol string, fallbackIPProtocol b fallbackProtocol = "ip6" } - level.Info(logger).Log("msg", "Resolving target address", "target", target, "ip_protocol", IPProtocol) + logger.Info("Resolving target address", "target", target, "ip_protocol", IPProtocol) resolveStart := time.Now() defer func() { @@ -73,19 +71,19 @@ func chooseProtocol(ctx context.Context, IPProtocol string, fallbackIPProtocol b ips, err := resolver.LookupIP(ctx, IPProtocol, target) if err == nil { for _, ip := range ips { - level.Info(logger).Log("msg", "Resolved target address", "target", target, "ip", ip.String()) + logger.Info("Resolved target address", "target", target, "ip", ip.String()) probeIPProtocolGauge.Set(protocolToGauge[IPProtocol]) probeIPAddrHash.Set(ipHash(ip)) return &net.IPAddr{IP: ip}, lookupTime, nil } } - level.Error(logger).Log("msg", "Resolution with IP protocol failed", "target", target, "ip_protocol", IPProtocol, "err", err) + logger.Error("Resolution with IP protocol failed", "target", target, "ip_protocol", IPProtocol, "err", err) return nil, 0.0, err } ips, err := resolver.LookupIPAddr(ctx, target) if err != nil { - level.Error(logger).Log("msg", "Resolution with IP protocol failed", "target", target, "err", err) + logger.Error("Resolution with IP protocol failed", "target", target, "err", err) return nil, 0.0, err } @@ -95,7 +93,7 @@ func chooseProtocol(ctx context.Context, IPProtocol string, fallbackIPProtocol b switch IPProtocol { case "ip4": if ip.IP.To4() != nil { - level.Info(logger).Log("msg", "Resolved target address", "target", target, "ip", ip.String()) + logger.Info("Resolved target address", "target", target, "ip", ip.String()) probeIPProtocolGauge.Set(4) probeIPAddrHash.Set(ipHash(ip.IP)) return &ip, lookupTime, nil @@ -106,7 +104,7 @@ func chooseProtocol(ctx context.Context, IPProtocol string, fallbackIPProtocol b case "ip6": if ip.IP.To4() == nil { - level.Info(logger).Log("msg", "Resolved target address", "target", target, "ip", ip.String()) + logger.Info("Resolved target address", "target", target, "ip", ip.String()) probeIPProtocolGauge.Set(6) probeIPAddrHash.Set(ipHash(ip.IP)) return &ip, lookupTime, nil @@ -129,7 +127,7 @@ func chooseProtocol(ctx context.Context, IPProtocol string, fallbackIPProtocol b probeIPProtocolGauge.Set(6) } probeIPAddrHash.Set(ipHash(fallback.IP)) - level.Info(logger).Log("msg", "Resolved target address", "target", target, "ip", fallback.String()) + logger.Info("Resolved target address", "target", target, "ip", fallback.String()) return fallback, lookupTime, nil } diff --git a/prober/utils_test.go b/prober/utils_test.go index 1b1c41dc..c439790e 100644 --- a/prober/utils_test.go +++ b/prober/utils_test.go @@ -23,14 +23,12 @@ import ( "fmt" "math/big" "net" - "os" "testing" "time" - "github.com/go-kit/log" - "github.com/prometheus/client_golang/prometheus" dto "github.com/prometheus/client_model/go" + "github.com/prometheus/common/promslog" ) // Check if expected results are in the registry @@ -149,8 +147,7 @@ func TestChooseProtocol(t *testing.T) { } ctx := context.Background() registry := prometheus.NewPedanticRegistry() - w := log.NewSyncWriter(os.Stderr) - logger := log.NewLogfmtLogger(w) + logger := promslog.New(&promslog.Config{}) ip, _, err := chooseProtocol(ctx, "ip4", true, "ipv6.google.com", registry, logger) if err != nil {