Skip to content

Commit c2fc3d3

Browse files
committed
PMM-14431 More complex check if it is real count or not.
1 parent c943d40 commit c2fc3d3

12 files changed

+143
-20
lines changed

exporter/collstats_collector.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ func (d *collstatsCollector) collect(ch chan<- prometheus.Metric) {
151151
labels["shard"] = shard
152152
}
153153

154-
for _, metric := range makeMetrics(prefix, metrics, labels, d.compatibleMode) {
154+
for _, metric := range makeMetrics(client, prefix, metrics, labels, d.compatibleMode) {
155155
ch <- metric
156156
}
157157
}

exporter/collstats_collector_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,72 @@ import (
2626
"github.com/prometheus/common/promslog"
2727
"github.com/stretchr/testify/assert"
2828
"go.mongodb.org/mongo-driver/bson"
29+
"go.mongodb.org/mongo-driver/mongo"
30+
"go.mongodb.org/mongo-driver/mongo/options"
2931

3032
"github.com/percona/mongodb_exporter/internal/tu"
3133
)
3234

35+
func TestCollStatsCollectorAccountIndexes(t *testing.T) {
36+
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
37+
defer cancel()
38+
39+
client := tu.DefaultTestClient(ctx, t)
40+
41+
database := client.Database("testdb")
42+
database.Drop(ctx) //nolint
43+
44+
defer func() {
45+
err := database.Drop(ctx)
46+
assert.NoError(t, err)
47+
}()
48+
49+
collName := "test_collection_account"
50+
coll := database.Collection(collName)
51+
52+
// Insert some data
53+
_, err := coll.InsertOne(ctx, bson.M{"account_id": 1, "count": 10})
54+
assert.NoError(t, err)
55+
_, err = coll.InsertOne(ctx, bson.M{"account_id": 2, "count": 20})
56+
assert.NoError(t, err)
57+
58+
// Create indexes
59+
indexModel := mongo.IndexModel{
60+
Keys: bson.D{{Key: "account_id", Value: 1}},
61+
Options: options.Index().SetName("test_index_account"),
62+
}
63+
_, err = coll.Indexes().CreateOne(ctx, indexModel)
64+
assert.NoError(t, err)
65+
66+
indexModel = mongo.IndexModel{
67+
Keys: bson.D{{Key: "count", Value: 1}},
68+
Options: options.Index().SetName("test_index_count"),
69+
}
70+
_, err = coll.Indexes().CreateOne(ctx, indexModel)
71+
assert.NoError(t, err)
72+
73+
ti := labelsGetterMock{}
74+
75+
collection := []string{"testdb.test_collection_account"}
76+
logger := promslog.New(&promslog.Config{})
77+
c := newCollectionStatsCollector(ctx, client, logger, false, ti, collection, false)
78+
79+
// Expected metrics (simplified, adjust values as needed)
80+
expected := strings.NewReader(`
81+
# HELP mongodb_collstats_storageStats_indexSizes collstats.storageStats.indexSizes
82+
# TYPE mongodb_collstats_storageStats_indexSizes untyped
83+
mongodb_collstats_storageStats_indexSizes{collection="test_collection_account",database="testdb",index_name="_id_"} 4096
84+
mongodb_collstats_storageStats_indexSizes{collection="test_collection_account",database="testdb",index_name="test_index_account"} 20480
85+
mongodb_collstats_storageStats_indexSizes{collection="test_collection_account",database="testdb",index_name="test_index_count"} 20480
86+
`)
87+
88+
filter := []string{
89+
"mongodb_collstats_storageStats_indexSizes",
90+
}
91+
err = testutil.CollectAndCompare(c, expected, filter...)
92+
assert.NoError(t, err)
93+
}
94+
3395
func TestCollStatsCollector(t *testing.T) {
3496
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
3597
defer cancel()

exporter/dbstats_collector.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ func (d *dbstatsCollector) collect(ch chan<- prometheus.Metric) {
100100
// to differentiate metrics between different databases.
101101
labels["database"] = db
102102

103-
newMetrics := makeMetrics(prefix, dbStats, labels, d.compatibleMode)
103+
newMetrics := makeMetrics(client, prefix, dbStats, labels, d.compatibleMode)
104104
for _, metric := range newMetrics {
105105
ch <- metric
106106
}

exporter/diagnostic_data_collector.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ func (d *diagnosticDataCollector) collect(ch chan<- prometheus.Metric) {
126126
m = b
127127
}
128128

129-
metrics = makeMetrics("", m, d.topologyInfo.baseLabels(), d.compatibleMode)
129+
metrics = makeMetrics(client, "", m, d.topologyInfo.baseLabels(), d.compatibleMode)
130130
metrics = append(metrics, locksMetrics(logger, m)...)
131131

132132
securityMetric, err := d.getSecurityMetricFromLineOptions(client)

exporter/indexstats_collector.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ func (d *indexstatsCollector) collect(ch chan<- prometheus.Metric) {
137137
labels["key_name"] = indexName
138138

139139
metrics := sanitizeMetrics(metric)
140-
for _, metric := range makeMetrics(prefix, metrics, labels, false) {
140+
for _, metric := range makeMetrics(d.base.client, prefix, metrics, labels, false) {
141141
ch <- metric
142142
}
143143
}

exporter/metrics.go

Lines changed: 71 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616
package exporter
1717

1818
import (
19+
"context"
20+
"fmt"
1921
"regexp"
22+
"slices"
2023
"strings"
2124
"sync"
2225
"time"
@@ -25,6 +28,7 @@ import (
2528
"github.com/prometheus/client_golang/prometheus"
2629
"go.mongodb.org/mongo-driver/bson"
2730
"go.mongodb.org/mongo-driver/bson/primitive"
31+
"go.mongodb.org/mongo-driver/mongo"
2832
)
2933

3034
const (
@@ -204,9 +208,58 @@ func nameAndLabel(prefix, name string) (string, string) {
204208
return prometheusize(prefix + name), ""
205209
}
206210

211+
func allReservedNames(client *mongo.Client) ([]string, error) {
212+
ctx := context.Background()
213+
reservedNames := []string{}
214+
dbs, err := client.ListDatabaseNames(ctx, struct{}{})
215+
if err != nil {
216+
return reservedNames, err
217+
}
218+
219+
for _, dbName := range dbs {
220+
fmt.Printf("Database: %s\n", dbName)
221+
db := client.Database(dbName)
222+
collCursor, err := db.ListCollections(ctx, struct{}{})
223+
if err != nil {
224+
return reservedNames, err
225+
}
226+
defer collCursor.Close(ctx)
227+
for collCursor.Next(ctx) {
228+
var collInfo struct {
229+
Name string `bson:"name"`
230+
Type string `bson:"type"`
231+
}
232+
if err := collCursor.Decode(&collInfo); err != nil {
233+
return reservedNames, err
234+
}
235+
reservedNames = append(reservedNames, collInfo.Name)
236+
if collInfo.Type == "view" {
237+
continue // skip views
238+
}
239+
coll := db.Collection(collInfo.Name)
240+
cursor, err := coll.Indexes().List(ctx)
241+
if err != nil {
242+
continue // skip if cannot list indexes
243+
}
244+
defer cursor.Close(ctx)
245+
for cursor.Next(ctx) {
246+
var indexDoc map[string]interface{}
247+
if err := cursor.Decode(&indexDoc); err != nil {
248+
continue
249+
}
250+
if name, ok := indexDoc["name"].(string); ok {
251+
reservedNames = append(reservedNames, name)
252+
}
253+
}
254+
}
255+
}
256+
257+
return reservedNames, nil
258+
}
259+
207260
// makeRawMetric creates a Prometheus metric based on the parameters we collected by
208261
// traversing the MongoDB structures returned by the collector functions.
209-
func makeRawMetric(prefix, name string, value interface{}, labels map[string]string) (*rawMetric, error) {
262+
func makeRawMetric(reservedNames []string, prefix, name string, value interface{}, labels map[string]string) (*rawMetric, error) {
210263
f, err := asFloat64(value)
211264
if err != nil {
212265
return nil, err
@@ -220,8 +273,10 @@ func makeRawMetric(prefix, name string, value interface{}, labels map[string]str
220273
fqName, label := nameAndLabel(prefix, name)
221274

222275
metricType := prometheus.UntypedValue
223-
if strings.HasSuffix(strings.ToLower(name), "count") {
224-
metricType = prometheus.CounterValue
276+
if !slices.Contains(reservedNames, name) {
277+
if strings.HasSuffix(strings.ToLower(name), "count") {
278+
metricType = prometheus.CounterValue
279+
}
225280
}
226281

227282
rm := &rawMetric{
@@ -301,7 +356,7 @@ func metricHelp(prefix, name string) string {
301356
return name
302357
}
303358

304-
func makeMetrics(prefix string, m bson.M, labels map[string]string, compatibleMode bool) []prometheus.Metric {
359+
func makeMetrics(client *mongo.Client, prefix string, m bson.M, labels map[string]string, compatibleMode bool) []prometheus.Metric {
305360
var res []prometheus.Metric
306361

307362
if prefix != "" {
@@ -327,15 +382,21 @@ func makeMetrics(prefix string, m bson.M, labels map[string]string, compatibleMo
327382
}
328383
switch v := val.(type) {
329384
case bson.M:
330-
res = append(res, makeMetrics(nextPrefix, v, l, compatibleMode)...)
385+
res = append(res, makeMetrics(client, nextPrefix, v, l, compatibleMode)...)
331386
case map[string]interface{}:
332-
res = append(res, makeMetrics(nextPrefix, v, l, compatibleMode)...)
387+
res = append(res, makeMetrics(client, nextPrefix, v, l, compatibleMode)...)
333388
case primitive.A:
334-
res = append(res, processSlice(nextPrefix, v, l, compatibleMode)...)
389+
res = append(res, processSlice(client, nextPrefix, v, l, compatibleMode)...)
335390
case []interface{}:
336391
continue
337392
default:
338-
rm, err := makeRawMetric(prefix, k, v, l)
393+
reservedNames, err := allReservedNames(client)
394+
if err != nil {
395+
fmt.Printf("\n\n\n cannot get reserved names: %v \n\n\n", err)
396+
continue
397+
}
398+
399+
rm, err := makeRawMetric(reservedNames, prefix, k, v, l)
339400
if err != nil {
340401
invalidMetric := prometheus.NewInvalidMetric(prometheus.NewInvalidDesc(err), err)
341402
res = append(res, invalidMetric)
@@ -376,7 +437,7 @@ func makeMetrics(prefix string, m bson.M, labels map[string]string, compatibleMo
376437

377438
// Extract maps from arrays. Only some structures like replicasets have arrays of members
378439
// and each member is represented by a map[string]interface{}.
379-
func processSlice(prefix string, v []interface{}, commonLabels map[string]string, compatibleMode bool) []prometheus.Metric {
440+
func processSlice(client *mongo.Client, prefix string, v []interface{}, commonLabels map[string]string, compatibleMode bool) []prometheus.Metric {
380441
metrics := make([]prometheus.Metric, 0)
381442
labels := make(map[string]string)
382443
for name, value := range commonLabels {
@@ -406,7 +467,7 @@ func processSlice(prefix string, v []interface{}, commonLabels map[string]string
406467
labels["member_idx"] = host
407468
}
408469

409-
metrics = append(metrics, makeMetrics(prefix, s, labels, compatibleMode)...)
470+
metrics = append(metrics, makeMetrics(client, prefix, s, labels, compatibleMode)...)
410471
}
411472

412473
return metrics

exporter/metrics_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ func TestMakeRawMetric(t *testing.T) {
166166
}
167167
}
168168

169-
m, err := makeRawMetric(prefix, name, tc.value, nil)
169+
m, err := makeRawMetric(nil, prefix, name, tc.value, nil)
170170

171171
assert.NoError(t, err)
172172
assert.Equal(t, want, m)

exporter/profile_status_collector.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ func (d *profileCollector) collect(ch chan<- prometheus.Metric) {
8888
logger.Debug("profile response from MongoDB:")
8989
debugResult(logger, primitive.M{db: m})
9090

91-
for _, metric := range makeMetrics("profile_slow_query", m, labels, d.compatibleMode) {
91+
for _, metric := range makeMetrics(client, "profile_slow_query", m, labels, d.compatibleMode) {
9292
ch <- metric
9393
}
9494
}

exporter/replset_config_collector.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ func (d *replSetGetConfigCollector) collect(ch chan<- prometheus.Metric) {
8686
logger.Debug("replSetGetConfig result:")
8787
debugResult(logger, m)
8888

89-
for _, metric := range makeMetrics("rs_cfg", m, d.topologyInfo.baseLabels(), d.compatibleMode) {
89+
for _, metric := range makeMetrics(client, "rs_cfg", m, d.topologyInfo.baseLabels(), d.compatibleMode) {
9090
ch <- metric
9191
}
9292
}

exporter/replset_status_collector.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ func (d *replSetGetStatusCollector) collect(ch chan<- prometheus.Metric) {
8181
logger.Debug("replSetGetStatus result:")
8282
debugResult(logger, m)
8383

84-
for _, metric := range makeMetrics("", m, d.topologyInfo.baseLabels(), d.compatibleMode) {
84+
for _, metric := range makeMetrics(client, "", m, d.topologyInfo.baseLabels(), d.compatibleMode) {
8585
ch <- metric
8686
}
8787
}

0 commit comments

Comments
 (0)