1616package exporter
1717
1818import (
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
3034const (
@@ -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
0 commit comments