diff --git a/Makefile b/Makefile index d167d84..20b8873 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ endif GOBUILD ?= CGO_ENABLED=0 go build PACKAGES ?= $(shell go list ./...) -SOURCES ?= $(shell find . -name "*.go" -type f) +SOURCES ?= $(shell find . -name "*.go" -type f -not -path ./.devenv/\* -not -path ./.direnv/\*) GENERATE ?= $(PACKAGES) TAGS ?= netgo diff --git a/changelog/unreleased/logging-library.md b/changelog/unreleased/logging-library.md new file mode 100644 index 0000000..03eb3c7 --- /dev/null +++ b/changelog/unreleased/logging-library.md @@ -0,0 +1,7 @@ +Change: Switch to official logging library + +Since there have been a structured logger part of the Go standard library we +thought it's time to replace the library with that. Be aware that log messages +should change a little bit. + +https://github.com/promhippie/prometheus-scw-sd/issues/278 diff --git a/go.mod b/go.mod index e0f2e4d..30727b3 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/oklog/run v1.1.0 github.com/prometheus/client_golang v1.20.1 github.com/prometheus/common v0.59.0 - github.com/prometheus/exporter-toolkit v0.12.0 + github.com/prometheus/exporter-toolkit v0.13.0 github.com/prometheus/prometheus v1.8.2-0.20210220213500-8c8de46003d1 github.com/scaleway/scaleway-sdk-go v1.0.0-beta.26 github.com/stretchr/testify v1.9.0 diff --git a/go.sum b/go.sum index 1308e62..2dac6c7 100644 --- a/go.sum +++ b/go.sum @@ -643,8 +643,8 @@ github.com/prometheus/common v0.17.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16 github.com/prometheus/common v0.59.0 h1:o2eVCLbhf3sgisnD5e0/twUt25r8gNmMHNzTOAuY9bs= github.com/prometheus/common v0.59.0/go.mod h1:GpWM7dewqmVYcd7SmRaiWVe9SSqjf0UrwnYnpEZNuT0= github.com/prometheus/exporter-toolkit v0.5.1/go.mod h1:OCkM4805mmisBhLmVFw858QYi3v0wKdY6/UxrT0pZVg= -github.com/prometheus/exporter-toolkit v0.12.0 h1:DkE5RcEZR3lQA2QD5JLVQIf41dFKNsVMXFhgqcif7fo= -github.com/prometheus/exporter-toolkit v0.12.0/go.mod h1:fQH0KtTn0yrrS0S82kqppRjDDiwMfIQUwT+RBRRhwUc= +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.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= diff --git a/pkg/action/discoverer.go b/pkg/action/discoverer.go index 16b6a3d..fb40dbb 100644 --- a/pkg/action/discoverer.go +++ b/pkg/action/discoverer.go @@ -2,13 +2,11 @@ package action import ( "context" - "errors" "fmt" + "log/slog" "strings" "time" - "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/prometheus/common/model" "github.com/prometheus/prometheus/discovery/targetgroup" baremetal "github.com/scaleway/scaleway-sdk-go/api/baremetal/v1" @@ -65,21 +63,12 @@ var ( "tags": providerPrefix + "tags", "zone": providerPrefix + "zone", } - - // ErrClientFailed defines an error if the client init fails. - ErrClientFailed = errors.New("failed to initialize client") - - // ErrClientForbidden defines an error if the authentication fails. - ErrClientForbidden = errors.New("failed to authenticate client") - - // ErrInvalidZone defines an error if an invalid zone have been provided. - ErrInvalidZone = errors.New("invalid zone provided") ) // Discoverer implements the Prometheus discoverer interface. type Discoverer struct { clients map[string]*scw.Client - logger log.Logger + logger *slog.Logger refresh int checkInstance bool instanceZones []string @@ -141,8 +130,7 @@ func (d *Discoverer) getTargets(ctx context.Context) ([]*targetgroup.Group, erro requestDuration.WithLabelValues(project, "instance", zone.String()).Observe(time.Since(now).Seconds()) if err != nil { - level.Warn(d.logger).Log( - "msg", "Failed to fetch servers", + d.logger.Warn("Failed to fetch servers", "project", project, "kind", "instance", "zone", zone, @@ -153,8 +141,7 @@ func (d *Discoverer) getTargets(ctx context.Context) ([]*targetgroup.Group, erro continue } - level.Debug(d.logger).Log( - "msg", "Requested servers", + d.logger.Debug("Requested servers", "project", project, "kind", "instance", "zone", zone, @@ -252,8 +239,7 @@ func (d *Discoverer) getTargets(ctx context.Context) ([]*targetgroup.Group, erro }, } - level.Debug(d.logger).Log( - "msg", "Server added", + d.logger.Debug("Server added", "project", project, "kind", "instance", "zone", zone, @@ -294,8 +280,7 @@ func (d *Discoverer) getTargets(ctx context.Context) ([]*targetgroup.Group, erro requestDuration.WithLabelValues(project, "baremetal", zone.String()).Observe(time.Since(now).Seconds()) if err != nil { - level.Warn(d.logger).Log( - "msg", "Failed to fetch servers", + d.logger.Warn("Failed to fetch servers", "project", project, "kind", "baremetal", "zone", zone, @@ -306,8 +291,7 @@ func (d *Discoverer) getTargets(ctx context.Context) ([]*targetgroup.Group, erro continue } - level.Debug(d.logger).Log( - "msg", "Requested servers", + d.logger.Debug("Requested servers", "project", project, "kind", "baremetal", "zone", zone, @@ -363,8 +347,7 @@ func (d *Discoverer) getTargets(ctx context.Context) ([]*targetgroup.Group, erro }, } - level.Debug(d.logger).Log( - "msg", "Server added", + d.logger.Debug("Server added", "project", project, "kind", "baremetal", "zone", zone, @@ -380,8 +363,7 @@ func (d *Discoverer) getTargets(ctx context.Context) ([]*targetgroup.Group, erro for k := range d.lasts { if _, ok := current[k]; !ok { - level.Debug(d.logger).Log( - "msg", "Server deleted", + d.logger.Debug("Server deleted", "source", k, ) diff --git a/pkg/action/metrics.go b/pkg/action/metrics.go index 2ee2200..cfe7cfa 100644 --- a/pkg/action/metrics.go +++ b/pkg/action/metrics.go @@ -2,9 +2,8 @@ package action import ( "fmt" + "log/slog" - "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/collectors" "github.com/promhippie/prometheus-scw-sd/pkg/version" @@ -49,11 +48,9 @@ func init() { } type promLogger struct { - logger log.Logger + logger *slog.Logger } func (pl promLogger) Println(v ...interface{}) { - level.Error(pl.logger).Log( - "msg", fmt.Sprintln(v...), - ) + pl.logger.Error(fmt.Sprintln(v...)) } diff --git a/pkg/action/server.go b/pkg/action/server.go index 2927454..6998439 100644 --- a/pkg/action/server.go +++ b/pkg/action/server.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "io" + "log/slog" "net/http" "os" "os/signal" @@ -11,8 +12,6 @@ import ( "time" "github.com/go-chi/chi/v5" - "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/oklog/run" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/exporter-toolkit/web" @@ -24,9 +23,8 @@ import ( ) // Server handles the server sub-command. -func Server(cfg *config.Config, logger log.Logger) error { - level.Info(logger).Log( - "msg", "Launching Prometheus Scaleway SD", +func Server(cfg *config.Config, logger *slog.Logger) error { + logger.Info("Launching Prometheus Scaleway SD", "version", version.String, "revision", version.Revision, "date", version.Date, @@ -44,8 +42,7 @@ func Server(cfg *config.Config, logger log.Logger) error { accessKey, err := config.Value(credential.AccessKey) if err != nil { - level.Error(logger).Log( - "msg", "Failed to read access key secret", + logger.Error("Failed to read access key secret", "project", credential.Project, "err", err, ) @@ -56,8 +53,7 @@ func Server(cfg *config.Config, logger log.Logger) error { secretKey, err := config.Value(credential.SecretKey) if err != nil { - level.Error(logger).Log( - "msg", "Failed to read secret key secret", + logger.Error("Failed to read secret key secret", "project", credential.Project, "err", err, ) @@ -92,13 +88,12 @@ func Server(cfg *config.Config, logger log.Logger) error { zone, err := scw.ParseZone(credential.Zone) if err != nil { - level.Error(logger).Log( - "msg", ErrInvalidZone, + logger.Error("Invalid zone provided", "project", credential.Project, "zone", credential.Zone, ) - return ErrInvalidZone + return fmt.Errorf("invalid zone provided") } opts = append(opts, scw.WithDefaultZone( @@ -109,12 +104,11 @@ func Server(cfg *config.Config, logger log.Logger) error { client, err := scw.NewClient(opts...) if err != nil { - level.Error(logger).Log( - "msg", ErrClientFailed, + logger.Error("Failed to initialize client", "project", credential.Project, ) - return ErrClientFailed + return fmt.Errorf("failed to initialize client") } clients[credential.Project] = client @@ -145,9 +139,8 @@ func Server(cfg *config.Config, logger log.Logger) error { } gr.Add(func() error { - level.Info(logger).Log( - "msg", "Starting metrics server", - "addr", cfg.Server.Addr, + logger.Info("Starting metrics server", + "address", cfg.Server.Addr, ) return web.ListenAndServe( @@ -164,16 +157,14 @@ func Server(cfg *config.Config, logger log.Logger) error { defer cancel() if err := server.Shutdown(ctx); err != nil { - level.Error(logger).Log( - "msg", "Failed to shutdown metrics gracefully", + logger.Error("Failed to shutdown metrics gracefully", "err", err, ) return } - level.Info(logger).Log( - "msg", "Metrics shutdown gracefully", + logger.Info("Metrics shutdown gracefully", "reason", reason, ) }) @@ -196,7 +187,7 @@ func Server(cfg *config.Config, logger log.Logger) error { return gr.Run() } -func handler(cfg *config.Config, logger log.Logger) *chi.Mux { +func handler(cfg *config.Config, logger *slog.Logger) *chi.Mux { mux := chi.NewRouter() mux.Use(middleware.Recoverer(logger)) mux.Use(middleware.RealIP) @@ -236,8 +227,7 @@ func handler(cfg *config.Config, logger log.Logger) *chi.Mux { content, err := os.ReadFile(cfg.Target.File) if err != nil { - level.Info(logger).Log( - "msg", "Failed to read service discovery data", + logger.Error("Failed to read service discovery data", "err", err, ) diff --git a/pkg/adapter/adapter.go b/pkg/adapter/adapter.go index 81b9d28..d8cea9b 100644 --- a/pkg/adapter/adapter.go +++ b/pkg/adapter/adapter.go @@ -19,12 +19,11 @@ import ( "context" "encoding/json" "fmt" + "log/slog" "os" "path/filepath" "reflect" - "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/prometheus/prometheus/discovery" "github.com/prometheus/prometheus/discovery/targetgroup" ) @@ -43,7 +42,7 @@ type Adapter struct { manager *discovery.Manager output string name string - logger log.Logger + logger *slog.Logger } func mapToArray(m map[string]*customSD) []customSD { @@ -84,7 +83,7 @@ func (a *Adapter) generateTargetGroups(allTargetGroups map[string][]*targetgroup a.groups = tempGroups err := a.writeOutput() if err != nil { - level.Error(log.With(a.logger, "component", "sd-adapter")).Log("err", err) + a.logger.With("component", "sd-adapter").Error("", "err", err) } } @@ -138,12 +137,12 @@ func (a *Adapter) Run() { } // NewAdapter creates a new instance of Adapter. -func NewAdapter(ctx context.Context, file string, name string, d discovery.Discoverer, logger log.Logger) *Adapter { +func NewAdapter(ctx context.Context, file string, name string, d discovery.Discoverer, logger *slog.Logger) *Adapter { return &Adapter{ ctx: ctx, disc: d, groups: make(map[string]*customSD), - manager: discovery.NewManager(ctx, logger), + manager: discovery.NewManager(ctx, nil), output: file, name: name, logger: logger, diff --git a/pkg/command/health.go b/pkg/command/health.go index 23a2060..799cb18 100644 --- a/pkg/command/health.go +++ b/pkg/command/health.go @@ -4,7 +4,6 @@ import ( "fmt" "net/http" - "github.com/go-kit/log/level" "github.com/promhippie/prometheus-scw-sd/pkg/config" "github.com/urfave/cli/v2" ) @@ -20,8 +19,7 @@ func Health(cfg *config.Config) *cli.Command { if c.IsSet("scw.config") { if err := readConfig(c.String("scw.config"), cfg); err != nil { - level.Error(logger).Log( - "msg", "Failed to read config", + logger.Error("Failed to read config", "err", err, ) @@ -37,8 +35,7 @@ func Health(cfg *config.Config) *cli.Command { ) if err != nil { - level.Error(logger).Log( - "msg", "Failed to request health check", + logger.Error("Failed to request health check", "err", err, ) @@ -48,8 +45,7 @@ func Health(cfg *config.Config) *cli.Command { defer resp.Body.Close() if resp.StatusCode != 200 { - level.Error(logger).Log( - "msg", "Health check seems to be in bad state", + logger.Error("Health check seems to be in bad state", "err", err, "code", resp.StatusCode, ) @@ -57,6 +53,10 @@ func Health(cfg *config.Config) *cli.Command { return err } + logger.Debug("Health check seems to be fine", + "code", resp.StatusCode, + ) + return nil }, } diff --git a/pkg/command/server.go b/pkg/command/server.go index bcc7e97..d682569 100644 --- a/pkg/command/server.go +++ b/pkg/command/server.go @@ -3,7 +3,6 @@ package command import ( "errors" - "github.com/go-kit/log/level" "github.com/promhippie/prometheus-scw-sd/pkg/action" "github.com/promhippie/prometheus-scw-sd/pkg/config" "github.com/urfave/cli/v2" @@ -26,8 +25,7 @@ func Server(cfg *config.Config) *cli.Command { if c.IsSet("scw.config") { if err := readConfig(c.String("scw.config"), cfg); err != nil { - level.Error(logger).Log( - "msg", "Failed to read config", + logger.Error("Failed to read config", "err", err, ) @@ -36,10 +34,7 @@ func Server(cfg *config.Config) *cli.Command { } if cfg.Target.File == "" { - level.Error(logger).Log( - "msg", "Missing path for output.file", - ) - + logger.Error("Missing path for output.file") return errors.New("missing path for output.file") } @@ -58,27 +53,18 @@ func Server(cfg *config.Config) *cli.Command { ) if credentials.AccessKey == "" { - level.Error(logger).Log( - "msg", "Missing required scw.access_key", - ) - + logger.Error("Missing required scw.access_key") return errors.New("missing required scw.access_key") } if credentials.SecretKey == "" { - level.Error(logger).Log( - "msg", "Missing required scw.secret_key", - ) - + logger.Error("Missing required scw.secret_key") return errors.New("missing required scw.secret_key") } } if len(cfg.Target.Credentials) == 0 { - level.Error(logger).Log( - "msg", "Missing any credentials", - ) - + logger.Error("Missing any credentials") return errors.New("missing any credentials") } diff --git a/pkg/command/setup.go b/pkg/command/setup.go index 2f357e8..4863f2d 100644 --- a/pkg/command/setup.go +++ b/pkg/command/setup.go @@ -3,12 +3,11 @@ package command import ( "encoding/json" "errors" + "log/slog" "os" "path/filepath" "strings" - "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/promhippie/prometheus-scw-sd/pkg/config" "gopkg.in/yaml.v3" ) @@ -18,36 +17,35 @@ var ( ErrConfigFormatInvalid = errors.New("config extension is not supported") ) -func setupLogger(cfg *config.Config) log.Logger { - var logger log.Logger - +func setupLogger(cfg *config.Config) *slog.Logger { if cfg.Logs.Pretty { - logger = log.NewSyncLogger( - log.NewLogfmtLogger(os.Stdout), - ) - } else { - logger = log.NewSyncLogger( - log.NewJSONLogger(os.Stdout), + return slog.New( + slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ + Level: loggerLevel(cfg), + }), ) } + return slog.New( + slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: loggerLevel(cfg), + }), + ) +} + +func loggerLevel(cfg *config.Config) slog.Leveler { switch strings.ToLower(cfg.Logs.Level) { case "error": - logger = level.NewFilter(logger, level.AllowError()) + return slog.LevelError case "warn": - logger = level.NewFilter(logger, level.AllowWarn()) + return slog.LevelWarn case "info": - logger = level.NewFilter(logger, level.AllowInfo()) + return slog.LevelInfo case "debug": - logger = level.NewFilter(logger, level.AllowDebug()) - default: - logger = level.NewFilter(logger, level.AllowInfo()) + return slog.LevelDebug } - return log.With( - logger, - "ts", log.DefaultTimestampUTC, - ) + return slog.LevelInfo } func readConfig(file string, cfg *config.Config) error { diff --git a/pkg/middleware/recoverer.go b/pkg/middleware/recoverer.go index 1cc2dab..95f9de1 100644 --- a/pkg/middleware/recoverer.go +++ b/pkg/middleware/recoverer.go @@ -1,21 +1,18 @@ package middleware import ( + "log/slog" "net/http" "runtime/debug" - - "github.com/go-kit/log" - "github.com/go-kit/log/level" ) // Recoverer initializes a recoverer middleware. -func Recoverer(logger log.Logger) func(next http.Handler) http.Handler { +func Recoverer(logger *slog.Logger) func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { defer func() { if rvr := recover(); rvr != nil { - level.Error(logger).Log( - "msg", rvr.(string), + logger.Error(rvr.(string), "trace", string(debug.Stack()), )