Skip to content

Commit 1e917bf

Browse files
BupycHukademidoff
andauthored
PMM-13477 Support MongoDB 8.0 (#943)
* PMM-13477 Support MongoDB 8.0 * PMM-13477 Support MongoDB 8.0 * PMM-13477 Support MongoDB 8.0 * PMM-13477 Fix tests. * PMM-13477 Fix imports and test matrix. * PMM-13477 A little bit of refactoring. * PMM-13477 Fix tests. * PMM-13477 Fix fcv tests. * PMM-13477 see logs on failure. * PMM-13477 fix tests. * PMM-13477 fix tests. * PMM-13477 fix imports. * PMM-13477 a bit of refactoring. * PMM-13477 fix test. * Update exporter/diagnostic_data_collector.go Co-authored-by: Alex Demidoff <[email protected]> --------- Co-authored-by: Alex Demidoff <[email protected]>
1 parent 913bd48 commit 1e917bf

14 files changed

+184
-84
lines changed

.github/workflows/go.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,15 @@ jobs:
2222
image:
2323
- mongo:4.4
2424
- mongo:5.0
25+
- mongo:6.0
26+
- mongo:7.0
27+
- mongo:8.0
28+
- mongo:latest
2529
- percona/percona-server-mongodb:4.4
2630
- percona/percona-server-mongodb:5.0
31+
- percona/percona-server-mongodb:6.0
32+
- percona/percona-server-mongodb:7.0
33+
- percona/percona-server-mongodb:latest
2734

2835
runs-on: ubuntu-latest
2936

@@ -42,3 +49,17 @@ jobs:
4249
sleep 10
4350
make test-race
4451
make test-cluster-clean
52+
53+
- name: Run debug commands on failure
54+
if: ${{ failure() }}
55+
run: |
56+
echo "--- Environment variables ---"
57+
env | sort
58+
echo "--- GO Environment ---"
59+
go env | sort
60+
echo "--- Git status ---"
61+
git status
62+
echo "--- Docker logs ---"
63+
docker compose logs
64+
echo "--- Docker ps ---"
65+
docker compose ps -a

exporter/diagnostic_data_collector.go

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,14 @@ type diagnosticDataCollector struct {
3535
ctx context.Context
3636
base *baseCollector
3737

38+
buildInfo buildInfo
39+
3840
compatibleMode bool
3941
topologyInfo labelsGetter
4042
}
4143

4244
// newDiagnosticDataCollector creates a collector for diagnostic information.
43-
func newDiagnosticDataCollector(ctx context.Context, client *mongo.Client, logger *logrus.Logger, compatible bool, topology labelsGetter) *diagnosticDataCollector {
45+
func newDiagnosticDataCollector(ctx context.Context, client *mongo.Client, logger *logrus.Logger, compatible bool, topology labelsGetter, buildInfo buildInfo) *diagnosticDataCollector {
4446
nodeType, err := getNodeType(ctx, client)
4547
if err != nil {
4648
logger.WithFields(logrus.Fields{
@@ -57,6 +59,8 @@ func newDiagnosticDataCollector(ctx context.Context, client *mongo.Client, logge
5759
ctx: ctx,
5860
base: newBaseCollector(client, logger.WithFields(logrus.Fields{"collector": "diagnostic_data"})),
5961

62+
buildInfo: buildInfo,
63+
6064
compatibleMode: compatible,
6165
topologyInfo: topology,
6266
}
@@ -112,6 +116,21 @@ func (d *diagnosticDataCollector) collect(ch chan<- prometheus.Metric) {
112116
logger.Debug("getDiagnosticData result")
113117
debugResult(logger, m)
114118

119+
// MongoDB 8.0 splits the diagnostic data into multiple blocks, so we need to merge them
120+
if d.buildInfo.VersionArray[0] >= 8 { //nolint:gomnd
121+
b := bson.M{}
122+
for _, mv := range m {
123+
block, ok := mv.(bson.M)
124+
if !ok {
125+
continue
126+
}
127+
for k, v := range block {
128+
b[k] = v
129+
}
130+
}
131+
m = b
132+
}
133+
115134
metrics = makeMetrics("", m, d.topologyInfo.baseLabels(), d.compatibleMode)
116135
metrics = append(metrics, locksMetrics(logger, m)...)
117136

@@ -132,12 +151,7 @@ func (d *diagnosticDataCollector) collect(ch chan<- prometheus.Metric) {
132151
}
133152

134153
if d.compatibleMode {
135-
buildInfo, err := retrieveMongoDBBuildInfo(d.ctx, client, logger)
136-
if err != nil {
137-
logger.Errorf("cannot retrieve MongoDB buildInfo: %s", err)
138-
}
139-
140-
metrics = append(metrics, serverVersion(buildInfo))
154+
metrics = append(metrics, serverVersion(d.buildInfo))
141155

142156
if nodeType == typeArbiter {
143157
if hm := arbiterMetrics(d.ctx, client, logger); hm != nil {

exporter/diagnostic_data_collector_test.go

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -46,31 +46,36 @@ func TestDiagnosticDataCollector(t *testing.T) {
4646
logger := logrus.New()
4747
ti := labelsGetterMock{}
4848

49-
c := newDiagnosticDataCollector(ctx, client, logger, false, ti)
49+
dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, logger.WithField("component", "test"))
50+
require.NoError(t, err)
51+
52+
c := newDiagnosticDataCollector(ctx, client, logger, false, ti, dbBuildInfo)
53+
54+
prefix := "local.oplog.rs.stats.storageStats.wiredTiger"
55+
if dbBuildInfo.VersionArray[0] < 7 {
56+
prefix = "local.oplog.rs.stats.wiredTiger"
57+
}
5058

5159
// The last \n at the end of this string is important
52-
expected := strings.NewReader(`
53-
# HELP mongodb_oplog_stats_ok local.oplog.rs.stats.
54-
# TYPE mongodb_oplog_stats_ok untyped
55-
mongodb_oplog_stats_ok 1
56-
# HELP mongodb_oplog_stats_wt_btree_fixed_record_size local.oplog.rs.stats.wiredTiger.btree.
60+
expectedString := fmt.Sprintf(`
61+
# HELP mongodb_oplog_stats_wt_btree_fixed_record_size %s.btree.
5762
# TYPE mongodb_oplog_stats_wt_btree_fixed_record_size untyped
5863
mongodb_oplog_stats_wt_btree_fixed_record_size 0
59-
# HELP mongodb_oplog_stats_wt_transaction_update_conflicts local.oplog.rs.stats.wiredTiger.transaction.
64+
# HELP mongodb_oplog_stats_wt_transaction_update_conflicts %s.transaction.
6065
# TYPE mongodb_oplog_stats_wt_transaction_update_conflicts untyped
61-
mongodb_oplog_stats_wt_transaction_update_conflicts 0` + "\n")
66+
mongodb_oplog_stats_wt_transaction_update_conflicts 0`, prefix, prefix)
67+
expected := strings.NewReader(expectedString + "\n")
6268

6369
// Filter metrics for 2 reasons:
6470
// 1. The result is huge
6571
// 2. We need to check against know values. Don't use metrics that return counters like uptime
6672
// or counters like the number of transactions because they won't return a known value to compare
6773
filter := []string{
68-
"mongodb_oplog_stats_ok",
6974
"mongodb_oplog_stats_wt_btree_fixed_record_size",
7075
"mongodb_oplog_stats_wt_transaction_update_conflicts",
7176
}
7277

73-
err := testutil.CollectAndCompare(c, expected, filter...)
78+
err = testutil.CollectAndCompare(c, expected, filter...)
7479
assert.NoError(t, err)
7580
}
7681

@@ -188,7 +193,10 @@ func TestCollectorWithCompatibleMode(t *testing.T) {
188193
logger := logrus.New()
189194
ti := labelsGetterMock{}
190195

191-
c := newDiagnosticDataCollector(ctx, client, logger, true, ti)
196+
dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, logger.WithField("component", "test"))
197+
require.NoError(t, err)
198+
199+
c := newDiagnosticDataCollector(ctx, client, logger, true, ti, dbBuildInfo)
192200

193201
err = testutil.CollectAndCompare(c, tt.expectedMetrics(), tt.metricsFilter...)
194202
assert.NoError(t, err)
@@ -202,12 +210,16 @@ func TestAllDiagnosticDataCollectorMetrics(t *testing.T) {
202210

203211
client := tu.DefaultTestClient(ctx, t)
204212

205-
ti := newTopologyInfo(ctx, client, logrus.New())
213+
logger := logrus.New()
214+
ti := newTopologyInfo(ctx, client, logger)
206215

207-
c := newDiagnosticDataCollector(ctx, client, logrus.New(), true, ti)
216+
dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, logger.WithField("component", "test"))
217+
require.NoError(t, err)
218+
219+
c := newDiagnosticDataCollector(ctx, client, logger, true, ti, dbBuildInfo)
208220

209221
reg := prometheus.NewRegistry()
210-
err := reg.Register(c)
222+
err = reg.Register(c)
211223
require.NoError(t, err)
212224
metrics := helpers.CollectMetrics(c)
213225
actualMetrics := helpers.ReadMetrics(metrics)
@@ -281,7 +293,11 @@ func TestDiagnosticDataErrors(t *testing.T) {
281293

282294
logger, hook := logrustest.NewNullLogger()
283295
ti := newTopologyInfo(ctx, client, logger)
284-
c := newDiagnosticDataCollector(ctx, client, logger, true, ti)
296+
297+
dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, logger.WithField("component", "test"))
298+
require.NoError(t, err)
299+
300+
c := newDiagnosticDataCollector(ctx, client, logger, true, ti, dbBuildInfo)
285301

286302
reg := prometheus.NewRegistry()
287303
err = reg.Register(c)
@@ -318,19 +334,23 @@ func TestContextTimeout(t *testing.T) {
318334

319335
client := tu.DefaultTestClient(ctx, t)
320336

321-
ti := newTopologyInfo(ctx, client, logrus.New())
337+
logger := logrus.New()
338+
ti := newTopologyInfo(ctx, client, logger)
339+
340+
dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, logger.WithField("component", "test"))
341+
require.NoError(t, err)
322342

323343
dbCount := 100
324344

325-
err := addTestData(ctx, client, dbCount)
345+
err = addTestData(ctx, client, dbCount)
326346
assert.NoError(t, err)
327347

328348
defer cleanTestData(ctx, client, dbCount) //nolint:errcheck
329349

330350
cctx, ccancel := context.WithCancel(context.Background())
331351
ccancel()
332352

333-
c := newDiagnosticDataCollector(cctx, client, logrus.New(), true, ti)
353+
c := newDiagnosticDataCollector(cctx, client, logger, true, ti, dbBuildInfo)
334354
// it should not panic
335355
helpers.CollectMetrics(c)
336356
}
@@ -403,7 +423,7 @@ func cleanTestData(ctx context.Context, client *mongo.Client, count int) error {
403423
}
404424

405425
func TestDisconnectedDiagnosticDataCollector(t *testing.T) {
406-
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
426+
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
407427
defer cancel()
408428

409429
client := tu.DefaultTestClient(ctx, t)
@@ -415,7 +435,10 @@ func TestDisconnectedDiagnosticDataCollector(t *testing.T) {
415435

416436
ti := labelsGetterMock{}
417437

418-
c := newDiagnosticDataCollector(ctx, client, logger, true, ti)
438+
dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, logger.WithField("component", "test"))
439+
require.Error(t, err)
440+
441+
c := newDiagnosticDataCollector(ctx, client, logger, true, ti, dbBuildInfo)
419442

420443
// The last \n at the end of this string is important
421444
expected := strings.NewReader(`

exporter/encryption_info_test.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/prometheus/client_golang/prometheus/testutil"
2626
"github.com/sirupsen/logrus"
2727
"github.com/stretchr/testify/assert"
28+
"github.com/stretchr/testify/require"
2829

2930
"github.com/percona/mongodb_exporter/internal/tu"
3031
)
@@ -45,7 +46,10 @@ func TestGetEncryptionInfo(t *testing.T) {
4546

4647
ti := labelsGetterMock{}
4748

48-
c := newDiagnosticDataCollector(ctx, client, logger, true, ti)
49+
dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, logger.WithField("component", "test"))
50+
require.NoError(t, err)
51+
52+
c := newDiagnosticDataCollector(ctx, client, logger, true, ti, dbBuildInfo)
4953

5054
// The last \n at the end of this string is important
5155
expected := strings.NewReader(`
@@ -61,6 +65,6 @@ func TestGetEncryptionInfo(t *testing.T) {
6165
"mongodb_version_info",
6266
}
6367

64-
err := testutil.CollectAndCompare(c, expected, filter...)
68+
err = testutil.CollectAndCompare(c, expected, filter...)
6569
assert.NoError(t, err)
6670
}

exporter/exporter.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -134,16 +134,17 @@ func (e *Exporter) makeRegistry(ctx context.Context, client *mongo.Client, topol
134134

135135
nodeType, err := getNodeType(ctx, client)
136136
if err != nil {
137-
e.logger.Errorf("Registry - Cannot get node type to check if this is a mongos : %s", err)
137+
e.logger.Errorf("Registry - Cannot get node type : %s", err)
138+
}
139+
140+
dbBuildInfo, err := retrieveMongoDBBuildInfo(ctx, client, e.logger.WithField("component", "buildInfo"))
141+
if err != nil {
142+
e.logger.Warnf("Registry - Cannot get MongoDB buildInfo: %s", err)
138143
}
139144

140145
gc := newGeneralCollector(ctx, client, nodeType, e.opts.Logger)
141146
registry.MustRegister(gc)
142147

143-
if client == nil {
144-
return registry
145-
}
146-
147148
// Enable collectors like collstats and indexstats depending on the number of collections
148149
// present in the database.
149150
limitsOk := false
@@ -203,7 +204,7 @@ func (e *Exporter) makeRegistry(ctx context.Context, client *mongo.Client, topol
203204

204205
if e.opts.EnableDiagnosticData && requestOpts.EnableDiagnosticData {
205206
ddc := newDiagnosticDataCollector(ctx, client, e.opts.Logger,
206-
e.opts.CompatibleMode, topologyInfo)
207+
e.opts.CompatibleMode, topologyInfo, dbBuildInfo)
207208
registry.MustRegister(ddc)
208209
}
209210

@@ -335,13 +336,18 @@ func (e *Exporter) Handler() http.Handler {
335336
gatherers = append(gatherers, prometheus.DefaultGatherer)
336337
}
337338

339+
var registry *prometheus.Registry
338340
var ti *topologyInfo
339341
if client != nil {
340342
// Topology can change between requests, so we need to get it every time.
341343
ti = newTopologyInfo(ctx, client, e.logger)
344+
registry = e.makeRegistry(ctx, client, ti, requestOpts)
345+
} else {
346+
registry = prometheus.NewRegistry()
347+
gc := newGeneralCollector(ctx, client, "", e.opts.Logger)
348+
registry.MustRegister(gc)
342349
}
343350

344-
registry := e.makeRegistry(ctx, client, ti, requestOpts)
345351
gatherers = append(gatherers, registry)
346352

347353
// Delegate http serving to Prometheus client library, which will call collector.Collect.

exporter/exporter_test.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,7 @@ func TestMongoS(t *testing.T) {
186186
assert.NoError(t, err)
187187

188188
e := New(exporterOpts)
189-
190-
rsgsc := newReplicationSetStatusCollector(ctx, client, e.opts.Logger,
191-
e.opts.CompatibleMode, new(labelsGetterMock))
189+
rsgsc := newReplicationSetStatusCollector(ctx, client, e.opts.Logger, e.opts.CompatibleMode, new(labelsGetterMock))
192190

193191
r := e.makeRegistry(ctx, client, new(labelsGetterMock), *e.opts)
194192

exporter/feature_compatibility_version_collector_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ func TestFCVCollector(t *testing.T) {
5555
mversion = "4.4"
5656
case mmv == "4.4":
5757
mversion = "4.2"
58+
case mmv == "6.0":
59+
mversion = "5.0"
60+
case mmv == "7.0":
61+
mversion = "6.0"
62+
case mmv == "8.0":
63+
mversion = "7.0"
64+
default:
65+
mversion = mmv
5866
}
5967

6068
// The last \n at the end of this string is important

exporter/general_collector.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,11 @@ func mongodbUpMetric(ctx context.Context, client *mongo.Client, nodeType mongoDB
6363
} else {
6464
log.Errorf("error while checking mongodb connection: %s. mongo_up is set to 0", err.Error())
6565
}
66-
6766
switch nodeType { //nolint:exhaustive
68-
case typeMongos:
69-
clusterRole = typeMongos
70-
case typeArbiter:
71-
clusterRole = typeArbiter
72-
default:
67+
case typeShardServer:
7368
clusterRole = typeMongod
69+
default:
70+
clusterRole = nodeType
7471
}
7572
}
7673

exporter/metrics.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,14 @@ var (
5252
prefixes = [][]string{
5353
{"serverStatus.wiredTiger.transaction", "ss_wt_txn"},
5454
{"serverStatus.wiredTiger", "ss_wt"},
55+
{"serverStatus.queues.execution", "ss_wt_concurrentTransactions"},
5556
{"serverStatus", "ss"},
5657
{"replSetGetStatus", "rs"},
5758
{"systemMetrics", "sys"},
5859
{"local.oplog.rs.stats.wiredTiger", "oplog_stats_wt"},
60+
{"local.oplog.rs.stats.storageStats.wiredTiger", "oplog_stats_wt"},
5961
{"local.oplog.rs.stats", "oplog_stats"},
62+
{"local.oplog.rs.stats.storageStats", "oplog_stats"},
6063
{"collstats_storage.wiredTiger", "collstats_storage_wt"},
6164
{"collstats_storage.indexDetails", "collstats_storage_idx"},
6265
{"collStats.storageStats", "collstats_storage"},
@@ -105,6 +108,7 @@ var (
105108
"serverStatus.opcountersRepl.": "legacy_op_type",
106109
"serverStatus.transactions.commitTypes.": "commit_type",
107110
"serverStatus.wiredTiger.concurrentTransactions.": "txn_rw_type",
111+
"serverStatus.queues.execution.": "txn_rw_type",
108112
"serverStatus.wiredTiger.perf.": "perf_bucket",
109113
"systemMetrics.disks.": "device_name",
110114
}

exporter/secondary_lag_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323

2424
"github.com/prometheus/client_golang/prometheus"
2525
dto "github.com/prometheus/client_model/go"
26+
"github.com/sirupsen/logrus"
2627
"github.com/stretchr/testify/assert"
2728
"github.com/stretchr/testify/require"
2829
"go.mongodb.org/mongo-driver/bson"
@@ -126,7 +127,7 @@ func TestSecondaryLag(t *testing.T) {
126127
assert.NoError(t, err)
127128

128129
m, _ = m["data"].(bson.M)
129-
metrics := replSetMetrics(m)
130+
metrics := replSetMetrics(m, logrus.WithField("component", "test"))
130131
var lag prometheus.Metric
131132
for _, m := range metrics {
132133
if strings.HasPrefix(m.Desc().String(), `Desc{fqName: "mongodb_mongod_replset_member_replication_lag"`) {

0 commit comments

Comments
 (0)