@@ -93,24 +93,68 @@ var (
9393 // mongodb_ss_opcounters{legacy_op_type="command"} 67923
9494 //
9595 nodeToPDMetrics = map [string ]string {
96- "collStats.storageStats.indexDetails." : "index_name" ,
97- "globalLock.activeQueue." : "count_type" ,
98- "globalLock.locks." : "lock_type" ,
99- "serverStatus.asserts." : "assert_type" ,
100- "serverStatus.connections." : "conn_type" ,
101- "serverStatus.globalLock.currentQueue." : "count_type" ,
102- "serverStatus.metrics.commands." : "cmd_name" ,
103- "serverStatus.metrics.cursor.open." : "csr_type" ,
104- "serverStatus.metrics.document." : "doc_op_type" ,
105- "serverStatus.opLatencies." : "op_type" ,
106- "serverStatus.opReadConcernCounters." : "concern_type" ,
107- "serverStatus.opcounters." : "legacy_op_type" ,
108- "serverStatus.opcountersRepl." : "legacy_op_type" ,
109- "serverStatus.transactions.commitTypes." : "commit_type" ,
110- "serverStatus.wiredTiger.concurrentTransactions." : "txn_rw_type" ,
111- "serverStatus.queues.execution." : "txn_rw_type" ,
112- "serverStatus.wiredTiger.perf." : "perf_bucket" ,
113- "systemMetrics.disks." : "device_name" ,
96+ "collStats.storageStats.indexDetails." : "index_name" ,
97+ "globalLock.activeQueue." : "count_type" ,
98+ "globalLock.locks." : "lock_type" ,
99+ "serverStatus.asserts." : "assert_type" ,
100+ "serverStatus.connections." : "conn_type" ,
101+ "serverStatus.globalLock.currentQueue." : "count_type" ,
102+ "serverStatus.metrics.commands." : "cmd_name" ,
103+ "serverStatus.metrics.cursor.open." : "csr_type" ,
104+ "serverStatus.metrics.document." : "doc_op_type" ,
105+ "serverStatus.opLatencies." : "op_type" ,
106+ "serverStatus.opReadConcernCounters." : "concern_type" ,
107+ "serverStatus.opcounters." : "legacy_op_type" ,
108+ "serverStatus.opcountersRepl." : "legacy_op_type" ,
109+ "serverStatus.transactions.commitTypes." : "commit_type" ,
110+ "serverStatus.wiredTiger.concurrentTransactions." : "txn_rw_type" ,
111+ "serverStatus.queues.execution." : "txn_rw_type" ,
112+ "serverStatus.wiredTiger.perf." : "perf_bucket" ,
113+ "systemMetrics.disks." : "device_name" ,
114+ "collstats.storageStats.indexSizes." : "index_name" ,
115+ "config.transactions.stats.storageStats.indexSizes." : "index_name" ,
116+ "config.image_collection.stats.storageStats.indexSizes." : "index_name" ,
117+ }
118+
119+ // This map is used to add labels to some specific metrics.
120+ // The difference from the case above that it works with middle nodes in the structure.
121+ // For example, the fields under the storageStats.indexDetails. structure have this
122+ // signature:
123+ //
124+ // "storageStats": primitive.M{
125+ // "indexDetails": primitive.M{
126+ // "_id_": primitive.M{
127+ // "LSM": primitive.M{
128+ // "bloom filter false positives": int32(0),
129+ // "bloom filter hits": int32(0),
130+ // "bloom filter misses": int32(0),
131+ // ...
132+ // },
133+ // "block-manager": primitive.M{
134+ // "allocations requiring file extension": int32(0),
135+ // ...
136+ // },
137+ // ...
138+ // },
139+ // "name_1": primitive.M{
140+ // ...
141+ // },
142+ // ...
143+ // },
144+ // },
145+ //
146+ // Applying the renaming rules, storageStats will become storageStats but instead of having metrics
147+ // with the form storageStats.indexDetails.<index_name>.<metric_name> where index_name is each one of
148+ // the fields inside the structure (_id_, name_1, etc), those keys will become labels for the same
149+ // metric name. The label name is defined as the value for each metric name in the map and the value
150+ // the label will have is the field name in the structure. Example.
151+ //
152+ // mongodb_storageStats_indexDetails_index_name_LSM_bloom_filter_false_positives{index_name="_id_"} 0
153+ keyNodesToLabels = map [string ]string {
154+ "storageStats.indexDetails." : "index_name" ,
155+ "config.image_collection.stats.storageStats.indexDetails." : "index_name" ,
156+ "config.transactions.stats.storageStats.indexDetails." : "index_name" ,
157+ "collstats.storageStats.indexDetails." : "index_name" ,
114158 }
115159
116160 // Regular expressions used to make the metric name Prometheus-compatible
@@ -236,8 +280,11 @@ func rawToPrometheusMetric(rm *rawMetric) (prometheus.Metric, error) {
236280// by prometheus. For first level metrics, there is no prefix so we should use the metric name or
237281// the help would be empty.
238282func metricHelp (prefix , name string ) string {
283+ if _ , ok := nodeToPDMetrics [prefix ]; ok {
284+ return strings .TrimSuffix (prefix , "." )
285+ }
239286 if prefix != "" {
240- return prefix
287+ return prefix + name
241288 }
242289
243290 return name
@@ -251,17 +298,29 @@ func makeMetrics(prefix string, m bson.M, labels map[string]string, compatibleMo
251298 }
252299
253300 for k , val := range m {
301+ nextPrefix := prefix + k
302+
303+ l := make (map [string ]string )
304+ if label , ok := keyNodesToLabels [prefix ]; ok {
305+ for k , v := range labels {
306+ l [k ] = v
307+ }
308+ l [label ] = k
309+ nextPrefix = prefix + label
310+ } else {
311+ l = labels
312+ }
254313 switch v := val .(type ) {
255314 case bson.M :
256- res = append (res , makeMetrics (prefix + k , v , labels , compatibleMode )... )
315+ res = append (res , makeMetrics (nextPrefix , v , l , compatibleMode )... )
257316 case map [string ]interface {}:
258- res = append (res , makeMetrics (prefix + k , v , labels , compatibleMode )... )
317+ res = append (res , makeMetrics (nextPrefix , v , l , compatibleMode )... )
259318 case primitive.A :
260- res = append (res , processSlice (prefix , k , v , labels , compatibleMode )... )
319+ res = append (res , processSlice (nextPrefix , v , l , compatibleMode )... )
261320 case []interface {}:
262321 continue
263322 default :
264- rm , err := makeRawMetric (prefix , k , v , labels )
323+ rm , err := makeRawMetric (prefix , k , v , l )
265324 if err != nil {
266325 invalidMetric := prometheus .NewInvalidMetric (prometheus .NewInvalidDesc (err ), err )
267326 res = append (res , invalidMetric )
@@ -302,7 +361,7 @@ func makeMetrics(prefix string, m bson.M, labels map[string]string, compatibleMo
302361
303362// Extract maps from arrays. Only some structures like replicasets have arrays of members
304363// and each member is represented by a map[string]interface{}.
305- func processSlice (prefix , k string , v []interface {}, commonLabels map [string ]string , compatibleMode bool ) []prometheus.Metric {
364+ func processSlice (prefix string , v []interface {}, commonLabels map [string ]string , compatibleMode bool ) []prometheus.Metric {
306365 metrics := make ([]prometheus.Metric , 0 )
307366 labels := make (map [string ]string )
308367 for name , value := range commonLabels {
@@ -332,7 +391,7 @@ func processSlice(prefix, k string, v []interface{}, commonLabels map[string]str
332391 labels ["member_idx" ] = host
333392 }
334393
335- metrics = append (metrics , makeMetrics (prefix + k , s , labels , compatibleMode )... )
394+ metrics = append (metrics , makeMetrics (prefix , s , labels , compatibleMode )... )
336395 }
337396
338397 return metrics
0 commit comments