1616package exporter
1717
1818import (
19+ "context"
1920 "regexp"
21+ "slices"
2022 "strings"
2123 "sync"
2224 "time"
@@ -25,6 +27,7 @@ import (
2527 "github.com/prometheus/client_golang/prometheus"
2628 "go.mongodb.org/mongo-driver/bson"
2729 "go.mongodb.org/mongo-driver/bson/primitive"
30+ "go.mongodb.org/mongo-driver/mongo"
2831)
2932
3033const (
@@ -206,7 +209,7 @@ func nameAndLabel(prefix, name string) (string, string) {
206209
207210// makeRawMetric creates a Prometheus metric based on the parameters we collected by
208211// traversing the MongoDB structures returned by the collector functions.
209- func makeRawMetric (prefix , name string , value interface {}, labels map [string ]string ) (* rawMetric , error ) {
212+ func makeRawMetric (reservedNames [] string , prefix , name string , value interface {}, labels map [string ]string ) (* rawMetric , error ) {
210213 f , err := asFloat64 (value )
211214 if err != nil {
212215 return nil , err
@@ -220,8 +223,10 @@ func makeRawMetric(prefix, name string, value interface{}, labels map[string]str
220223 fqName , label := nameAndLabel (prefix , name )
221224
222225 metricType := prometheus .UntypedValue
223- if strings .HasSuffix (strings .ToLower (name ), "count" ) {
224- metricType = prometheus .CounterValue
226+ if ! slices .Contains (reservedNames , name ) {
227+ if strings .HasSuffix (strings .ToLower (name ), "count" ) {
228+ metricType = prometheus .CounterValue
229+ }
225230 }
226231
227232 rm := & rawMetric {
@@ -301,7 +306,41 @@ func metricHelp(prefix, name string) string {
301306 return name
302307}
303308
304- func makeMetrics (prefix string , m bson.M , labels map [string ]string , compatibleMode bool ) []prometheus.Metric {
309+ // GetAllIndexesForCollections returns all index names for the given list of "db.collection" strings.
310+ func GetAllIndexesForCollections (ctx context.Context , client * mongo.Client , collections []string ) ([]string , error ) {
311+ var indexNames []string
312+
313+ for _ , dbCollection := range collections {
314+ parts := strings .SplitN (dbCollection , "." , 2 )
315+ if len (parts ) != 2 {
316+ continue // skip invalid format
317+ }
318+ dbName := parts [0 ]
319+ collName := parts [1 ]
320+
321+ coll := client .Database (dbName ).Collection (collName )
322+ cursor , err := coll .Indexes ().List (ctx )
323+ if err != nil {
324+ // skip collections where indexes cannot be listed (e.g., views, system collections)
325+ continue
326+ }
327+ defer cursor .Close (ctx )
328+
329+ for cursor .Next (ctx ) {
330+ var idxDoc struct {
331+ Name string `bson:"name"`
332+ }
333+ if err := cursor .Decode (& idxDoc ); err != nil {
334+ continue
335+ }
336+ indexNames = append (indexNames , idxDoc .Name )
337+ }
338+ }
339+
340+ return indexNames , nil
341+ }
342+
343+ func makeMetrics (reservedNames []string , prefix string , m bson.M , labels map [string ]string , compatibleMode bool ) []prometheus.Metric {
305344 var res []prometheus.Metric
306345
307346 if prefix != "" {
@@ -327,15 +366,15 @@ func makeMetrics(prefix string, m bson.M, labels map[string]string, compatibleMo
327366 }
328367 switch v := val .(type ) {
329368 case bson.M :
330- res = append (res , makeMetrics (nextPrefix , v , l , compatibleMode )... )
369+ res = append (res , makeMetrics (reservedNames , nextPrefix , v , l , compatibleMode )... )
331370 case map [string ]interface {}:
332- res = append (res , makeMetrics (nextPrefix , v , l , compatibleMode )... )
371+ res = append (res , makeMetrics (reservedNames , nextPrefix , v , l , compatibleMode )... )
333372 case primitive.A :
334- res = append (res , processSlice (nextPrefix , v , l , compatibleMode )... )
373+ res = append (res , processSlice (reservedNames , nextPrefix , v , l , compatibleMode )... )
335374 case []interface {}:
336375 continue
337376 default :
338- rm , err := makeRawMetric (prefix , k , v , l )
377+ rm , err := makeRawMetric (reservedNames , prefix , k , v , l )
339378 if err != nil {
340379 invalidMetric := prometheus .NewInvalidMetric (prometheus .NewInvalidDesc (err ), err )
341380 res = append (res , invalidMetric )
@@ -376,7 +415,7 @@ func makeMetrics(prefix string, m bson.M, labels map[string]string, compatibleMo
376415
377416// Extract maps from arrays. Only some structures like replicasets have arrays of members
378417// 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 {
418+ func processSlice (reservedNames [] string , prefix string , v []interface {}, commonLabels map [string ]string , compatibleMode bool ) []prometheus.Metric {
380419 metrics := make ([]prometheus.Metric , 0 )
381420 labels := make (map [string ]string )
382421 for name , value := range commonLabels {
@@ -406,7 +445,7 @@ func processSlice(prefix string, v []interface{}, commonLabels map[string]string
406445 labels ["member_idx" ] = host
407446 }
408447
409- metrics = append (metrics , makeMetrics (prefix , s , labels , compatibleMode )... )
448+ metrics = append (metrics , makeMetrics (reservedNames , prefix , s , labels , compatibleMode )... )
410449 }
411450
412451 return metrics
0 commit comments