From 89d75bf7dbd73eebc074a225342a7d9eda839242 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Mar 2025 12:12:38 +0000 Subject: [PATCH 01/13] Bump github.com/prometheus/common from 0.62.0 to 0.63.0 Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.62.0 to 0.63.0. - [Release notes](https://github.com/prometheus/common/releases) - [Changelog](https://github.com/prometheus/common/blob/main/RELEASE.md) - [Commits](https://github.com/prometheus/common/compare/v0.62.0...v0.63.0) --- updated-dependencies: - dependency-name: github.com/prometheus/common dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 6 +++--- go.sum | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index fd48cfc91..42bb1ad8d 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.21.1 github.com/prometheus/client_model v0.6.1 - github.com/prometheus/common v0.62.0 + github.com/prometheus/common v0.63.0 github.com/prometheus/exporter-toolkit v0.14.0 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.10.0 @@ -61,13 +61,13 @@ require ( golang.org/x/exp v0.0.0-20240529005216-23cca8864a10 // indirect golang.org/x/mod v0.19.0 // indirect golang.org/x/net v0.35.0 // indirect - golang.org/x/oauth2 v0.24.0 // indirect + golang.org/x/oauth2 v0.25.0 // indirect golang.org/x/sync v0.11.0 // indirect golang.org/x/sys v0.30.0 // indirect golang.org/x/term v0.29.0 // indirect golang.org/x/text v0.22.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect - google.golang.org/protobuf v1.36.1 // indirect + google.golang.org/protobuf v1.36.5 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 08d91f7cf..aa2015e52 100644 --- a/go.sum +++ b/go.sum @@ -77,8 +77,8 @@ github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVI github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= @@ -161,8 +161,8 @@ github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGC github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= 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.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= -github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= +github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= +github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= github.com/prometheus/exporter-toolkit v0.14.0 h1:NMlswfibpcZZ+H0sZBiTjrA3/aBFHkNZqE+iCj5EmRg= github.com/prometheus/exporter-toolkit v0.14.0/go.mod h1:Gu5LnVvt7Nr/oqTBUC23WILZepW0nffNo10XdhQcwWA= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= @@ -238,8 +238,8 @@ golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= -golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= -golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70= +golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -290,8 +290,8 @@ golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= +google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= From 2eab18ce87d471d3faf4d44e5bda8d008d63107c Mon Sep 17 00:00:00 2001 From: idoko Date: Wed, 2 Apr 2025 23:32:02 +0100 Subject: [PATCH 02/13] update promslog levels --- exporter/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exporter/server.go b/exporter/server.go index 1aea32abe..111f938e9 100644 --- a/exporter/server.go +++ b/exporter/server.go @@ -80,7 +80,7 @@ func RunWebServer(opts *ServerOpts, exporters []*Exporter, log *logrus.Logger) { WebListenAddresses: &[]string{opts.WebListenAddress}, WebConfigFile: &opts.TLSConfigPath, } - logLevel := &promslog.AllowedLevel{} + logLevel := &promslog.Level{} _ = logLevel.Set(log.Level.String()) if err := web.ListenAndServe(server, flags, promslog.New(&promslog.Config{ //nolint:exhaustivestruct Level: logLevel, From 1f31568dfd15c52bedaa6a464a8e186f417db1c5 Mon Sep 17 00:00:00 2001 From: idoko Date: Thu, 3 Apr 2025 01:47:15 +0100 Subject: [PATCH 03/13] baseline for logrus -> slog migration --- exporter/base_collector.go | 6 +- exporter/collstats_collector.go | 16 ++--- exporter/collstats_collector_test.go | 4 +- exporter/currentop_collector.go | 25 ++++---- exporter/currentop_collector_test.go | 4 +- exporter/dbstats_collector.go | 14 ++-- exporter/dbstats_collector_test.go | 4 +- exporter/debug.go | 12 ++-- exporter/debug_test.go | 17 +++-- exporter/diagnostic_data_collector.go | 27 ++++---- exporter/diagnostic_data_collector_test.go | 38 +++++------ exporter/encryption_info_test.go | 8 +-- exporter/exporter.go | 24 +++---- exporter/exporter_test.go | 12 ++-- ...feature_compatibility_version_collector.go | 10 +-- ...re_compatibility_version_collector_test.go | 4 +- exporter/general_collector.go | 10 +-- exporter/general_collector_test.go | 6 +- exporter/indexstats_collector.go | 16 ++--- exporter/indexstats_collector_test.go | 6 +- exporter/multi_target_test.go | 6 +- exporter/pbm_collector.go | 22 +++---- exporter/pbm_collector_test.go | 4 +- exporter/profile_status_collector.go | 10 +-- exporter/profile_status_collector_test.go | 4 +- exporter/replset_config_collector.go | 10 +-- exporter/replset_config_collector_test.go | 6 +- exporter/replset_status_collector.go | 8 +-- exporter/replset_status_collector_test.go | 6 +- exporter/secondary_lag_test.go | 4 +- exporter/seedlist.go | 19 +++--- exporter/seedlist_test.go | 4 +- exporter/server.go | 27 ++++---- exporter/shards_collector.go | 20 +++--- exporter/shards_collector_test.go | 4 +- exporter/top_collector.go | 6 +- exporter/top_collector_test.go | 4 +- exporter/topology_info.go | 12 ++-- exporter/topology_info_test.go | 6 +- exporter/v1_compatibility.go | 64 +++++++++---------- exporter/v1_compatibility_test.go | 22 +++++-- go.mod | 1 - go.sum | 4 -- main.go | 39 ++++++----- main_test.go | 8 +-- 45 files changed, 293 insertions(+), 290 deletions(-) diff --git a/exporter/base_collector.go b/exporter/base_collector.go index 0f84a4708..37078ab17 100644 --- a/exporter/base_collector.go +++ b/exporter/base_collector.go @@ -17,23 +17,23 @@ package exporter import ( "context" + "log/slog" "sync" "github.com/prometheus/client_golang/prometheus" - "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/mongo" ) type baseCollector struct { client *mongo.Client - logger *logrus.Entry + logger *slog.Logger lock sync.Mutex metricsCache []prometheus.Metric } // newBaseCollector creates a skeletal collector, which is used to create other collectors. -func newBaseCollector(client *mongo.Client, logger *logrus.Entry) *baseCollector { +func newBaseCollector(client *mongo.Client, logger *slog.Logger) *baseCollector { return &baseCollector{ client: client, logger: logger, diff --git a/exporter/collstats_collector.go b/exporter/collstats_collector.go index ed2de6e8d..189f634e3 100644 --- a/exporter/collstats_collector.go +++ b/exporter/collstats_collector.go @@ -17,10 +17,10 @@ package exporter import ( "context" + "log/slog" "strings" "github.com/prometheus/client_golang/prometheus" - "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" ) @@ -38,10 +38,10 @@ type collstatsCollector struct { } // newCollectionStatsCollector creates a collector for statistics about collections. -func newCollectionStatsCollector(ctx context.Context, client *mongo.Client, logger *logrus.Logger, discovery bool, topology labelsGetter, collections []string, enableDetails bool) *collstatsCollector { +func newCollectionStatsCollector(ctx context.Context, client *mongo.Client, logger *slog.Logger, discovery bool, topology labelsGetter, collections []string, enableDetails bool) *collstatsCollector { return &collstatsCollector{ ctx: ctx, - base: newBaseCollector(client, logger.WithFields(logrus.Fields{"collector": "collstats"})), + base: newBaseCollector(client, logger.With("collector", "collstats")), compatibleMode: false, // there are no compatible metrics for this collector. discoveringMode: discovery, @@ -70,7 +70,7 @@ func (d *collstatsCollector) collect(ch chan<- prometheus.Metric) { if d.discoveringMode { onlyCollectionsNamespaces, err := listAllCollections(d.ctx, client, d.collections, systemDBs, true) if err != nil { - logger.Errorf("cannot auto discover databases and collections: %s", err.Error()) + logger.Error("cannot auto discover databases and collections", "error", err.Error()) return } @@ -80,7 +80,7 @@ func (d *collstatsCollector) collect(ch chan<- prometheus.Metric) { var err error collections, err = checkNamespacesForViews(d.ctx, client, d.collections) if err != nil { - logger.Errorf("cannot list collections: %s", err.Error()) + logger.Error("cannot list collections", "error", err.Error()) return } } @@ -126,19 +126,19 @@ func (d *collstatsCollector) collect(ch chan<- prometheus.Metric) { cursor, err := client.Database(database).Collection(collection).Aggregate(d.ctx, pipeline) if err != nil { - logger.Errorf("cannot get $collstats cursor for collection %s.%s: %s", database, collection, err) + logger.Error("cannot get $collstats cursor for collection", "database", database, "collection", collection, "error", err) continue } var stats []bson.M if err = cursor.All(d.ctx, &stats); err != nil { - logger.Errorf("cannot get $collstats for collection %s.%s: %s", database, collection, err) + logger.Error("cannot get $collstats for collection", "database", database, "collection", collection, "error", err) continue } - logger.Debugf("$collStats metrics for %s.%s", database, collection) + logger.Debug("$collStats metrics for %s.%s", "database", database, "collection", collection) debugResult(logger, stats) prefix := "collstats" diff --git a/exporter/collstats_collector_test.go b/exporter/collstats_collector_test.go index c8dc84052..b098418a3 100644 --- a/exporter/collstats_collector_test.go +++ b/exporter/collstats_collector_test.go @@ -23,7 +23,7 @@ import ( "time" "github.com/prometheus/client_golang/prometheus/testutil" - "github.com/sirupsen/logrus" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/assert" "go.mongodb.org/mongo-driver/bson" @@ -53,7 +53,7 @@ func TestCollStatsCollector(t *testing.T) { ti := labelsGetterMock{} collection := []string{"testdb.testcol_00", "testdb.testcol_01", "testdb.testcol_02"} - logger := logrus.New() + logger := promslog.New(&promslog.Config{}) c := newCollectionStatsCollector(ctx, client, logger, false, ti, collection, false) // The last \n at the end of this string is important diff --git a/exporter/currentop_collector.go b/exporter/currentop_collector.go index b93316e96..b30616d93 100644 --- a/exporter/currentop_collector.go +++ b/exporter/currentop_collector.go @@ -17,12 +17,13 @@ package exporter import ( "context" + "fmt" + "log/slog" "strconv" "time" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" - "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" @@ -39,12 +40,12 @@ type currentopCollector struct { var ErrInvalidOrMissingInprogEntry = errors.New("invalid or missing inprog entry in currentop results") // newCurrentopCollector creates a collector for being processed queries. -func newCurrentopCollector(ctx context.Context, client *mongo.Client, logger *logrus.Logger, +func newCurrentopCollector(ctx context.Context, client *mongo.Client, logger *slog.Logger, compatible bool, topology labelsGetter, currentOpSlowTime string, ) *currentopCollector { return ¤topCollector{ ctx: ctx, - base: newBaseCollector(client, logger.WithFields(logrus.Fields{"collector": "currentop"})), + base: newBaseCollector(client, logger.With("collector", "currentop")), compatibleMode: compatible, topologyInfo: topology, currentopslowtime: currentOpSlowTime, @@ -66,7 +67,7 @@ func (d *currentopCollector) collect(ch chan<- prometheus.Metric) { client := d.base.client slowtime, err := time.ParseDuration(d.currentopslowtime) if err != nil { - logger.Errorf("Failed to parse slowtime: %s", err) + logger.Error("Failed to parse slowtime", "error", err) ch <- prometheus.NewInvalidMetric(prometheus.NewInvalidDesc(err), err) return } @@ -90,7 +91,7 @@ func (d *currentopCollector) collect(ch chan<- prometheus.Metric) { var r primitive.M if err := res.Decode(&r); err != nil { - logger.Errorf("Failed to decode currentOp response: %s", err) + logger.Error("Failed to decode currentOp response", "error", err) ch <- prometheus.NewInvalidMetric(prometheus.NewInvalidDesc(err), err) return } @@ -101,7 +102,7 @@ func (d *currentopCollector) collect(ch chan<- prometheus.Metric) { inprog, ok := r["inprog"].(primitive.A) if !ok { - logger.Errorf("Invalid type primitive.A assertion for 'inprog': %T", r["inprog"]) + logger.Error(fmt.Sprintf("Invalid type primitive.A assertion for 'inprog': %T", r["inprog"])) ch <- prometheus.NewInvalidMetric(prometheus.NewInvalidDesc(ErrInvalidOrMissingInprogEntry), ErrInvalidOrMissingInprogEntry) } @@ -115,33 +116,33 @@ func (d *currentopCollector) collect(ch chan<- prometheus.Metric) { bsonMapElement, ok := bsonMap.(primitive.M) if !ok { - logger.Errorf("Invalid type primitive.M assertion for bsonMap: %T", bsonMapElement) + logger.Error(fmt.Sprintf("Invalid type primitive.M assertion for bsonMap: %T", bsonMapElement)) continue } opid, ok := bsonMapElement["opid"].(int32) if !ok { - logger.Errorf("Invalid type int32 assertion for 'opid': %T", bsonMapElement) + logger.Error(fmt.Sprintf("Invalid type int32 assertion for 'opid': %T", bsonMapElement)) continue } namespace, ok := bsonMapElement["ns"].(string) if !ok { - logger.Errorf("Invalid type string assertion for 'ns': %T", bsonMapElement) + logger.Error(fmt.Sprintf("Invalid type string assertion for 'ns': %T", bsonMapElement)) continue } db, collection := splitNamespace(namespace) op, ok := bsonMapElement["op"].(string) if !ok { - logger.Errorf("Invalid type string assertion for 'op': %T", bsonMapElement) + logger.Error(fmt.Sprintf("Invalid type string assertion for 'op': %T", bsonMapElement)) continue } desc, ok := bsonMapElement["desc"].(string) if !ok { - logger.Errorf("Invalid type string assertion for 'desc': %T", bsonMapElement) + logger.Error(fmt.Sprintf("Invalid type string assertion for 'desc': %T", bsonMapElement)) continue } microsecs_running, ok := bsonMapElement["microsecs_running"].(int64) if !ok { - logger.Errorf("Invalid type int64 assertion for 'microsecs_running': %T", bsonMapElement) + logger.Error(fmt.Sprintf("Invalid type int64 assertion for 'microsecs_running': %T", bsonMapElement)) continue } diff --git a/exporter/currentop_collector_test.go b/exporter/currentop_collector_test.go index 72168b648..b4f5b66fb 100644 --- a/exporter/currentop_collector_test.go +++ b/exporter/currentop_collector_test.go @@ -22,7 +22,7 @@ import ( "time" "github.com/prometheus/client_golang/prometheus/testutil" - "github.com/sirupsen/logrus" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/assert" "go.mongodb.org/mongo-driver/bson" @@ -60,7 +60,7 @@ func TestCurrentopCollector(t *testing.T) { ti := labelsGetterMock{} st := "0s" - c := newCurrentopCollector(ctx, client, logrus.New(), false, ti, st) + c := newCurrentopCollector(ctx, client, promslog.New(&promslog.Config{}), false, ti, st) // Filter metrics by reason: // 1. The result will be different on different hardware diff --git a/exporter/dbstats_collector.go b/exporter/dbstats_collector.go index b43141456..136ad975f 100644 --- a/exporter/dbstats_collector.go +++ b/exporter/dbstats_collector.go @@ -17,9 +17,9 @@ package exporter import ( "context" + "log/slog" "github.com/prometheus/client_golang/prometheus" - "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" ) @@ -37,10 +37,10 @@ type dbstatsCollector struct { } // newDBStatsCollector creates a collector for statistics on database storage. -func newDBStatsCollector(ctx context.Context, client *mongo.Client, logger *logrus.Logger, compatible bool, topology labelsGetter, databaseRegex []string, freeStorage bool) *dbstatsCollector { +func newDBStatsCollector(ctx context.Context, client *mongo.Client, logger *slog.Logger, compatible bool, topology labelsGetter, databaseRegex []string, freeStorage bool) *dbstatsCollector { return &dbstatsCollector{ ctx: ctx, - base: newBaseCollector(client, logger.WithFields(logrus.Fields{"collector": "dbstats"})), + base: newBaseCollector(client, logger.With("collector", "dbstats")), compatibleMode: compatible, topologyInfo: topology, @@ -67,12 +67,12 @@ func (d *dbstatsCollector) collect(ch chan<- prometheus.Metric) { dbNames, err := databases(d.ctx, client, d.databaseFilter, nil) if err != nil { - logger.Errorf("Failed to get database names: %s", err) + logger.Error("Failed to get database names", "error", err) return } - logger.Debugf("getting stats for databases: %v", dbNames) + logger.Debug("getting stats for databases", "databases", dbNames) for _, db := range dbNames { var dbStats bson.M var cmd bson.D @@ -84,12 +84,12 @@ func (d *dbstatsCollector) collect(ch chan<- prometheus.Metric) { r := client.Database(db).RunCommand(d.ctx, cmd) err := r.Decode(&dbStats) if err != nil { - logger.Errorf("Failed to get $dbstats for database %s: %s", db, err) + logger.Error("Failed to get $dbstats for database", "database", db, "error", err) continue } - logger.Debugf("$dbStats metrics for %s", db) + logger.Debug("$dbStats metrics for", "database", db) debugResult(logger, dbStats) prefix := "dbstats" diff --git a/exporter/dbstats_collector_test.go b/exporter/dbstats_collector_test.go index 8b01d8bcf..eda94008d 100644 --- a/exporter/dbstats_collector_test.go +++ b/exporter/dbstats_collector_test.go @@ -23,7 +23,7 @@ import ( "time" "github.com/prometheus/client_golang/prometheus/testutil" - "github.com/sirupsen/logrus" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/assert" "go.mongodb.org/mongo-driver/bson" @@ -58,7 +58,7 @@ func TestDBStatsCollector(t *testing.T) { ti := labelsGetterMock{} - logger := logrus.New() + logger := promslog.New(&promslog.Config{}) c := newDBStatsCollector(ctx, client, logger, false, ti, []string{dbName}, false) expected := strings.NewReader(` # HELP mongodb_dbstats_collections dbstats.collections diff --git a/exporter/debug.go b/exporter/debug.go index 3e13979fc..918e50cea 100644 --- a/exporter/debug.go +++ b/exporter/debug.go @@ -16,25 +16,25 @@ package exporter import ( + "context" "encoding/json" "fmt" + "log/slog" "os" - - "github.com/sirupsen/logrus" ) -func debugResult(log *logrus.Entry, m interface{}) { - if !log.Logger.IsLevelEnabled(logrus.DebugLevel) { +func debugResult(log *slog.Logger, m interface{}) { + if !log.Enabled(context.TODO(), slog.LevelDebug) { return } debugStr, err := json.MarshalIndent(m, "", " ") if err != nil { - log.Errorf("cannot marshal struct for debug: %s", err) + log.Error("cannot marshal struct for debug", "error", err) return } - // don't use logrus because: + // don't use the passed-in logger because: // 1. It will escape new lines and " making it harder to read and to use // 2. It will add timestamp // 3. This way is easier to copy/paste to put the info in a ticket diff --git a/exporter/debug_test.go b/exporter/debug_test.go index edb57671b..e8b042bd2 100644 --- a/exporter/debug_test.go +++ b/exporter/debug_test.go @@ -20,14 +20,16 @@ import ( "os" "testing" - "github.com/sirupsen/logrus" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "go.mongodb.org/mongo-driver/bson" ) func TestDebug(t *testing.T) { - log := logrus.New() - log.SetLevel(logrus.DebugLevel) + logLevel := promslog.NewLevel() + err := logLevel.Set("debug") + require.NoError(t, err) olderr := os.Stderr r, w, _ := os.Pipe() @@ -35,10 +37,13 @@ func TestDebug(t *testing.T) { os.Stderr = w defer func() { os.Stderr = olderr - logrus.SetLevel(logrus.ErrorLevel) + _ = logLevel.Set("error") }() - log.Out = w + log := promslog.New(&promslog.Config{ + Level: logLevel, + Writer: w, + }) m := bson.M{ "f1": 1, @@ -55,7 +60,7 @@ func TestDebug(t *testing.T) { } }` + "\n" - debugResult(log.WithField("component", "test"), m) + debugResult(log.With("component", "test"), m) assert.NoError(t, w.Close()) out, _ := io.ReadAll(r) diff --git a/exporter/diagnostic_data_collector.go b/exporter/diagnostic_data_collector.go index e4b19fe00..147e19ae4 100644 --- a/exporter/diagnostic_data_collector.go +++ b/exporter/diagnostic_data_collector.go @@ -17,10 +17,10 @@ package exporter import ( "context" + "log/slog" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" - "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" ) @@ -42,22 +42,19 @@ type diagnosticDataCollector struct { } // newDiagnosticDataCollector creates a collector for diagnostic information. -func newDiagnosticDataCollector(ctx context.Context, client *mongo.Client, logger *logrus.Logger, compatible bool, topology labelsGetter, buildInfo buildInfo) *diagnosticDataCollector { +func newDiagnosticDataCollector(ctx context.Context, client *mongo.Client, logger *slog.Logger, compatible bool, topology labelsGetter, buildInfo buildInfo) *diagnosticDataCollector { + logger = logger.With("component", "diagnosticDataCollector") nodeType, err := getNodeType(ctx, client) if err != nil { - logger.WithFields(logrus.Fields{ - "component": "diagnosticDataCollector", - }).Errorf("Cannot get node type: %s", err) + logger.Error("Cannot get node type", "error", err) } if nodeType == typeArbiter { - logger.WithFields(logrus.Fields{ - "component": "diagnosticDataCollector", - }).Warn("some metrics might be unavailable on arbiter nodes") + logger.Warn("some metrics might be unavailable on arbiter nodes") } return &diagnosticDataCollector{ ctx: ctx, - base: newBaseCollector(client, logger.WithFields(logrus.Fields{"collector": "diagnostic_data"})), + base: newBaseCollector(client, logger.With("collector", "diagnostic_data")), buildInfo: buildInfo, @@ -84,9 +81,7 @@ func (d *diagnosticDataCollector) collect(ch chan<- prometheus.Metric) { nodeType, err := getNodeType(d.ctx, client) if err != nil { - logger.WithFields(logrus.Fields{ - "component": "diagnosticDataCollector", - }).Errorf("Cannot get node type: %s", err) + logger.Error("Cannot get node type", "error", err) } var metrics []prometheus.Metric @@ -94,11 +89,11 @@ func (d *diagnosticDataCollector) collect(ch chan<- prometheus.Metric) { res := client.Database("admin").RunCommand(d.ctx, cmd) if res.Err() != nil { if nodeType != typeArbiter { - logger.Warnf("failed to run command: getDiagnosticData, some metrics might be unavailable %s", res.Err()) + logger.Warn("failed to run command: getDiagnosticData, some metrics might be unavailable", "error", res.Err()) } } else { if err := res.Decode(&m); err != nil { - logger.Errorf("cannot run getDiagnosticData: %s", err) + logger.Error("cannot run getDiagnosticData", "error", err) return } @@ -110,7 +105,7 @@ func (d *diagnosticDataCollector) collect(ch chan<- prometheus.Metric) { m, ok = m["data"].(bson.M) if !ok { err = errors.Wrapf(errUnexpectedDataType, "%T for data field", m["data"]) - logger.Errorf("cannot decode getDiagnosticData: %s", err) + logger.Error("cannot decode getDiagnosticData", "error", err) } logger.Debug("getDiagnosticData result") @@ -136,7 +131,7 @@ func (d *diagnosticDataCollector) collect(ch chan<- prometheus.Metric) { securityMetric, err := d.getSecurityMetricFromLineOptions(client) if err != nil { - logger.Errorf("failed to run command: getCmdLineOptions: %s", err) + logger.Error("failed to run command: getCmdLineOptions", "error", err) } else if securityMetric != nil { metrics = append(metrics, securityMetric) } diff --git a/exporter/diagnostic_data_collector_test.go b/exporter/diagnostic_data_collector_test.go index c3a618681..4098a4db1 100644 --- a/exporter/diagnostic_data_collector_test.go +++ b/exporter/diagnostic_data_collector_test.go @@ -28,8 +28,7 @@ import ( "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/testutil" - "github.com/sirupsen/logrus" - logrustest "github.com/sirupsen/logrus/hooks/test" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.mongodb.org/mongo-driver/bson" @@ -43,10 +42,10 @@ func TestDiagnosticDataCollector(t *testing.T) { defer cancel() client := tu.DefaultTestClient(ctx, t) - logger := logrus.New() + logger := promslog.New(&promslog.Config{}) ti := labelsGetterMock{} - dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, logger.WithField("component", "test")) + dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, logger.With("component", "test")) require.NoError(t, err) c := newDiagnosticDataCollector(ctx, client, logger, false, ti, dbBuildInfo) @@ -190,10 +189,10 @@ func TestCollectorWithCompatibleMode(t *testing.T) { port, err := tu.PortForContainer(tt.containerName) require.NoError(t, err) client := tu.TestClient(ctx, port, t) - logger := logrus.New() + logger := promslog.New(&promslog.Config{}) ti := labelsGetterMock{} - dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, logger.WithField("component", "test")) + dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, logger.With("component", "test")) require.NoError(t, err) c := newDiagnosticDataCollector(ctx, client, logger, true, ti, dbBuildInfo) @@ -210,11 +209,15 @@ func TestAllDiagnosticDataCollectorMetrics(t *testing.T) { client := tu.DefaultTestClient(ctx, t) - logger := logrus.New() - logger.SetLevel(logrus.DebugLevel) + logLevel := promslog.NewLevel() + err := logLevel.Set("debug") + require.NoError(t, err) + logger := promslog.New(&promslog.Config{ + Level: logLevel, + }) ti := newTopologyInfo(ctx, client, logger) - dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, logger.WithField("component", "test")) + dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, logger.With("component", "test")) require.NoError(t, err) c := newDiagnosticDataCollector(ctx, client, logger, true, ti, dbBuildInfo) @@ -292,10 +295,10 @@ func TestDiagnosticDataErrors(t *testing.T) { require.NoError(t, err) client := tu.TestClient(ctx, port, t) - logger, hook := logrustest.NewNullLogger() + logger := promslog.New(&promslog.Config{}) ti := newTopologyInfo(ctx, client, logger) - dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, logger.WithField("component", "test")) + dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, logger.With("component", "test")) require.NoError(t, err) c := newDiagnosticDataCollector(ctx, client, logger, true, ti, dbBuildInfo) @@ -305,7 +308,7 @@ func TestDiagnosticDataErrors(t *testing.T) { require.NoError(t, err) _ = helpers.CollectMetrics(c) - var errorLogs []log + /*var errorLogs []log for _, entry := range hook.Entries { if entry.Level == logrus.ErrorLevel || entry.Level == logrus.WarnLevel { errorLogs = append(errorLogs, log{ @@ -325,7 +328,7 @@ func TestDiagnosticDataErrors(t *testing.T) { "'%s' has no prefix: '%s'", hook.LastEntry().Message, tc.expectedMessage) - } + }*/ }) } } @@ -335,10 +338,10 @@ func TestContextTimeout(t *testing.T) { client := tu.DefaultTestClient(ctx, t) - logger := logrus.New() + logger := promslog.New(&promslog.Config{}) ti := newTopologyInfo(ctx, client, logger) - dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, logger.WithField("component", "test")) + dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, logger.With("component", "test")) require.NoError(t, err) dbCount := 100 @@ -431,12 +434,11 @@ func TestDisconnectedDiagnosticDataCollector(t *testing.T) { err := client.Disconnect(ctx) assert.NoError(t, err) - logger := logrus.New() - logger.Out = io.Discard // disable logs in tests + logger := promslog.NewNopLogger() ti := labelsGetterMock{} - dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, logger.WithField("component", "test")) + dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, logger.With("component", "test")) require.Error(t, err) c := newDiagnosticDataCollector(ctx, client, logger, true, ti, dbBuildInfo) diff --git a/exporter/encryption_info_test.go b/exporter/encryption_info_test.go index 8f50bedd6..b6ef2fb6b 100644 --- a/exporter/encryption_info_test.go +++ b/exporter/encryption_info_test.go @@ -18,13 +18,12 @@ package exporter import ( "context" "fmt" - "io" "strings" "testing" "time" "github.com/prometheus/client_golang/prometheus/testutil" - "github.com/sirupsen/logrus" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -46,12 +45,11 @@ func TestGetEncryptionInfo(t *testing.T) { err := client.Disconnect(ctx) assert.NoError(t, err) }) - logger := logrus.New() - logger.Out = io.Discard // disable logs in tests + logger := promslog.NewNopLogger() ti := labelsGetterMock{} - dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, logger.WithField("component", "test")) + dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, logger.With("component", "test")) require.NoError(t, err) c := newDiagnosticDataCollector(ctx, client, logger, true, ti, dbBuildInfo) diff --git a/exporter/exporter.go b/exporter/exporter.go index 5821829cd..b458c2113 100644 --- a/exporter/exporter.go +++ b/exporter/exporter.go @@ -19,6 +19,7 @@ package exporter import ( "context" "fmt" + "log/slog" "net/http" _ "net/http/pprof" "strconv" @@ -27,7 +28,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/sirupsen/logrus" + "github.com/prometheus/common/promslog" "go.mongodb.org/mongo-driver/mongo" "github.com/percona/mongodb_exporter/exporter/dsn_fix" @@ -37,7 +38,7 @@ import ( type Exporter struct { client *mongo.Client clientMu sync.Mutex - logger *logrus.Logger + logger *slog.Logger opts *Opts lock *sync.Mutex totalCollectionsCount int @@ -79,7 +80,7 @@ type Opts struct { CurrentOpSlowTime string ProfileTimeTS int - Logger *logrus.Logger + Logger *slog.Logger URI string NodeName string @@ -101,7 +102,8 @@ func New(opts *Opts) *Exporter { } if opts.Logger == nil { - opts.Logger = logrus.New() + promslogConfig := &promslog.Config{} + opts.Logger = promslog.New(promslogConfig) } ctx := context.Background() @@ -116,7 +118,7 @@ func New(opts *Opts) *Exporter { go func() { _, err := exp.getClient(ctx) if err != nil { - exp.logger.Errorf("Cannot connect to MongoDB: %v", err) + exp.logger.Error("Cannot connect to MongoDB", "error", err) } }() @@ -135,12 +137,12 @@ func (e *Exporter) makeRegistry(ctx context.Context, client *mongo.Client, topol nodeType, err := getNodeType(ctx, client) if err != nil { - e.logger.Errorf("Registry - Cannot get node type : %s", err) + e.logger.Error("Registry - Cannot get node type", "error", err) } - dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, e.logger.WithField("component", "buildInfo")) + dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, e.logger.With("component", "buildInfo")) if err != nil { - e.logger.Warnf("Registry - Cannot get MongoDB buildInfo: %s", err) + e.logger.Warn("Registry - Cannot get MongoDB buildInfo", "error", err) } gc := newGeneralCollector(ctx, client, nodeType, e.opts.Logger) @@ -314,7 +316,7 @@ func (e *Exporter) Handler() http.Handler { client, err = e.getClient(ctx) if err != nil { - e.logger.Errorf("Cannot connect to MongoDB: %v", err) + e.logger.Error("Cannot connect to MongoDB", "error", err) } if client != nil && e.getTotalCollectionsCount() <= 0 { @@ -332,7 +334,7 @@ func (e *Exporter) Handler() http.Handler { if client != nil { err := client.Disconnect(ctx) if err != nil { - e.logger.Errorf("Cannot disconnect client: %v", err) + e.logger.Error("Cannot disconnect client", "error", err) } } }() @@ -361,7 +363,7 @@ func (e *Exporter) Handler() http.Handler { // Delegate http serving to Prometheus client library, which will call collector.Collect. h := promhttp.HandlerFor(gatherers, promhttp.HandlerOpts{ ErrorHandling: promhttp.ContinueOnError, - ErrorLog: e.logger, + // ErrorLog: e.logger, // todo(idoqo): check with prometheus/client_golang about the interface here }) h.ServeHTTP(w, r) diff --git a/exporter/exporter_test.go b/exporter/exporter_test.go index a00ca19d8..11d58c8a1 100644 --- a/exporter/exporter_test.go +++ b/exporter/exporter_test.go @@ -28,7 +28,7 @@ import ( "testing" "github.com/prometheus/client_golang/prometheus/testutil" - "github.com/sirupsen/logrus" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/assert" "github.com/percona/mongodb_exporter/internal/tu" @@ -78,7 +78,7 @@ func TestConnect(t *testing.T) { //nolint:dupl t.Run("Test per-request connection", func(t *testing.T) { - log := logrus.New() + log := promslog.New(&promslog.Config{}) exporterOpts := &Opts{ Logger: log, @@ -112,7 +112,7 @@ func TestConnect(t *testing.T) { //nolint:dupl t.Run("Test global connection", func(t *testing.T) { - log := logrus.New() + log := promslog.New(&promslog.Config{}) exporterOpts := &Opts{ Logger: log, @@ -151,7 +151,7 @@ func TestConnect(t *testing.T) { // replSetGetStatusCollector and it should return false since it wasn't registered. // Note: Two Collectors are considered equal if their Describe method yields the // same set of descriptors. -// unregister will try to Describe to get the descriptors set and we are using +// unregister will try to Describe to get the descriptors set, and we are using // DescribeByCollect so, in the logs, you will see an error: // msg="cannot get replSetGetStatus: replSetGetStatus is not supported through mongos" // This is correct. Collect is being executed to Describe and Unregister. @@ -175,7 +175,7 @@ func TestMongoS(t *testing.T) { for _, test := range tests { exporterOpts := &Opts{ - Logger: logrus.New(), + Logger: promslog.New(&promslog.Config{}), URI: fmt.Sprintf("mongodb://%s/admin", net.JoinHostPort(hostname, test.port)), DirectConnect: true, GlobalConnPool: false, @@ -219,7 +219,7 @@ func TestMongoUpMetric(t *testing.T) { for _, tc := range testCases { t.Run(tc.clusterRole+"/"+tc.URI, func(t *testing.T) { exporterOpts := &Opts{ - Logger: logrus.New(), + Logger: promslog.New(&promslog.Config{}), URI: tc.URI, ConnectTimeoutMS: 200, DirectConnect: true, diff --git a/exporter/feature_compatibility_version_collector.go b/exporter/feature_compatibility_version_collector.go index 871544c6c..c92b2a32f 100644 --- a/exporter/feature_compatibility_version_collector.go +++ b/exporter/feature_compatibility_version_collector.go @@ -18,10 +18,10 @@ package exporter import ( "context" "fmt" + "log/slog" "strconv" "github.com/prometheus/client_golang/prometheus" - "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" ) @@ -32,10 +32,10 @@ type featureCompatibilityCollector struct { } // newProfileCollector creates a collector for being processed queries. -func newFeatureCompatibilityCollector(ctx context.Context, client *mongo.Client, logger *logrus.Logger) *featureCompatibilityCollector { +func newFeatureCompatibilityCollector(ctx context.Context, client *mongo.Client, logger *slog.Logger) *featureCompatibilityCollector { return &featureCompatibilityCollector{ ctx: ctx, - base: newBaseCollector(client, logger.WithFields(logrus.Fields{"collector": "featureCompatibility"})), + base: newBaseCollector(client, logger.With("collector", "featureCompatibility")), } } @@ -59,7 +59,7 @@ func (d *featureCompatibilityCollector) collect(ch chan<- prometheus.Metric) { m := make(map[string]interface{}) if err := res.Decode(&m); err != nil { - d.base.logger.Errorf("Failed to decode featureCompatibilityVersion: %v", err) + d.base.logger.Error("Failed to decode featureCompatibilityVersion", "error", err) ch <- prometheus.NewInvalidMetric(prometheus.NewInvalidDesc(err), err) return } @@ -69,7 +69,7 @@ func (d *featureCompatibilityCollector) collect(ch chan<- prometheus.Metric) { versionString := fmt.Sprintf("%v", rawValue) version, err := strconv.ParseFloat(versionString, 64) if err != nil { - d.base.logger.Errorf("Failed to parse featureCompatibilityVersion: %v", err) + d.base.logger.Error("Failed to parse featureCompatibilityVersion", "error", err) ch <- prometheus.NewInvalidMetric(prometheus.NewInvalidDesc(err), err) return } diff --git a/exporter/feature_compatibility_version_collector_test.go b/exporter/feature_compatibility_version_collector_test.go index df2e9e264..608dd4386 100644 --- a/exporter/feature_compatibility_version_collector_test.go +++ b/exporter/feature_compatibility_version_collector_test.go @@ -24,7 +24,7 @@ import ( "github.com/hashicorp/go-version" "github.com/prometheus/client_golang/prometheus/testutil" - "github.com/sirupsen/logrus" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -41,7 +41,7 @@ func TestFCVCollector(t *testing.T) { database.Drop(ctx) //nolint:errcheck defer database.Drop(ctx) //nolint:errcheck - c := newFeatureCompatibilityCollector(ctx, client, logrus.New()) + c := newFeatureCompatibilityCollector(ctx, client, promslog.New(&promslog.Config{})) sversion, _ := getMongoDBVersionInfo(t, "mongo-1-1") diff --git a/exporter/general_collector.go b/exporter/general_collector.go index ebe9f3f4f..86bae0e1a 100644 --- a/exporter/general_collector.go +++ b/exporter/general_collector.go @@ -17,9 +17,9 @@ package exporter import ( "context" + "log/slog" "github.com/prometheus/client_golang/prometheus" - "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/readpref" ) @@ -32,11 +32,11 @@ type generalCollector struct { } // newGeneralCollector creates a collector for MongoDB connectivity status. -func newGeneralCollector(ctx context.Context, client *mongo.Client, nodeType mongoDBNodeType, logger *logrus.Logger) *generalCollector { +func newGeneralCollector(ctx context.Context, client *mongo.Client, nodeType mongoDBNodeType, logger *slog.Logger) *generalCollector { return &generalCollector{ ctx: ctx, nodeType: nodeType, - base: newBaseCollector(client, logger.WithFields(logrus.Fields{"collector": "general"})), + base: newBaseCollector(client, logger.With("collector", "general")), } } @@ -53,7 +53,7 @@ func (d *generalCollector) collect(ch chan<- prometheus.Metric) { ch <- mongodbUpMetric(d.ctx, d.base.client, d.nodeType, d.base.logger) } -func mongodbUpMetric(ctx context.Context, client *mongo.Client, nodeType mongoDBNodeType, log *logrus.Entry) prometheus.Metric { //nolint:ireturn +func mongodbUpMetric(ctx context.Context, client *mongo.Client, nodeType mongoDBNodeType, log *slog.Logger) prometheus.Metric { //nolint:ireturn var value float64 var clusterRole mongoDBNodeType @@ -61,7 +61,7 @@ func mongodbUpMetric(ctx context.Context, client *mongo.Client, nodeType mongoDB if err := client.Ping(ctx, readpref.PrimaryPreferred()); err == nil { value = 1 } else { - log.Errorf("error while checking mongodb connection: %s. mongo_up is set to 0", err.Error()) + log.Error("error while checking mongodb connection, mongo_up will be set to 0", "error", err.Error()) } switch nodeType { //nolint:exhaustive case typeShardServer: diff --git a/exporter/general_collector_test.go b/exporter/general_collector_test.go index f373a45f7..04e859183 100644 --- a/exporter/general_collector_test.go +++ b/exporter/general_collector_test.go @@ -22,7 +22,7 @@ import ( "time" "github.com/prometheus/client_golang/prometheus/testutil" - "github.com/sirupsen/logrus" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -38,7 +38,7 @@ func TestGeneralCollector(t *testing.T) { client := tu.DefaultTestClient(ctx, t) nodeType, _ := getNodeType(ctx, client) - c := newGeneralCollector(ctx, client, nodeType, logrus.New()) + c := newGeneralCollector(ctx, client, nodeType, promslog.New(&promslog.Config{})) filter := []string{ "collector_scrape_time_ms", @@ -82,7 +82,7 @@ func TestGeneralCollector(t *testing.T) { client := tu.TestClient(ctx, port, t) nodeType, _ := getNodeType(ctx, client) - c := newGeneralCollector(ctx, client, nodeType, logrus.New()) + c := newGeneralCollector(ctx, client, nodeType, promslog.New(&promslog.Config{})) filter := []string{ "collector_scrape_time_ms", diff --git a/exporter/indexstats_collector.go b/exporter/indexstats_collector.go index 25d65c553..e2e6f0abc 100644 --- a/exporter/indexstats_collector.go +++ b/exporter/indexstats_collector.go @@ -18,10 +18,10 @@ package exporter import ( "context" "fmt" + "log/slog" "strings" "github.com/prometheus/client_golang/prometheus" - "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" ) @@ -38,10 +38,10 @@ type indexstatsCollector struct { } // newIndexStatsCollector creates a collector for statistics on index usage. -func newIndexStatsCollector(ctx context.Context, client *mongo.Client, logger *logrus.Logger, discovery, overrideDescendingIndex bool, topology labelsGetter, collections []string) *indexstatsCollector { +func newIndexStatsCollector(ctx context.Context, client *mongo.Client, logger *slog.Logger, discovery, overrideDescendingIndex bool, topology labelsGetter, collections []string) *indexstatsCollector { return &indexstatsCollector{ ctx: ctx, - base: newBaseCollector(client, logger.WithFields(logrus.Fields{"collector": "indexstats"})), + base: newBaseCollector(client, logger.With("collector", "indexstats")), discoveringMode: discovery, topologyInfo: topology, @@ -69,7 +69,7 @@ func (d *indexstatsCollector) collect(ch chan<- prometheus.Metric) { if d.discoveringMode { onlyCollectionsNamespaces, err := listAllCollections(d.ctx, client, d.collections, systemDBs, true) if err != nil { - logger.Errorf("cannot auto discover databases and collections: %s", err.Error()) + logger.Error("cannot auto discover databases and collections", "error", err.Error()) return } @@ -79,7 +79,7 @@ func (d *indexstatsCollector) collect(ch chan<- prometheus.Metric) { var err error collections, err = checkNamespacesForViews(d.ctx, client, d.collections) if err != nil { - logger.Errorf("cannot list collections: %s", err.Error()) + logger.Error("cannot list collections", "error", err.Error()) return } @@ -105,19 +105,19 @@ func (d *indexstatsCollector) collect(ch chan<- prometheus.Metric) { cursor, err := client.Database(database).Collection(collection).Aggregate(d.ctx, mongo.Pipeline{aggregation}) if err != nil { - logger.Errorf("cannot get $indexStats cursor for collection %s.%s: %s", database, collection, err) + logger.Error("cannot get $indexStats cursor for collection", "database", database, "collection", collection, "error", err) continue } var stats []bson.M if err = cursor.All(d.ctx, &stats); err != nil { - logger.Errorf("cannot get $indexStats for collection %s.%s: %s", database, collection, err) + logger.Error("cannot get $indexStats for collection", "database", database, "collection", collection, "error", err) continue } - d.base.logger.Debugf("indexStats for %s.%s", database, collection) + d.base.logger.Debug("indexStats", "database", database, "collection", collection) debugResult(d.base.logger, stats) diff --git a/exporter/indexstats_collector_test.go b/exporter/indexstats_collector_test.go index 1669649d7..d53a2cfdd 100644 --- a/exporter/indexstats_collector_test.go +++ b/exporter/indexstats_collector_test.go @@ -24,7 +24,7 @@ import ( "github.com/AlekSi/pointer" "github.com/prometheus/client_golang/prometheus/testutil" - "github.com/sirupsen/logrus" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/assert" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" @@ -64,7 +64,7 @@ func TestIndexStatsCollector(t *testing.T) { } collection := []string{"testdb.testcol_00", "testdb.testcol_01", "testdb.testcol_02"} - c := newIndexStatsCollector(ctx, client, logrus.New(), false, true, ti, collection) + c := newIndexStatsCollector(ctx, client, promslog.New(&promslog.Config{}), false, true, ti, collection) // The last \n at the end of this string is important expected := strings.NewReader(` @@ -114,7 +114,7 @@ func TestDescendingIndexOverride(t *testing.T) { } collection := []string{"testdb.testcol_00", "testdb.testcol_01", "testdb.testcol_02"} - c := newIndexStatsCollector(ctx, client, logrus.New(), false, true, ti, collection) + c := newIndexStatsCollector(ctx, client, promslog.New(&promslog.Config{}), false, true, ti, collection) // The last \n at the end of this string is important expected := strings.NewReader(` diff --git a/exporter/multi_target_test.go b/exporter/multi_target_test.go index 57a68b376..8278591d9 100644 --- a/exporter/multi_target_test.go +++ b/exporter/multi_target_test.go @@ -24,7 +24,7 @@ import ( "regexp" "testing" - "github.com/sirupsen/logrus" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/assert" "github.com/percona/mongodb_exporter/internal/tu" @@ -59,7 +59,7 @@ func TestMultiTarget(t *testing.T) { for i, opt := range opts { exporters[i] = New(opt) } - log := logrus.New() + log := promslog.New(&promslog.Config{}) serverMap := buildServerMap(exporters, log) expected := []string{ @@ -112,7 +112,7 @@ func TestOverallHandler(t *testing.T) { } exporters := make([]*Exporter, len(opts)) - logger := logrus.New() + logger := promslog.New(&promslog.Config{}) for i, opt := range opts { exporters[i] = New(opt) diff --git a/exporter/pbm_collector.go b/exporter/pbm_collector.go index f1b4bce50..1babddbf8 100644 --- a/exporter/pbm_collector.go +++ b/exporter/pbm_collector.go @@ -17,13 +17,13 @@ package exporter import ( "context" + "log/slog" "strings" "time" "github.com/percona/percona-backup-mongodb/sdk" "github.com/percona/percona-backup-mongodb/sdk/cli" "github.com/prometheus/client_golang/prometheus" - "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/mongo" "github.com/percona/mongodb_exporter/internal/util" @@ -55,7 +55,7 @@ func createPBMMetric(name, help string, value float64, labels map[string]string) return prometheus.MustNewConstMetric(d, prometheus.GaugeValue, value) } -func newPbmCollector(ctx context.Context, client *mongo.Client, mongoURI string, logger *logrus.Logger) *pbmCollector { +func newPbmCollector(ctx context.Context, client *mongo.Client, mongoURI string, logger *slog.Logger) *pbmCollector { // we can't get details of other cluster members from PBM if directConnection is set to true, // we re-write it if that option is set (e.g from PMM). if strings.Contains(mongoURI, "directConnection=true") { @@ -65,7 +65,7 @@ func newPbmCollector(ctx context.Context, client *mongo.Client, mongoURI string, return &pbmCollector{ ctx: ctx, mongoURI: mongoURI, - base: newBaseCollector(client, logger.WithFields(logrus.Fields{"collector": "pbm"})), + base: newBaseCollector(client, logger.With("collector", "pbm")), } } @@ -86,19 +86,19 @@ func (p *pbmCollector) collect(ch chan<- prometheus.Metric) { pbmEnabledMetric := 0 pbmClient, err := sdk.NewClient(p.ctx, p.mongoURI) if err != nil { - logger.Warnf("failed to create PBM client: %s", err.Error()) + logger.Warn("failed to create PBM client", "error", err.Error()) return } defer func() { err := pbmClient.Close(p.ctx) if err != nil { - logger.Errorf("failed to close PBM client: %v", err) + logger.Error("failed to close PBM client", "error", err) } }() pbmConfig, err := pbmClient.GetConfig(p.ctx) if err != nil { - logger.Infof("failed to get PBM configuration: %s", err.Error()) + logger.Info("failed to get PBM configuration", "error", err.Error()) } if pbmConfig != nil { @@ -126,16 +126,16 @@ func (p *pbmCollector) collect(ch chan<- prometheus.Metric) { } } -func (p *pbmCollector) pbmAgentMetrics(ctx context.Context, pbmClient *sdk.Client, l *logrus.Entry) []prometheus.Metric { +func (p *pbmCollector) pbmAgentMetrics(ctx context.Context, pbmClient *sdk.Client, l *slog.Logger) []prometheus.Metric { currentNode, err := util.MyRole(ctx, p.base.client) if err != nil { - l.Errorf("failed to get current node info: %s", err.Error()) + l.Error("failed to get current node info", "error", err.Error()) return nil } clusterStatus, err := cli.ClusterStatus(ctx, pbmClient, cli.RSConfGetter(p.mongoURI)) if err != nil { - l.Errorf("failed to get cluster status: %s", err.Error()) + l.Error("failed to get cluster status", "error", err.Error()) return nil } @@ -174,10 +174,10 @@ func (p *pbmCollector) pbmAgentMetrics(ctx context.Context, pbmClient *sdk.Clien return metrics } -func (p *pbmCollector) pbmBackupsMetrics(ctx context.Context, pbmClient *sdk.Client, l *logrus.Entry) []prometheus.Metric { +func (p *pbmCollector) pbmBackupsMetrics(ctx context.Context, pbmClient *sdk.Client, l *slog.Logger) []prometheus.Metric { backupsList, err := pbmClient.GetAllBackups(ctx) if err != nil { - l.Errorf("failed to get PBM backup list: %s", err.Error()) + l.Error("failed to get PBM backup list", "error", err.Error()) return nil } diff --git a/exporter/pbm_collector_test.go b/exporter/pbm_collector_test.go index 5a03599b3..d0033db13 100644 --- a/exporter/pbm_collector_test.go +++ b/exporter/pbm_collector_test.go @@ -22,7 +22,7 @@ import ( "time" "github.com/prometheus/client_golang/prometheus/testutil" - "github.com/sirupsen/logrus" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -41,7 +41,7 @@ func TestPBMCollector(t *testing.T) { client := tu.TestClient(ctx, port, t) mongoURI := "mongodb://admin:admin@127.0.0.1:17006/?connectTimeoutMS=1000&directConnection=true&serverSelectionTimeoutMS=1000" //nolint:gosec - c := newPbmCollector(ctx, client, mongoURI, logrus.New()) + c := newPbmCollector(ctx, client, mongoURI, promslog.New(&promslog.Config{})) t.Run("pbm configured metric", func(t *testing.T) { filter := []string{ diff --git a/exporter/profile_status_collector.go b/exporter/profile_status_collector.go index 79c76bdd5..37325f3fc 100644 --- a/exporter/profile_status_collector.go +++ b/exporter/profile_status_collector.go @@ -17,10 +17,10 @@ package exporter import ( "context" + "log/slog" "time" "github.com/prometheus/client_golang/prometheus" - "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" @@ -35,12 +35,12 @@ type profileCollector struct { } // newProfileCollector creates a collector for being processed queries. -func newProfileCollector(ctx context.Context, client *mongo.Client, logger *logrus.Logger, +func newProfileCollector(ctx context.Context, client *mongo.Client, logger *slog.Logger, compatible bool, topology labelsGetter, profileTimeTS int, ) *profileCollector { return &profileCollector{ ctx: ctx, - base: newBaseCollector(client, logger.WithFields(logrus.Fields{"collector": "profile"})), + base: newBaseCollector(client, logger.With("collector", "profile")), compatibleMode: compatible, topologyInfo: topology, profiletimets: profileTimeTS, @@ -64,7 +64,7 @@ func (d *profileCollector) collect(ch chan<- prometheus.Metric) { databases, err := databases(d.ctx, client, nil, nil) if err != nil { - logger.Warnf("cannot get databases: %s", err) + logger.Warn("cannot get databases", "error", err) return } @@ -78,7 +78,7 @@ func (d *profileCollector) collect(ch chan<- prometheus.Metric) { for _, db := range databases { res, err := client.Database(db).Collection("system.profile").CountDocuments(d.ctx, cmd) if err != nil { - logger.Warnf("cannot get profile count for database %s: %s", db, err) + logger.Warn("cannot get profile count for database", "database", db, "error", err) break } labels["database"] = db diff --git a/exporter/profile_status_collector_test.go b/exporter/profile_status_collector_test.go index d296385f9..84955e518 100644 --- a/exporter/profile_status_collector_test.go +++ b/exporter/profile_status_collector_test.go @@ -22,7 +22,7 @@ import ( "time" "github.com/prometheus/client_golang/prometheus/testutil" - "github.com/sirupsen/logrus" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/assert" "go.mongodb.org/mongo-driver/bson" @@ -49,7 +49,7 @@ func TestProfileCollector(t *testing.T) { ti := labelsGetterMock{} - c := newProfileCollector(ctx, client, logrus.New(), false, ti, 30) + c := newProfileCollector(ctx, client, promslog.New(&promslog.Config{}), false, ti, 30) expected := strings.NewReader(` # HELP mongodb_profile_slow_query_count profile_slow_query.count diff --git a/exporter/replset_config_collector.go b/exporter/replset_config_collector.go index 6bb76f8f2..561e4522d 100644 --- a/exporter/replset_config_collector.go +++ b/exporter/replset_config_collector.go @@ -17,10 +17,10 @@ package exporter import ( "context" + "log/slog" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" - "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" ) @@ -34,10 +34,10 @@ type replSetGetConfigCollector struct { } // newReplicationSetConfigCollector creates a collector for configuration of replication set. -func newReplicationSetConfigCollector(ctx context.Context, client *mongo.Client, logger *logrus.Logger, compatible bool, topology labelsGetter) *replSetGetConfigCollector { +func newReplicationSetConfigCollector(ctx context.Context, client *mongo.Client, logger *slog.Logger, compatible bool, topology labelsGetter) *replSetGetConfigCollector { return &replSetGetConfigCollector{ ctx: ctx, - base: newBaseCollector(client, logger.WithFields(logrus.Fields{"collector": "replset_config"})), + base: newBaseCollector(client, logger.With("collector", "replset_config")), compatibleMode: compatible, topologyInfo: topology, @@ -69,7 +69,7 @@ func (d *replSetGetConfigCollector) collect(ch chan<- prometheus.Metric) { return } } - logger.Errorf("cannot get replSetGetConfig: %s", err) + logger.Error("cannot get replSetGetConfig", "error", err) return } @@ -77,7 +77,7 @@ func (d *replSetGetConfigCollector) collect(ch chan<- prometheus.Metric) { config, ok := m["config"].(bson.M) if !ok { err := errors.Wrapf(errUnexpectedDataType, "%T for data field", m["config"]) - logger.Errorf("cannot decode getDiagnosticData: %s", err) + logger.Error("cannot decode getDiagnosticData", "error", err) return } diff --git a/exporter/replset_config_collector_test.go b/exporter/replset_config_collector_test.go index 809f83d35..a710b4931 100644 --- a/exporter/replset_config_collector_test.go +++ b/exporter/replset_config_collector_test.go @@ -22,7 +22,7 @@ import ( "time" "github.com/prometheus/client_golang/prometheus/testutil" - "github.com/sirupsen/logrus" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/assert" "github.com/percona/mongodb_exporter/internal/tu" @@ -36,7 +36,7 @@ func TestReplsetConfigCollector(t *testing.T) { ti := labelsGetterMock{} - c := newReplicationSetConfigCollector(ctx, client, logrus.New(), false, ti) + c := newReplicationSetConfigCollector(ctx, client, promslog.New(&promslog.Config{}), false, ti) // The last \n at the end of this string is important expected := strings.NewReader(` @@ -62,7 +62,7 @@ func TestReplsetConfigCollectorNoSharding(t *testing.T) { ti := labelsGetterMock{} - c := newReplicationSetConfigCollector(ctx, client, logrus.New(), false, ti) + c := newReplicationSetConfigCollector(ctx, client, promslog.New(&promslog.Config{}), false, ti) // Replication set metrics should not be generated for unsharded server count := testutil.CollectAndCount(c) diff --git a/exporter/replset_status_collector.go b/exporter/replset_status_collector.go index afbbd6d39..0387b8d26 100644 --- a/exporter/replset_status_collector.go +++ b/exporter/replset_status_collector.go @@ -17,9 +17,9 @@ package exporter import ( "context" + "log/slog" "github.com/prometheus/client_golang/prometheus" - "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" ) @@ -38,10 +38,10 @@ type replSetGetStatusCollector struct { } // newReplicationSetStatusCollector creates a collector for statistics on replication set. -func newReplicationSetStatusCollector(ctx context.Context, client *mongo.Client, logger *logrus.Logger, compatible bool, topology labelsGetter) *replSetGetStatusCollector { +func newReplicationSetStatusCollector(ctx context.Context, client *mongo.Client, logger *slog.Logger, compatible bool, topology labelsGetter) *replSetGetStatusCollector { return &replSetGetStatusCollector{ ctx: ctx, - base: newBaseCollector(client, logger.WithFields(logrus.Fields{"collector": "replset_status"})), + base: newBaseCollector(client, logger.With("collector", "replset_status")), compatibleMode: compatible, topologyInfo: topology, @@ -73,7 +73,7 @@ func (d *replSetGetStatusCollector) collect(ch chan<- prometheus.Metric) { return } } - logger.Errorf("cannot get replSetGetStatus: %s", err) + logger.Error("cannot get replSetGetStatus", "error", err) return } diff --git a/exporter/replset_status_collector_test.go b/exporter/replset_status_collector_test.go index 12a5cbcb0..83867a834 100644 --- a/exporter/replset_status_collector_test.go +++ b/exporter/replset_status_collector_test.go @@ -22,7 +22,7 @@ import ( "time" "github.com/prometheus/client_golang/prometheus/testutil" - "github.com/sirupsen/logrus" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/assert" "github.com/percona/mongodb_exporter/internal/tu" @@ -36,7 +36,7 @@ func TestReplsetStatusCollector(t *testing.T) { ti := labelsGetterMock{} - c := newReplicationSetStatusCollector(ctx, client, logrus.New(), false, ti) + c := newReplicationSetStatusCollector(ctx, client, promslog.New(&promslog.Config{}), false, ti) // The last \n at the end of this string is important expected := strings.NewReader(` @@ -66,7 +66,7 @@ func TestReplsetStatusCollectorNoSharding(t *testing.T) { ti := labelsGetterMock{} - c := newReplicationSetStatusCollector(ctx, client, logrus.New(), false, ti) + c := newReplicationSetStatusCollector(ctx, client, promslog.New(&promslog.Config{}), false, ti) // Replication set metrics should not be generated for unsharded server count := testutil.CollectAndCount(c) diff --git a/exporter/secondary_lag_test.go b/exporter/secondary_lag_test.go index bf12761ce..3d0054c9a 100644 --- a/exporter/secondary_lag_test.go +++ b/exporter/secondary_lag_test.go @@ -23,7 +23,7 @@ import ( "github.com/prometheus/client_golang/prometheus" dto "github.com/prometheus/client_model/go" - "github.com/sirupsen/logrus" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.mongodb.org/mongo-driver/bson" @@ -127,7 +127,7 @@ func TestSecondaryLag(t *testing.T) { assert.NoError(t, err) m, _ = m["data"].(bson.M) - metrics := replSetMetrics(m, logrus.WithField("component", "test")) + metrics := replSetMetrics(m, promslog.New(&promslog.Config{}).With("component", "test")) var lag prometheus.Metric for _, m := range metrics { if strings.HasPrefix(m.Desc().String(), `Desc{fqName: "mongodb_mongod_replset_member_replication_lag"`) { diff --git a/exporter/seedlist.go b/exporter/seedlist.go index 343907696..e6ebb257c 100644 --- a/exporter/seedlist.go +++ b/exporter/seedlist.go @@ -16,29 +16,30 @@ package exporter import ( + "fmt" + "log" + "log/slog" "net" "net/url" "strconv" "strings" - - "github.com/sirupsen/logrus" ) // GetSeedListFromSRV converts mongodb+srv URI to flat connection string. -func GetSeedListFromSRV(uri string, log *logrus.Logger) string { +func GetSeedListFromSRV(uri string, logger *slog.Logger) string { uriParsed, err := url.Parse(uri) if err != nil { - log.Fatalf("Failed to parse URI %s: %v", uri, err) + log.Fatal(fmt.Sprintf("Failed to parse URI %s: %v", uri, err)) } cname, srvRecords, err := net.LookupSRV("mongodb", "tcp", uriParsed.Hostname()) if err != nil { - log.Errorf("Failed to lookup SRV records for %s: %v", uri, err) + logger.Error("Failed to lookup SRV records", "uri", uri, "error", err) return uri } if len(srvRecords) == 0 { - log.Errorf("No SRV records found for %s", uri) + logger.Error("No SRV records found", "uri", uri) return uri } @@ -46,16 +47,16 @@ func GetSeedListFromSRV(uri string, log *logrus.Logger) string { txtRecords, err := net.LookupTXT(uriParsed.Hostname()) if err != nil { - log.Errorf("Failed to lookup TXT records for %s: %v", cname, err) + logger.Error("Failed to lookup TXT records", "cname", cname, "error", err) } if len(txtRecords) > 1 { - log.Errorf("Multiple TXT records found for %s, thus were not applied", cname) + logger.Error("Multiple TXT records were found and none will be applied", "cname", cname) } if len(txtRecords) == 1 { // We take connection parameters from the TXT record uriParams, err := url.ParseQuery(txtRecords[0]) if err != nil { - log.Errorf("Failed to parse TXT record %s: %v", txtRecords[0], err) + logger.Error("Failed to parse TXT record", "txt_record", txtRecords[0], "error", err) } else { // Override connection parameters with ones from URI query string for p, v := range uriParsed.Query() { diff --git a/exporter/seedlist_test.go b/exporter/seedlist_test.go index b236cae0a..900c5343e 100644 --- a/exporter/seedlist_test.go +++ b/exporter/seedlist_test.go @@ -20,7 +20,7 @@ import ( "testing" "github.com/foxcpp/go-mockdns" - "github.com/sirupsen/logrus" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/assert" "github.com/percona/mongodb_exporter/internal/tu" @@ -29,7 +29,7 @@ import ( func TestGetSeedListFromSRV(t *testing.T) { // Can't run in parallel because it patches the net.DefaultResolver - log := logrus.New() + log := promslog.New(&promslog.Config{}) srv := tu.SetupFakeResolver() defer func(t *testing.T) { diff --git a/exporter/server.go b/exporter/server.go index 111f938e9..6c6154ce2 100644 --- a/exporter/server.go +++ b/exporter/server.go @@ -17,6 +17,7 @@ package exporter import ( "context" + "log/slog" "net/http" "net/url" "os" @@ -28,7 +29,6 @@ import ( "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/common/promslog" "github.com/prometheus/exporter-toolkit/web" - "github.com/sirupsen/logrus" ) // ServerMap stores http handlers for each host @@ -44,8 +44,8 @@ type ServerOpts struct { DisableDefaultRegistry bool } -// Runs the main web-server -func RunWebServer(opts *ServerOpts, exporters []*Exporter, log *logrus.Logger) { +// RunWebServer runs the main web-server +func RunWebServer(opts *ServerOpts, exporters []*Exporter, log *slog.Logger) { mux := http.DefaultServeMux if len(exporters) == 0 { @@ -68,7 +68,7 @@ func RunWebServer(opts *ServerOpts, exporters []*Exporter, log *logrus.Logger) { `)) if err != nil { - log.Errorf("error writing response: %v", err) + log.Error("error writing response", "error", err) } }) @@ -81,11 +81,10 @@ func RunWebServer(opts *ServerOpts, exporters []*Exporter, log *logrus.Logger) { WebConfigFile: &opts.TLSConfigPath, } logLevel := &promslog.Level{} - _ = logLevel.Set(log.Level.String()) if err := web.ListenAndServe(server, flags, promslog.New(&promslog.Config{ //nolint:exhaustivestruct Level: logLevel, })); err != nil { - log.Errorf("error starting server: %v", err) + log.Error("error starting server", "error", err) os.Exit(1) } } @@ -110,7 +109,7 @@ func multiTargetHandler(serverMap ServerMap) http.HandlerFunc { // OverallTargetsHandler is a handler to scrape all the targets in one request. // Adds instance label to each metric. -func OverallTargetsHandler(exporters []*Exporter, logger *logrus.Logger) http.HandlerFunc { +func OverallTargetsHandler(exporters []*Exporter, logger *slog.Logger) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { seconds, err := strconv.Atoi(r.Header.Get("X-Prometheus-Scrape-Timeout-Seconds")) // To support older ones vmagents. @@ -132,7 +131,7 @@ func OverallTargetsHandler(exporters []*Exporter, logger *logrus.Logger) http.Ha client, err := e.getClient(ctx) if err != nil { - e.logger.Errorf("Cannot connect to MongoDB: %v", err) + e.logger.Error("Cannot connect to MongoDB", "error", err) } // Close client after usage. @@ -141,7 +140,7 @@ func OverallTargetsHandler(exporters []*Exporter, logger *logrus.Logger) http.Ha if client != nil { err := client.Disconnect(ctx) if err != nil { - logger.Errorf("Cannot disconnect client: %v", err) + logger.Error("Cannot disconnect client", "error", err) } } }() @@ -171,20 +170,20 @@ func OverallTargetsHandler(exporters []*Exporter, logger *logrus.Logger) http.Ha // Delegate http serving to Prometheus client library, which will call collector.Collect. h := promhttp.HandlerFor(gatherers, promhttp.HandlerOpts{ ErrorHandling: promhttp.ContinueOnError, - ErrorLog: logger, + // ErrorLog: logger, // todo(idoqo): check with promhttp }) h.ServeHTTP(w, r) } } -func buildServerMap(exporters []*Exporter, log *logrus.Logger) ServerMap { +func buildServerMap(exporters []*Exporter, log *slog.Logger) ServerMap { servers := make(ServerMap, len(exporters)) for _, e := range exporters { - if url, err := url.Parse(e.opts.URI); err == nil { - servers[url.Host] = e.Handler() + if parsedURL, err := url.Parse(e.opts.URI); err == nil { + servers[parsedURL.Host] = e.Handler() } else { - log.Errorf("Unable to parse addr %s as url: %s", e.opts.URI, err) + log.Error("Unable to parse provided address as url", "address", e.opts.URI, "error", err) } } diff --git a/exporter/shards_collector.go b/exporter/shards_collector.go index 32daaca59..e204baa2f 100644 --- a/exporter/shards_collector.go +++ b/exporter/shards_collector.go @@ -18,11 +18,11 @@ package exporter import ( "context" "fmt" + "log/slog" "strings" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" - "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" @@ -35,10 +35,10 @@ type shardsCollector struct { } // newShardsCollector creates collector collecting metrics about chunks for shards Mongo. -func newShardsCollector(ctx context.Context, client *mongo.Client, logger *logrus.Logger, compatibleMode bool) *shardsCollector { +func newShardsCollector(ctx context.Context, client *mongo.Client, logger *slog.Logger, compatibleMode bool) *shardsCollector { return &shardsCollector{ ctx: ctx, - base: newBaseCollector(client, logger.WithFields(logrus.Fields{"collector": "shards"})), + base: newBaseCollector(client, logger.With("collector", "shards")), compatible: compatibleMode, } } @@ -62,14 +62,14 @@ func (d *shardsCollector) collect(ch chan<- prometheus.Metric) { metrics := make([]prometheus.Metric, 0) metric, err := chunksTotal(ctx, client) if err != nil { - logger.Warnf("cannot create metric for chunks total: %s", err) + logger.Warn("cannot create metric for chunks total", "error", err) } else { metrics = append(metrics, metric) } ms, err := chunksTotalPerShard(ctx, client) if err != nil { - logger.Warnf("cannot create metric for chunks total per shard: %s", err) + logger.Warn("cannot create metric for chunks total per shard", "error", err) } else { metrics = append(metrics, ms...) } @@ -80,7 +80,7 @@ func (d *shardsCollector) collect(ch chan<- prometheus.Metric) { databaseNames, err := client.ListDatabaseNames(d.ctx, bson.D{}) if err != nil { - logger.Errorf("cannot get database names: %s", err) + logger.Error("cannot get database names", "error", err) } for _, database := range databaseNames { collections := d.getCollectionsForDBName(database) @@ -155,14 +155,14 @@ func (d *shardsCollector) getCollectionsForDBName(database string) []primitive.M cursor := client.Database("config").Collection("collections") rs, err := cursor.Find(d.ctx, bson.M{"_id": bson.M{"$regex": fmt.Sprintf("^%s.", database), "$options": "i"}}) if err != nil { - logger.Errorf("cannot find _id starting with \"%s.\":%s", database, err) + logger.Error("cannot find _id with database prefix", "database", database, "error", err) return nil } var decoded []bson.M err = rs.All(d.ctx, &decoded) if err != nil { - logger.Errorf("cannot decode collections: %s", err) + logger.Error("cannot decode collections", "error", err) return nil } @@ -193,14 +193,14 @@ func (d *shardsCollector) getChunksForCollection(row primitive.M) []bson.M { cur, err := client.Database("config").Collection("chunks").Aggregate(context.Background(), aggregation) if err != nil { - logger.Errorf("cannot get $shards cursor for collection config.chunks: %s", err) + logger.Error("cannot get $shards cursor for collection config.chunks", "error", err) return nil } var chunks []bson.M err = cur.All(context.Background(), &chunks) if err != nil { - logger.Errorf("cannot decode $shards for collection config.chunks: %s", err) + logger.Error("cannot decode $shards for collection config.chunks", "error", err) return nil } diff --git a/exporter/shards_collector_test.go b/exporter/shards_collector_test.go index efb7c613c..4900b4ded 100644 --- a/exporter/shards_collector_test.go +++ b/exporter/shards_collector_test.go @@ -22,7 +22,7 @@ import ( "time" "github.com/prometheus/client_golang/prometheus" - "github.com/sirupsen/logrus" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/assert" "github.com/percona/mongodb_exporter/internal/tu" @@ -35,7 +35,7 @@ func TestShardsCollector(t *testing.T) { defer cancel() client := tu.DefaultTestClientMongoS(ctx, t) - c := newShardsCollector(ctx, client, logrus.New(), false) + c := newShardsCollector(ctx, client, promslog.New(&promslog.Config{}), false) reg := prometheus.NewPedanticRegistry() if err := reg.Register(c); err != nil { diff --git a/exporter/top_collector.go b/exporter/top_collector.go index 6a9d09bea..87a043499 100644 --- a/exporter/top_collector.go +++ b/exporter/top_collector.go @@ -18,9 +18,9 @@ package exporter import ( "context" "fmt" + "log/slog" "github.com/prometheus/client_golang/prometheus" - "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" @@ -36,12 +36,12 @@ type topCollector struct { var ErrInvalidOrMissingTotalsEntry = fmt.Errorf("invalid or misssing totals entry in top results") -func newTopCollector(ctx context.Context, client *mongo.Client, logger *logrus.Logger, compatible bool, +func newTopCollector(ctx context.Context, client *mongo.Client, logger *slog.Logger, compatible bool, topology labelsGetter, ) *topCollector { return &topCollector{ ctx: ctx, - base: newBaseCollector(client, logger.WithFields(logrus.Fields{"collector": "top"})), + base: newBaseCollector(client, logger.With("collector", "top")), compatibleMode: false, // there are no compatible metrics for this collector. topologyInfo: topology, } diff --git a/exporter/top_collector_test.go b/exporter/top_collector_test.go index 27c051c5f..95cdbd02b 100644 --- a/exporter/top_collector_test.go +++ b/exporter/top_collector_test.go @@ -21,7 +21,7 @@ import ( "time" "github.com/prometheus/client_golang/prometheus/testutil" - "github.com/sirupsen/logrus" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/assert" "github.com/percona/mongodb_exporter/internal/tu" @@ -35,7 +35,7 @@ func TestTopCollector(t *testing.T) { ti := labelsGetterMock{} - c := newTopCollector(ctx, client, logrus.New(), false, ti) + c := newTopCollector(ctx, client, promslog.New(&promslog.Config{}), false, ti) // Filter metrics for 2 reasons: // 1. The result is huge diff --git a/exporter/topology_info.go b/exporter/topology_info.go index 254f8795e..1ed5da14c 100644 --- a/exporter/topology_info.go +++ b/exporter/topology_info.go @@ -18,10 +18,10 @@ package exporter import ( "context" "fmt" + "log/slog" "sync" "github.com/pkg/errors" - "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" @@ -57,7 +57,7 @@ type topologyInfo struct { // by a new connector, able to reconnect if needed. In case of reconnection, we should // call loadLabels to refresh the labels because they might have changed client *mongo.Client - logger *logrus.Entry + logger *slog.Logger rw sync.RWMutex labels map[string]string } @@ -65,17 +65,17 @@ type topologyInfo struct { // ErrCannotGetTopologyLabels Cannot read topology labels. var ErrCannotGetTopologyLabels = fmt.Errorf("cannot get topology labels") -func newTopologyInfo(ctx context.Context, client *mongo.Client, logger *logrus.Logger) *topologyInfo { +func newTopologyInfo(ctx context.Context, client *mongo.Client, logger *slog.Logger) *topologyInfo { ti := &topologyInfo{ client: client, - logger: logger.WithFields(logrus.Fields{"component": "topology_info"}), + logger: logger.With("component", "topology_info"), labels: make(map[string]string), rw: sync.RWMutex{}, } err := ti.loadLabels(ctx) if err != nil { - logger.Warnf("cannot load topology labels: %s", err) + logger.Warn("cannot load topology labels", "error", err) } return ti @@ -157,7 +157,7 @@ func getNodeType(ctx context.Context, client *mongo.Client) (mongoDBNodeType, er return typeMongod, nil } -func getClusterRole(ctx context.Context, client *mongo.Client, logger *logrus.Entry) (string, error) { +func getClusterRole(ctx context.Context, client *mongo.Client, logger *slog.Logger) (string, error) { cmdOpts := primitive.M{} // Not always we can get this info. For example, we cannot get this for hidden hosts so // if there is an error, just ignore it diff --git a/exporter/topology_info_test.go b/exporter/topology_info_test.go index 7d7d3ec1a..c96422841 100644 --- a/exporter/topology_info_test.go +++ b/exporter/topology_info_test.go @@ -21,7 +21,7 @@ import ( "testing" "time" - "github.com/sirupsen/logrus" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -89,7 +89,7 @@ func TestTopologyLabels(t *testing.T) { require.NoError(t, err) client := tu.TestClient(ctx, port, t) - ti := newTopologyInfo(ctx, client, logrus.New()) + ti := newTopologyInfo(ctx, client, promslog.New(&promslog.Config{})) bl := ti.baseLabels() assert.Equal(t, tc.want[labelReplicasetName], bl[labelReplicasetName], tc.containerName) assert.Equal(t, tc.want[labelReplicasetState], bl[labelReplicasetState], tc.containerName) @@ -136,7 +136,7 @@ func TestGetClusterRole(t *testing.T) { require.NoError(t, err) client := tu.TestClient(ctx, port, t) - logger := logrus.WithField("component", "test") + logger := promslog.New(&promslog.Config{}).With("component", "test") nodeType, err := getClusterRole(ctx, client, logger) assert.NoError(t, err) assert.Equal(t, tc.want, nodeType, fmt.Sprintf("container name: %s, port: %s", tc.containerName, port)) diff --git a/exporter/v1_compatibility.go b/exporter/v1_compatibility.go index d3cc7199c..4a26b3905 100644 --- a/exporter/v1_compatibility.go +++ b/exporter/v1_compatibility.go @@ -18,13 +18,13 @@ package exporter import ( "context" "fmt" + "log/slog" "math" "strings" "time" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" - "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" @@ -725,10 +725,10 @@ var lockMetrics = []lockMetric{ } // locksMetrics returns the list of lock metrics as a prometheus.Metric slice -// This function reads the human readable list from lockMetrics() and creates a slice of metrics +// This function reads the human-readable list from lockMetrics() and creates a slice of metrics // ready to be exposed, taking the value for each metric from th provided bson.M structure from // getDiagnosticData. -func locksMetrics(logger *logrus.Entry, m bson.M) []prometheus.Metric { +func locksMetrics(logger *slog.Logger, m bson.M) []prometheus.Metric { res := make([]prometheus.Metric, 0, len(lockMetrics)) for _, lm := range lockMetrics { @@ -737,7 +737,7 @@ func locksMetrics(logger *logrus.Entry, m bson.M) []prometheus.Metric { continue } if err != nil { - logger.Errorf("cannot convert lock metric %s to old style: %s", mm.Desc(), err) + logger.Error("cannot convert lock metric to old style", "metric", mm.Desc(), "error", err) continue } res = append(res, mm) @@ -791,20 +791,20 @@ var specialMetricDefinitions = []specialMetric{ }, } -func specialMetrics(ctx context.Context, client *mongo.Client, m bson.M, nodeType mongoDBNodeType, l *logrus.Entry) []prometheus.Metric { +func specialMetrics(ctx context.Context, client *mongo.Client, m bson.M, nodeType mongoDBNodeType, l *slog.Logger) []prometheus.Metric { metrics := make([]prometheus.Metric, 0) for _, def := range specialMetricDefinitions { val, err := sumMetrics(m, def.paths) if err != nil { - l.Errorf("cannot create metric for path: %v: %s", def.paths, err) + l.Error("cannot create metric for path", "paths", def.paths, "error", err) continue } d := prometheus.NewDesc(def.name, def.help, nil, def.labels) metric, err := prometheus.NewConstMetric(d, prometheus.GaugeValue, val) if err != nil { - l.Errorf("cannot create metric for path: %v: %s", def.paths, err) + l.Error("cannot create metric for path", "paths", def.paths, "error", err) continue } @@ -813,7 +813,7 @@ func specialMetrics(ctx context.Context, client *mongo.Client, m bson.M, nodeTyp if nodeType == typeMongod || nodeType == typeArbiter { if engine, err := storageEngine(m); err != nil { - l.Errorf("cannot retrieve engine type: %s", err) + l.Error("cannot retrieve engine type", "error", err) } else { metrics = append(metrics, engine) } @@ -829,7 +829,7 @@ func specialMetrics(ctx context.Context, client *mongo.Client, m bson.M, nodeTyp if nodeType != typeMongos { if opLogMetrics, err := oplogStatus(ctx, client); err != nil { - l.Warnf("cannot create metrics for oplog: %s", err) + l.Warn("cannot create metrics for oplog", "error", err) } else { metrics = append(metrics, opLogMetrics...) } @@ -839,7 +839,7 @@ func specialMetrics(ctx context.Context, client *mongo.Client, m bson.M, nodeTyp return metrics } -func retrieveMongoDBBuildInfo(ctx context.Context, client *mongo.Client, l *logrus.Entry) (buildInfo, error) { +func retrieveMongoDBBuildInfo(ctx context.Context, client *mongo.Client, l *slog.Logger) (buildInfo, error) { if client == nil { return buildInfo{}, errors.New("cannot get mongo build info: client is nil") } @@ -857,7 +857,7 @@ func retrieveMongoDBBuildInfo(ctx context.Context, client *mongo.Client, l *logr } else { buildInfoDoc.Edition = CommunityEdition } - l.Debug("MongoDB edition: ", buildInfoDoc.Edition) + l.Debug("MongoDB edition", "edition", buildInfoDoc.Edition) if buildInfoDoc.PSMDBVersion != "" { buildInfoDoc.Vendor = PerconaVendor @@ -917,10 +917,10 @@ func myState(ctx context.Context, client *mongo.Client) prometheus.Metric { } // arbiterMetrics returns metrics for mongoDB arbiter instances. -func arbiterMetrics(ctx context.Context, client *mongo.Client, l *logrus.Entry) []prometheus.Metric { +func arbiterMetrics(ctx context.Context, client *mongo.Client, l *slog.Logger) []prometheus.Metric { response, err := util.MyRole(ctx, client) if err != nil { - l.Errorf("cannot get role of the running instance: %s", err) + l.Error("cannot get role of the running instance", "error", err) return nil } @@ -984,15 +984,15 @@ func oplogStatus(ctx context.Context, client *mongo.Client) ([]prometheus.Metric return []prometheus.Metric{headMetric, tailMetric}, nil } -func replSetMetrics(d bson.M, l *logrus.Entry) []prometheus.Metric { +func replSetMetrics(d bson.M, l *slog.Logger) []prometheus.Metric { var repl proto.ReplicaSetStatus b, err := bson.Marshal(d) if err != nil { - l.Warnf("cannot marshal replica set status: %s", err) + l.Warn("cannot marshal replica set status", "error", err) return nil } if err := bson.Unmarshal(b, &repl); err != nil { - l.Warnf("cannot unmarshal replica set status: %s", err) + l.Warn("cannot unmarshal replica set status", "error", err) return nil } @@ -1069,42 +1069,42 @@ func replSetMetrics(d bson.M, l *logrus.Entry) []prometheus.Metric { return metrics } -func mongosMetrics(ctx context.Context, client *mongo.Client, l *logrus.Entry) []prometheus.Metric { +func mongosMetrics(ctx context.Context, client *mongo.Client, l *slog.Logger) []prometheus.Metric { metrics := make([]prometheus.Metric, 0) if metric, err := databasesTotalPartitioned(ctx, client); err != nil { - l.Debugf("cannot create metric for database total: %s", err) + l.Debug("cannot create metric for database total", "error", err) } else { metrics = append(metrics, metric) } if metric, err := databasesTotalUnpartitioned(ctx, client); err != nil { - l.Debugf("cannot create metric for database total: %s", err) + l.Debug("cannot create metric for database total", "error", err) } else { metrics = append(metrics, metric) } if metric, err := shardedCollectionsTotal(ctx, client); err != nil { - l.Debugf("cannot create metric for collections total: %s", err) + l.Debug("cannot create metric for collections total", "error", err) } else { metrics = append(metrics, metric) } if metric, err := balancerEnabled(ctx, client); err != nil { - l.Debugf("cannot create metric for balancer is enabled: %s", err) + l.Debug("cannot create metric for balancer is enabled", "error", err) } else { metrics = append(metrics, metric) } if metric, err := chunksBalancerRunning(ctx, client); err != nil { - l.Debugf("cannot create metric for chunks balancer running: %s", err) + l.Debug("cannot create metric for chunks balancer running", "error", err) } else { metrics = append(metrics, metric) } ms, err := changelog10m(ctx, client, l) if err != nil { - l.Errorf("cannot create metric for changelog: %s", err) + l.Error("cannot create metric for changelog", "error", err) } else { metrics = append(metrics, ms...) } @@ -1112,13 +1112,13 @@ func mongosMetrics(ctx context.Context, client *mongo.Client, l *logrus.Entry) [ metrics = append(metrics, dbstatsMetrics(ctx, client, l)...) if metric, err := shardingShardsTotal(ctx, client); err != nil { - l.Debugf("cannot create metric for database total: %s", err) + l.Debug("cannot create metric for database total", "error", err) } else { metrics = append(metrics, metric) } if metric, err := shardingShardsDrainingTotal(ctx, client); err != nil { - l.Debugf("cannot create metric for database total: %s", err) + l.Debug("cannot create metric for database total", "error", err) } else { metrics = append(metrics, metric) } @@ -1257,7 +1257,7 @@ type ShardingChangelogStats struct { Items *[]ShardingChangelogSummary } -func changelog10m(ctx context.Context, client *mongo.Client, l *logrus.Entry) ([]prometheus.Metric, error) { +func changelog10m(ctx context.Context, client *mongo.Client, l *slog.Logger) ([]prometheus.Metric, error) { var metrics []prometheus.Metric coll := client.Database("config").Collection("changelog") @@ -1274,7 +1274,7 @@ func changelog10m(ctx context.Context, client *mongo.Client, l *logrus.Entry) ([ for c.Next(ctx) { s := &ShardingChangelogSummary{} if err := c.Decode(s); err != nil { - l.Error(err) + l.Error("failed to decode changelog summary", "error", err) continue } @@ -1332,20 +1332,20 @@ type buildInfo struct { Modules []string `bson:"modules"` } -func getDatabaseStatList(ctx context.Context, client *mongo.Client, l *logrus.Entry) *databaseStatList { +func getDatabaseStatList(ctx context.Context, client *mongo.Client, l *slog.Logger) *databaseStatList { dbStatList := &databaseStatList{} dbNames, err := client.ListDatabaseNames(ctx, bson.M{}) if err != nil { - l.Errorf("Failed to get database names: %s.", err) + l.Error("Failed to get database names", "error", err) return nil } - l.Debugf("getting stats for databases: %v", dbNames) + l.Debug("getting stats for databases", "databases", dbNames) for _, db := range dbNames { dbStatus := databaseStatus{} r := client.Database(db).RunCommand(context.TODO(), bson.D{{Key: "dbStats", Value: 1}, {Key: "scale", Value: 1}}) err := r.Decode(&dbStatus) if err != nil { - l.Errorf("Failed to get database status: %s.", err) + l.Error("Failed to get database status", "error", err) return nil } dbStatList.Members = append(dbStatList.Members, dbStatus) @@ -1354,7 +1354,7 @@ func getDatabaseStatList(ctx context.Context, client *mongo.Client, l *logrus.En return dbStatList } -func dbstatsMetrics(ctx context.Context, client *mongo.Client, l *logrus.Entry) []prometheus.Metric { +func dbstatsMetrics(ctx context.Context, client *mongo.Client, l *slog.Logger) []prometheus.Metric { var metrics []prometheus.Metric dbStatList := getDatabaseStatList(ctx, client, l) diff --git a/exporter/v1_compatibility_test.go b/exporter/v1_compatibility_test.go index da1150c0c..ad73c72af 100644 --- a/exporter/v1_compatibility_test.go +++ b/exporter/v1_compatibility_test.go @@ -27,7 +27,7 @@ import ( "github.com/prometheus/client_golang/prometheus" dto "github.com/prometheus/client_model/go" - "github.com/sirupsen/logrus" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.mongodb.org/mongo-driver/bson" @@ -108,9 +108,13 @@ func TestAddLocksMetrics(t *testing.T) { err = json.Unmarshal(buf, &m) assert.NoError(t, err) - logger := logrus.New() - logger.SetLevel(logrus.DebugLevel) - metrics := locksMetrics(logger.WithField("component", "test"), m) + logLevel := promslog.NewLevel() + err = logLevel.Set("debug") + require.NoError(t, err) + logger := promslog.New(&promslog.Config{ + Level: logLevel, + }) + metrics := locksMetrics(logger.With("component", "test"), m) desc := make([]string, 0, len(metrics)) for _, metric := range metrics { @@ -303,8 +307,12 @@ func TestArbiterMetrics(t *testing.T) { t.Parallel() containerName := "mongo-1-arbiter" - logger := logrus.New() - logger.SetLevel(logrus.DebugLevel) + logLevel := promslog.NewLevel() + err := logLevel.Set("debug") + require.NoError(t, err) + logger := promslog.New(&promslog.Config{ + Level: logLevel, + }) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() @@ -312,7 +320,7 @@ func TestArbiterMetrics(t *testing.T) { port, err := tu.PortForContainer(containerName) require.NoError(t, err) client := tu.TestClient(ctx, port, t) - metrics := arbiterMetrics(ctx, client, logger.WithField("component", "test")) + metrics := arbiterMetrics(ctx, client, logger.With("component", "test")) var rsMembers dto.Metric for _, m := range metrics { if strings.HasPrefix(m.Desc().String(), `Desc{fqName: "mongodb_mongod_replset_number_of_members"`) { diff --git a/go.mod b/go.mod index 42bb1ad8d..65730ed3e 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,6 @@ require ( github.com/prometheus/client_model v0.6.1 github.com/prometheus/common v0.63.0 github.com/prometheus/exporter-toolkit v0.14.0 - github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.10.0 go.mongodb.org/mongo-driver v1.17.3 ) diff --git a/go.sum b/go.sum index aa2015e52..da72ec198 100644 --- a/go.sum +++ b/go.sum @@ -44,7 +44,6 @@ github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GK github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= @@ -181,7 +180,6 @@ github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+ github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY= github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/testcontainers/testcontainers-go v0.34.0 h1:5fbgF0vIN5u+nD3IWabQwRybuB4GY8G2HHgCkbMzMHo= @@ -253,7 +251,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -298,6 +295,5 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index b3def466a..75e175c8c 100644 --- a/main.go +++ b/main.go @@ -17,13 +17,15 @@ package main import ( "fmt" + "log" + "log/slog" "net" "net/url" "regexp" "strings" "github.com/alecthomas/kong" - "github.com/sirupsen/logrus" + "github.com/prometheus/common/promslog" "github.com/percona/mongodb_exporter/exporter" ) @@ -104,20 +106,15 @@ func main() { return } - log := logrus.New() - - levels := map[string]logrus.Level{ - "debug": logrus.DebugLevel, - "error": logrus.ErrorLevel, - "fatal": logrus.FatalLevel, - "info": logrus.InfoLevel, - "warn": logrus.WarnLevel, - } - log.SetLevel(levels[opts.LogLevel]) - log.Debugf("Compatible mode: %v", opts.CompatibleMode) + logLevel := promslog.NewLevel() + _ = logLevel.Set(opts.LogLevel) + logger := promslog.New(&promslog.Config{ + Level: logLevel, + }) + logger.Debug("Compatible mode", "compatible_mode", opts.CompatibleMode) if opts.WebTelemetryPath == "" { - log.Warn("Web telemetry path \"\" invalid, falling back to \"/\" instead") + logger.Warn("Web telemetry path \"\" is invalid, falling back to \"/\" instead") opts.WebTelemetryPath = "/" } @@ -126,7 +123,7 @@ func main() { } if opts.TimeoutOffset <= 0 { - log.Warn("Timeout offset needs to be greater than \"0\", falling back to \"1\". You can specify the timout offset with --web.timeout-offset command argument") + logger.Warn("Timeout offset needs to be greater than \"0\", falling back to \"1\". You can specify the timout offset with --web.timeout-offset command argument") opts.TimeoutOffset = 1 } @@ -137,12 +134,12 @@ func main() { WebListenAddress: opts.WebListenAddress, TLSConfigPath: opts.TLSConfigPath, } - exporter.RunWebServer(serverOpts, buildServers(opts, log), log) + exporter.RunWebServer(serverOpts, buildServers(opts, logger), logger) } -func buildExporter(opts GlobalFlags, uri string, log *logrus.Logger) *exporter.Exporter { +func buildExporter(opts GlobalFlags, uri string, log *slog.Logger) *exporter.Exporter { uri = buildURI(uri, opts.User, opts.Password) - log.Debugf("Connection URI: %s", uri) + log.Debug("Connection URI", "uri", uri) uriParsed, _ := url.Parse(uri) var nodeName string @@ -205,7 +202,7 @@ func buildExporter(opts GlobalFlags, uri string, log *logrus.Logger) *exporter.E return e } -func buildServers(opts GlobalFlags, logger *logrus.Logger) []*exporter.Exporter { +func buildServers(opts GlobalFlags, logger *slog.Logger) []*exporter.Exporter { URIs := parseURIList(opts.URI, logger, opts.SplitCluster) servers := make([]*exporter.Exporter, len(URIs)) for serverIdx := range URIs { @@ -215,11 +212,11 @@ func buildServers(opts GlobalFlags, logger *logrus.Logger) []*exporter.Exporter return servers } -func parseURIList(uriList []string, logger *logrus.Logger, splitCluster bool) []string { +func parseURIList(uriList []string, logger *slog.Logger, splitCluster bool) []string { var URIs []string // If server URI is prefixed with mongodb scheme string, then every next URI in - // line not prefixed with mongodb scheme string is a part of cluster. Otherwise + // line not prefixed with mongodb scheme string is a part of cluster. Otherwise, // treat it as a standalone server realURI := "" matchRegexp := regexp.MustCompile(`^mongodb(\+srv)?://`) @@ -259,7 +256,7 @@ func parseURIList(uriList []string, logger *logrus.Logger, splitCluster bool) [] for _, hosturl := range URIs { urlParsed, err := url.Parse(hosturl) if err != nil { - logger.Fatal(fmt.Sprintf("Failed to parse URI %s: %v", hosturl, err)) + log.Fatal(fmt.Sprintf("Failed to parse URI %s: %v", hosturl, err)) } for _, host := range strings.Split(urlParsed.Host, ",") { targetURI := "mongodb://" diff --git a/main_test.go b/main_test.go index 7860eae9a..3d54f866e 100644 --- a/main_test.go +++ b/main_test.go @@ -21,7 +21,7 @@ import ( "testing" "github.com/foxcpp/go-mockdns" - "github.com/sirupsen/logrus" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/assert" "github.com/percona/mongodb_exporter/internal/tu" @@ -54,7 +54,7 @@ func TestParseURIList(t *testing.T) { "mongodb://server5", }, } - logger := logrus.New() + logger := promslog.New(&promslog.Config{}) for test, expected := range tests { actual := parseURIList(strings.Split(test, ","), logger, false) assert.Equal(t, expected, actual) @@ -83,7 +83,7 @@ func TestSplitCluster(t *testing.T) { }, } - logger := logrus.New() + logger := promslog.New(&promslog.Config{}) srv := tu.SetupFakeResolver() @@ -116,7 +116,7 @@ func TestBuildExporter(t *testing.T) { CompatibleMode: true, } - log := logrus.New() + log := promslog.New(&promslog.Config{}) buildExporter(opts, "mongodb://usr:pwd@127.0.0.1/", log) } From dfd5dc69b7ad1c16b768ffb27f8d1098e5135168 Mon Sep 17 00:00:00 2001 From: idoko Date: Sun, 6 Apr 2025 11:45:03 +0100 Subject: [PATCH 04/13] enable diagnostic data tests --- exporter/diagnostic_data_collector_test.go | 74 +++++++++++++++------- 1 file changed, 50 insertions(+), 24 deletions(-) diff --git a/exporter/diagnostic_data_collector_test.go b/exporter/diagnostic_data_collector_test.go index 4098a4db1..b43c53d29 100644 --- a/exporter/diagnostic_data_collector_test.go +++ b/exporter/diagnostic_data_collector_test.go @@ -19,6 +19,7 @@ import ( "context" "fmt" "io" + "log/slog" "sort" "strings" "testing" @@ -253,13 +254,48 @@ func TestAllDiagnosticDataCollectorMetrics(t *testing.T) { } } +// errorCountHandler is a custom handler that keeps tracks of the number of errors and warnings that were logged. +// it discards all errors of other levels. +type errorCountHandler struct { + opts slog.HandlerOptions + logRecords []slog.Record +} + +func newErrorCountHandler(opts *slog.HandlerOptions) *errorCountHandler { + h := &errorCountHandler{ + logRecords: make([]slog.Record, 0), + } + if opts != nil { + h.opts = *opts + } + if h.opts.Level == nil { + h.opts.Level = slog.LevelWarn + } + return h +} + +func (h *errorCountHandler) Handle(ctx context.Context, r slog.Record) error { + if r.Level == slog.LevelError || r.Level == slog.LevelWarn { + h.logRecords = append(h.logRecords, r) + } + return nil +} + +func (h *errorCountHandler) Enabled(_ context.Context, level slog.Level) bool { + return level >= slog.LevelInfo +} + +func (h *errorCountHandler) WithAttrs(attrs []slog.Attr) slog.Handler { + return h +} + +func (h *errorCountHandler) WithGroup(name string) slog.Handler { + return h +} + //nolint:funlen func TestDiagnosticDataErrors(t *testing.T) { t.Parallel() - type log struct { - message string - level uint32 - } type testCase struct { name string @@ -295,7 +331,8 @@ func TestDiagnosticDataErrors(t *testing.T) { require.NoError(t, err) client := tu.TestClient(ctx, port, t) - logger := promslog.New(&promslog.Config{}) + errCountLogHandler := newErrorCountHandler(nil) + logger := slog.New(errCountLogHandler) ti := newTopologyInfo(ctx, client, logger) dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, logger.With("component", "test")) @@ -308,27 +345,16 @@ func TestDiagnosticDataErrors(t *testing.T) { require.NoError(t, err) _ = helpers.CollectMetrics(c) - /*var errorLogs []log - for _, entry := range hook.Entries { - if entry.Level == logrus.ErrorLevel || entry.Level == logrus.WarnLevel { - errorLogs = append(errorLogs, log{ - message: entry.Message, - level: uint32(entry.Level), - }) - } - } - if tc.expectedMessage == "" { - assert.Empty(t, errorLogs) + assert.Empty(t, errCountLogHandler.logRecords) } else { - require.NotEmpty(t, errorLogs) - assert.True( - t, - strings.HasPrefix(hook.LastEntry().Message, tc.expectedMessage), - "'%s' has no prefix: '%s'", - hook.LastEntry().Message, - tc.expectedMessage) - }*/ + require.NotEmpty(t, errCountLogHandler.logRecords) + messages := make([]string, 0, len(errCountLogHandler.logRecords)) + for _, record := range errCountLogHandler.logRecords { + messages = append(messages, record.Message) + } + assert.Contains(t, messages, tc.expectedMessage) + } }) } } From 01afaa915b1c0630005512e963cb307fd8b7036a Mon Sep 17 00:00:00 2001 From: idoko Date: Sun, 6 Apr 2025 14:05:34 +0100 Subject: [PATCH 05/13] use custom logger for promhttp --- exporter/exporter.go | 2 +- exporter/http_error_logger.go | 38 +++++++++++++++++++++++++++++++++++ exporter/server.go | 2 +- 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 exporter/http_error_logger.go diff --git a/exporter/exporter.go b/exporter/exporter.go index b458c2113..559fbd01d 100644 --- a/exporter/exporter.go +++ b/exporter/exporter.go @@ -363,7 +363,7 @@ func (e *Exporter) Handler() http.Handler { // Delegate http serving to Prometheus client library, which will call collector.Collect. h := promhttp.HandlerFor(gatherers, promhttp.HandlerOpts{ ErrorHandling: promhttp.ContinueOnError, - // ErrorLog: e.logger, // todo(idoqo): check with prometheus/client_golang about the interface here + ErrorLog: newHTTPErrorLogger(e.logger), }) h.ServeHTTP(w, r) diff --git a/exporter/http_error_logger.go b/exporter/http_error_logger.go new file mode 100644 index 000000000..acb4cc4eb --- /dev/null +++ b/exporter/http_error_logger.go @@ -0,0 +1,38 @@ +package exporter + +import ( + "fmt" + "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" + "log/slog" +) + +// httpErrorLogger is a wrapper around slog.Logger that can log promhttp errors (by implementing a Println method). +type httpErrorLogger struct { + logger *slog.Logger +} + +func newHTTPErrorLogger(logger *slog.Logger) *httpErrorLogger { + return &httpErrorLogger{logger: logger} +} + +// Println implements the Println method for httpErrorHandler. +func (h *httpErrorLogger) Println(v ...any) { + // promhttp calls the Println() method as follows: + // logger.Println(message, err) i.e., v[0] is the message (a string) and v[1] is the error (which might be prometheus.MultiError) + if len(v) == 2 { + msg, mok := v[0].(string) + err, eok := v[1].(error) + if mok && eok { + multiErr := prometheus.MultiError{} + if errors.As(err, &multiErr) { + errCount := len(multiErr) + for i, err := range multiErr { + h.logger.Error(msg, "error", err, "total_errors", errCount, "error_no", i) + } + } + } + } + // fallback + h.logger.Error(fmt.Sprint(v...)) +} diff --git a/exporter/server.go b/exporter/server.go index 6c6154ce2..ffd77da20 100644 --- a/exporter/server.go +++ b/exporter/server.go @@ -170,7 +170,7 @@ func OverallTargetsHandler(exporters []*Exporter, logger *slog.Logger) http.Hand // Delegate http serving to Prometheus client library, which will call collector.Collect. h := promhttp.HandlerFor(gatherers, promhttp.HandlerOpts{ ErrorHandling: promhttp.ContinueOnError, - // ErrorLog: logger, // todo(idoqo): check with promhttp + ErrorLog: newHTTPErrorLogger(logger), }) h.ServeHTTP(w, r) From 9e89e8b472eb7b0a9bb44d114f138215bfe7bc6e Mon Sep 17 00:00:00 2001 From: idoko Date: Sun, 6 Apr 2025 22:14:10 +0100 Subject: [PATCH 06/13] satisfy linter --- exporter/exporter.go | 3 +-- exporter/seedlist.go | 3 +-- exporter/top_collector.go | 2 +- exporter/top_collector_test.go | 2 +- main.go | 2 +- 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/exporter/exporter.go b/exporter/exporter.go index 559fbd01d..ac56e1a7f 100644 --- a/exporter/exporter.go +++ b/exporter/exporter.go @@ -231,8 +231,7 @@ func (e *Exporter) makeRegistry(ctx context.Context, client *mongo.Client, topol } if e.opts.EnableTopMetrics && nodeType != typeMongos && limitsOk && requestOpts.EnableTopMetrics { - tc := newTopCollector(ctx, client, e.opts.Logger, - e.opts.CompatibleMode, topologyInfo) + tc := newTopCollector(ctx, client, e.opts.Logger, topologyInfo) registry.MustRegister(tc) } diff --git a/exporter/seedlist.go b/exporter/seedlist.go index e6ebb257c..79bb8a76e 100644 --- a/exporter/seedlist.go +++ b/exporter/seedlist.go @@ -16,7 +16,6 @@ package exporter import ( - "fmt" "log" "log/slog" "net" @@ -29,7 +28,7 @@ import ( func GetSeedListFromSRV(uri string, logger *slog.Logger) string { uriParsed, err := url.Parse(uri) if err != nil { - log.Fatal(fmt.Sprintf("Failed to parse URI %s: %v", uri, err)) + log.Fatalf("Failed to parse URI %s: %v", uri, err) } cname, srvRecords, err := net.LookupSRV("mongodb", "tcp", uriParsed.Hostname()) diff --git a/exporter/top_collector.go b/exporter/top_collector.go index 87a043499..6d8f29456 100644 --- a/exporter/top_collector.go +++ b/exporter/top_collector.go @@ -36,7 +36,7 @@ type topCollector struct { var ErrInvalidOrMissingTotalsEntry = fmt.Errorf("invalid or misssing totals entry in top results") -func newTopCollector(ctx context.Context, client *mongo.Client, logger *slog.Logger, compatible bool, +func newTopCollector(ctx context.Context, client *mongo.Client, logger *slog.Logger, topology labelsGetter, ) *topCollector { return &topCollector{ diff --git a/exporter/top_collector_test.go b/exporter/top_collector_test.go index 95cdbd02b..08d287cf5 100644 --- a/exporter/top_collector_test.go +++ b/exporter/top_collector_test.go @@ -35,7 +35,7 @@ func TestTopCollector(t *testing.T) { ti := labelsGetterMock{} - c := newTopCollector(ctx, client, promslog.New(&promslog.Config{}), false, ti) + c := newTopCollector(ctx, client, promslog.New(&promslog.Config{}), ti) // Filter metrics for 2 reasons: // 1. The result is huge diff --git a/main.go b/main.go index 75e175c8c..5764fddd5 100644 --- a/main.go +++ b/main.go @@ -256,7 +256,7 @@ func parseURIList(uriList []string, logger *slog.Logger, splitCluster bool) []st for _, hosturl := range URIs { urlParsed, err := url.Parse(hosturl) if err != nil { - log.Fatal(fmt.Sprintf("Failed to parse URI %s: %v", hosturl, err)) + log.Fatalf("Failed to parse URI %s: %v", hosturl, err) } for _, host := range strings.Split(urlParsed.Host, ",") { targetURI := "mongodb://" From 156b4fefdb22b16de4e2b65dd516bfb8c8645c10 Mon Sep 17 00:00:00 2001 From: idoko Date: Sun, 13 Apr 2025 23:50:47 +0100 Subject: [PATCH 07/13] tidy go.mod --- go.sum | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go.sum b/go.sum index 211c23fa6..e0563a71c 100644 --- a/go.sum +++ b/go.sum @@ -236,8 +236,8 @@ golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA= golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I= -golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= -golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70= +golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= From 2c62e12616cd2b130ef5fd59d44f670a63c4e532 Mon Sep 17 00:00:00 2001 From: idoko Date: Mon, 14 Apr 2025 00:32:58 +0100 Subject: [PATCH 08/13] surpress linters --- exporter/seedlist.go | 2 +- exporter/v1_compatibility.go | 4 ++-- main.go | 6 ++---- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/exporter/seedlist.go b/exporter/seedlist.go index 79bb8a76e..b30a3a776 100644 --- a/exporter/seedlist.go +++ b/exporter/seedlist.go @@ -25,7 +25,7 @@ import ( ) // GetSeedListFromSRV converts mongodb+srv URI to flat connection string. -func GetSeedListFromSRV(uri string, logger *slog.Logger) string { +func GetSeedListFromSRV(uri string, logger *slog.Logger) string { //nolint:cyclop uriParsed, err := url.Parse(uri) if err != nil { log.Fatalf("Failed to parse URI %s: %v", uri, err) diff --git a/exporter/v1_compatibility.go b/exporter/v1_compatibility.go index 4a26b3905..8ce49fa11 100644 --- a/exporter/v1_compatibility.go +++ b/exporter/v1_compatibility.go @@ -791,7 +791,7 @@ var specialMetricDefinitions = []specialMetric{ }, } -func specialMetrics(ctx context.Context, client *mongo.Client, m bson.M, nodeType mongoDBNodeType, l *slog.Logger) []prometheus.Metric { +func specialMetrics(ctx context.Context, client *mongo.Client, m bson.M, nodeType mongoDBNodeType, l *slog.Logger) []prometheus.Metric { //nolint:cyclop metrics := make([]prometheus.Metric, 0) for _, def := range specialMetricDefinitions { @@ -984,7 +984,7 @@ func oplogStatus(ctx context.Context, client *mongo.Client) ([]prometheus.Metric return []prometheus.Metric{headMetric, tailMetric}, nil } -func replSetMetrics(d bson.M, l *slog.Logger) []prometheus.Metric { +func replSetMetrics(d bson.M, l *slog.Logger) []prometheus.Metric { //nolint:cyclop var repl proto.ReplicaSetStatus b, err := bson.Marshal(d) if err != nil { diff --git a/main.go b/main.go index 5764fddd5..abf19175c 100644 --- a/main.go +++ b/main.go @@ -197,9 +197,7 @@ func buildExporter(opts GlobalFlags, uri string, log *slog.Logger) *exporter.Exp CurrentOpSlowTime: opts.CurrentOpSlowTime, } - e := exporter.New(exporterOpts) - - return e + return exporter.New(exporterOpts) } func buildServers(opts GlobalFlags, logger *slog.Logger) []*exporter.Exporter { @@ -212,7 +210,7 @@ func buildServers(opts GlobalFlags, logger *slog.Logger) []*exporter.Exporter { return servers } -func parseURIList(uriList []string, logger *slog.Logger, splitCluster bool) []string { +func parseURIList(uriList []string, logger *slog.Logger, splitCluster bool) []string { //nolint:gocognit var URIs []string // If server URI is prefixed with mongodb scheme string, then every next URI in From 72a751bfd75da3068bf5a0b80633f6917268b180 Mon Sep 17 00:00:00 2001 From: idoko Date: Mon, 14 Apr 2025 00:41:53 +0100 Subject: [PATCH 09/13] fix formatting --- exporter/http_error_logger.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/exporter/http_error_logger.go b/exporter/http_error_logger.go index acb4cc4eb..eaa82b6a7 100644 --- a/exporter/http_error_logger.go +++ b/exporter/http_error_logger.go @@ -2,9 +2,10 @@ package exporter import ( "fmt" + "log/slog" + "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" - "log/slog" ) // httpErrorLogger is a wrapper around slog.Logger that can log promhttp errors (by implementing a Println method). From 3477e876ebe5efaad4d69ce645feb8f279a2170a Mon Sep 17 00:00:00 2001 From: idoko Date: Mon, 14 Apr 2025 00:50:48 +0100 Subject: [PATCH 10/13] satisfy linter --- exporter/diagnostic_data_collector_test.go | 6 +++--- exporter/server.go | 3 +-- exporter/v1_compatibility.go | 2 +- main.go | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/exporter/diagnostic_data_collector_test.go b/exporter/diagnostic_data_collector_test.go index b43c53d29..04584aec9 100644 --- a/exporter/diagnostic_data_collector_test.go +++ b/exporter/diagnostic_data_collector_test.go @@ -274,7 +274,7 @@ func newErrorCountHandler(opts *slog.HandlerOptions) *errorCountHandler { return h } -func (h *errorCountHandler) Handle(ctx context.Context, r slog.Record) error { +func (h *errorCountHandler) Handle(_ context.Context, r slog.Record) error { if r.Level == slog.LevelError || r.Level == slog.LevelWarn { h.logRecords = append(h.logRecords, r) } @@ -285,11 +285,11 @@ func (h *errorCountHandler) Enabled(_ context.Context, level slog.Level) bool { return level >= slog.LevelInfo } -func (h *errorCountHandler) WithAttrs(attrs []slog.Attr) slog.Handler { +func (h *errorCountHandler) WithAttrs(_ []slog.Attr) slog.Handler { return h } -func (h *errorCountHandler) WithGroup(name string) slog.Handler { +func (h *errorCountHandler) WithGroup(_ string) slog.Handler { return h } diff --git a/exporter/server.go b/exporter/server.go index ffd77da20..f94695863 100644 --- a/exporter/server.go +++ b/exporter/server.go @@ -138,8 +138,7 @@ func OverallTargetsHandler(exporters []*Exporter, logger *slog.Logger) http.Hand if !e.opts.GlobalConnPool { defer func() { if client != nil { - err := client.Disconnect(ctx) - if err != nil { + if err := client.Disconnect(ctx); err != nil { logger.Error("Cannot disconnect client", "error", err) } } diff --git a/exporter/v1_compatibility.go b/exporter/v1_compatibility.go index 8ce49fa11..0398afeea 100644 --- a/exporter/v1_compatibility.go +++ b/exporter/v1_compatibility.go @@ -984,7 +984,7 @@ func oplogStatus(ctx context.Context, client *mongo.Client) ([]prometheus.Metric return []prometheus.Metric{headMetric, tailMetric}, nil } -func replSetMetrics(d bson.M, l *slog.Logger) []prometheus.Metric { //nolint:cyclop +func replSetMetrics(d bson.M, l *slog.Logger) []prometheus.Metric { //nolint:cyclop,funlen var repl proto.ReplicaSetStatus b, err := bson.Marshal(d) if err != nil { diff --git a/main.go b/main.go index abf19175c..4eae7774a 100644 --- a/main.go +++ b/main.go @@ -210,7 +210,7 @@ func buildServers(opts GlobalFlags, logger *slog.Logger) []*exporter.Exporter { return servers } -func parseURIList(uriList []string, logger *slog.Logger, splitCluster bool) []string { //nolint:gocognit +func parseURIList(uriList []string, logger *slog.Logger, splitCluster bool) []string { //nolint:gocognit,cyclop var URIs []string // If server URI is prefixed with mongodb scheme string, then every next URI in From 11ad24cd3c6551d9582faad393f2e77ef5bc2c84 Mon Sep 17 00:00:00 2001 From: idoko Date: Mon, 14 Apr 2025 01:02:57 +0100 Subject: [PATCH 11/13] add license headers --- exporter/http_error_logger.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/exporter/http_error_logger.go b/exporter/http_error_logger.go index eaa82b6a7..21f2eedd8 100644 --- a/exporter/http_error_logger.go +++ b/exporter/http_error_logger.go @@ -1,3 +1,18 @@ +// mongodb_exporter +// Copyright (C) 2025 Percona LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package exporter import ( From deb0e713a5a110fe06389d409c8ceac25275a568 Mon Sep 17 00:00:00 2001 From: idoko Date: Tue, 15 Apr 2025 20:24:52 +0100 Subject: [PATCH 12/13] drop format string --- exporter/collstats_collector.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/exporter/collstats_collector.go b/exporter/collstats_collector.go index 189f634e3..bbfac8e22 100644 --- a/exporter/collstats_collector.go +++ b/exporter/collstats_collector.go @@ -116,9 +116,9 @@ func (d *collstatsCollector) collect(ch chan<- prometheus.Metric) { project := bson.D{ { Key: "$project", Value: bson.M{ - "storageStats.wiredTiger": 0, - "storageStats.indexDetails": 0, - }, + "storageStats.wiredTiger": 0, + "storageStats.indexDetails": 0, + }, }, } pipeline = append(pipeline, project) @@ -138,7 +138,7 @@ func (d *collstatsCollector) collect(ch chan<- prometheus.Metric) { continue } - logger.Debug("$collStats metrics for %s.%s", "database", database, "collection", collection) + logger.Debug("$collStats metrics", "database", database, "collection", collection) debugResult(logger, stats) prefix := "collstats" From 0e32dcd71559faa497bc3c5f5aaf8bca89230927 Mon Sep 17 00:00:00 2001 From: idoko Date: Tue, 15 Apr 2025 20:33:28 +0100 Subject: [PATCH 13/13] fix formatting --- exporter/collstats_collector.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/exporter/collstats_collector.go b/exporter/collstats_collector.go index bbfac8e22..1636f8961 100644 --- a/exporter/collstats_collector.go +++ b/exporter/collstats_collector.go @@ -116,9 +116,9 @@ func (d *collstatsCollector) collect(ch chan<- prometheus.Metric) { project := bson.D{ { Key: "$project", Value: bson.M{ - "storageStats.wiredTiger": 0, - "storageStats.indexDetails": 0, - }, + "storageStats.wiredTiger": 0, + "storageStats.indexDetails": 0, + }, }, } pipeline = append(pipeline, project)