@@ -22,6 +22,7 @@ import (
22
22
"fmt"
23
23
"net/http"
24
24
"os"
25
+ "strconv"
25
26
"sync"
26
27
"time"
27
28
@@ -96,7 +97,7 @@ func New(opts *Opts) *Exporter {
96
97
opts : opts ,
97
98
webListenAddress : opts .WebListenAddress ,
98
99
lock : & sync.Mutex {},
99
- totalCollectionsCount : - 1 , // not calculated yet. waiting the db connection.
100
+ totalCollectionsCount : - 1 , // Not calculated yet. waiting the db connection.
100
101
}
101
102
// Try initial connect. Connection will be retried with every scrape.
102
103
go func () {
@@ -116,7 +117,7 @@ func (e *Exporter) getTotalCollectionsCount() int {
116
117
return e .totalCollectionsCount
117
118
}
118
119
119
- func (e * Exporter ) makeRegistry (ctx context.Context , client * mongo.Client , topologyInfo labelsGetter ) * prometheus.Registry {
120
+ func (e * Exporter ) makeRegistry (ctx context.Context , client * mongo.Client , topologyInfo labelsGetter , requestOpts Opts ) * prometheus.Registry {
120
121
registry := prometheus .NewRegistry ()
121
122
122
123
gc := generalCollector {
@@ -135,11 +136,11 @@ func (e *Exporter) makeRegistry(ctx context.Context, client *mongo.Client, topol
135
136
e .logger .Errorf ("Cannot get node type to check if this is a mongos: %s" , err )
136
137
}
137
138
138
- // enable collectors like collstats and indexstats depending on the number of collections
139
+ // Enable collectors like collstats and indexstats depending on the number of collections
139
140
// present in the database.
140
141
limitsOk := false
141
- if e .opts .CollStatsLimit = = 0 || // Unlimited
142
- ( e .getTotalCollectionsCount () > 0 && e . getTotalCollectionsCount () < e .opts .CollStatsLimit ) {
142
+ if e .opts .CollStatsLimit < = 0 || // Unlimited
143
+ e .getTotalCollectionsCount () <= e .opts .CollStatsLimit {
143
144
limitsOk = true
144
145
}
145
146
@@ -149,12 +150,14 @@ func (e *Exporter) makeRegistry(ctx context.Context, client *mongo.Client, topol
149
150
}
150
151
e .opts .EnableDiagnosticData = true
151
152
e .opts .EnableDBStats = true
153
+ e .opts .EnableCollStats = true
152
154
e .opts .EnableTopMetrics = true
153
155
e .opts .EnableReplicasetStatus = true
156
+ e .opts .EnableIndexStats = true
154
157
}
155
158
156
- // if we manually set the collection names we want or auto discovery is set
157
- if (len (e .opts .CollStatsNamespaces ) > 0 || e .opts .DiscoveringMode ) && e .opts .EnableCollStats && limitsOk {
159
+ // If we manually set the collection names we want or auto discovery is set.
160
+ if (len (e .opts .CollStatsNamespaces ) > 0 || e .opts .DiscoveringMode ) && e .opts .EnableCollStats && limitsOk && requestOpts . EnableCollStats {
158
161
cc := collstatsCollector {
159
162
ctx : ctx ,
160
163
client : client ,
@@ -167,8 +170,8 @@ func (e *Exporter) makeRegistry(ctx context.Context, client *mongo.Client, topol
167
170
registry .MustRegister (& cc )
168
171
}
169
172
170
- // if we manually set the collection names we want or auto discovery is set
171
- if (len (e .opts .IndexStatsCollections ) > 0 || e .opts .DiscoveringMode ) && e .opts .EnableIndexStats && limitsOk {
173
+ // If we manually set the collection names we want or auto discovery is set.
174
+ if (len (e .opts .IndexStatsCollections ) > 0 || e .opts .DiscoveringMode ) && e .opts .EnableIndexStats && limitsOk && requestOpts . EnableIndexStats {
172
175
ic := indexstatsCollector {
173
176
ctx : ctx ,
174
177
client : client ,
@@ -180,7 +183,7 @@ func (e *Exporter) makeRegistry(ctx context.Context, client *mongo.Client, topol
180
183
registry .MustRegister (& ic )
181
184
}
182
185
183
- if e .opts .EnableDiagnosticData {
186
+ if e .opts .EnableDiagnosticData && requestOpts . EnableDiagnosticData {
184
187
ddc := diagnosticDataCollector {
185
188
ctx : ctx ,
186
189
client : client ,
@@ -191,7 +194,7 @@ func (e *Exporter) makeRegistry(ctx context.Context, client *mongo.Client, topol
191
194
registry .MustRegister (& ddc )
192
195
}
193
196
194
- if e .opts .EnableDBStats {
197
+ if e .opts .EnableDBStats && requestOpts . EnableDBStats {
195
198
cc := dbstatsCollector {
196
199
ctx : ctx ,
197
200
client : client ,
@@ -202,7 +205,7 @@ func (e *Exporter) makeRegistry(ctx context.Context, client *mongo.Client, topol
202
205
registry .MustRegister (& cc )
203
206
}
204
207
205
- if e .opts .EnableTopMetrics && nodeType != typeMongos {
208
+ if e .opts .EnableTopMetrics && nodeType != typeMongos && requestOpts . EnableTopMetrics {
206
209
tc := topCollector {
207
210
ctx : ctx ,
208
211
client : client ,
@@ -213,8 +216,8 @@ func (e *Exporter) makeRegistry(ctx context.Context, client *mongo.Client, topol
213
216
registry .MustRegister (& tc )
214
217
}
215
218
216
- // replSetGetStatus is not supported through mongos
217
- if e .opts .EnableReplicasetStatus && nodeType != typeMongos {
219
+ // replSetGetStatus is not supported through mongos.
220
+ if e .opts .EnableReplicasetStatus && nodeType != typeMongos && requestOpts . EnableReplicasetStatus {
218
221
rsgsc := replSetGetStatusCollector {
219
222
ctx : ctx ,
220
223
client : client ,
@@ -230,17 +233,17 @@ func (e *Exporter) makeRegistry(ctx context.Context, client *mongo.Client, topol
230
233
231
234
func (e * Exporter ) getClient (ctx context.Context ) (* mongo.Client , error ) {
232
235
if e .opts .GlobalConnPool {
233
- // get global client. Maybe it must be initialized first.
236
+ // Get global client. Maybe it must be initialized first.
234
237
// Initialization is retried with every scrape until it succeeds once.
235
238
e .clientMu .Lock ()
236
239
defer e .clientMu .Unlock ()
237
240
238
- // if client is already initialized, return it
241
+ // If client is already initialized, return it.
239
242
if e .client != nil {
240
243
return e .client , nil
241
244
}
242
245
243
- client , err := connect (ctx , e .opts .URI , e .opts .DirectConnect )
246
+ client , err := connect (context . Background () , e .opts .URI , e .opts .DirectConnect )
244
247
if err != nil {
245
248
return nil , err
246
249
}
@@ -249,7 +252,7 @@ func (e *Exporter) getClient(ctx context.Context) (*mongo.Client, error) {
249
252
return client , nil
250
253
}
251
254
252
- // !e.opts.GlobalConnPool: create new client for every scrape
255
+ // !e.opts.GlobalConnPool: create new client for every scrape.
253
256
client , err := connect (ctx , e .opts .URI , e .opts .DirectConnect )
254
257
if err != nil {
255
258
return nil , err
@@ -259,19 +262,50 @@ func (e *Exporter) getClient(ctx context.Context) (*mongo.Client, error) {
259
262
}
260
263
261
264
// Handler returns an http.Handler that serves metrics. Can be used instead of
262
- // Run for hooking up custom HTTP servers.
265
+ // run for hooking up custom HTTP servers.
263
266
func (e * Exporter ) Handler () http.Handler {
264
267
return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
268
+ seconds , err := strconv .Atoi (r .Header .Get ("X-Prometheus-Scrape-Timeout-Seconds" ))
269
+ // To support also older ones vmagents.
270
+ if err != nil {
271
+ seconds = 10
272
+ }
273
+
265
274
var client * mongo.Client
266
- ctx , cancel := context .WithTimeout (r .Context (), time .Second )
275
+ ctx , cancel := context .WithTimeout (r .Context (), time .Duration ( seconds ) * time . Second )
267
276
defer cancel ()
268
277
269
- client , err := e .getClient (ctx )
278
+ filters := r .URL .Query ()["collect[]" ]
279
+
280
+ requestOpts := Opts {}
281
+
282
+ if len (filters ) == 0 {
283
+ requestOpts = * e .opts
284
+ }
285
+
286
+ for _ , filter := range filters {
287
+ switch filter {
288
+ case "diagnosticdata" :
289
+ requestOpts .EnableDiagnosticData = true
290
+ case "replicasetstatus" :
291
+ requestOpts .EnableReplicasetStatus = true
292
+ case "dbstats" :
293
+ requestOpts .EnableDBStats = true
294
+ case "topmetrics" :
295
+ requestOpts .EnableTopMetrics = true
296
+ case "indexstats" :
297
+ requestOpts .EnableIndexStats = true
298
+ case "collstats" :
299
+ requestOpts .EnableCollStats = true
300
+ }
301
+ }
302
+
303
+ client , err = e .getClient (ctx )
270
304
if err != nil {
271
305
e .logger .Errorf ("Cannot connect to MongoDB: %v" , err )
272
306
}
273
307
274
- if client != nil && e .getTotalCollectionsCount () < 0 {
308
+ if client != nil && e .getTotalCollectionsCount () <= 0 {
275
309
count , err := nonSystemCollectionsCount (ctx , client , nil , nil )
276
310
if err == nil {
277
311
e .lock .Lock ()
@@ -280,7 +314,7 @@ func (e *Exporter) Handler() http.Handler {
280
314
}
281
315
}
282
316
283
- // Close client after usage
317
+ // Close client after usage.
284
318
if ! e .opts .GlobalConnPool {
285
319
defer func () {
286
320
if client != nil {
@@ -292,7 +326,7 @@ func (e *Exporter) Handler() http.Handler {
292
326
}()
293
327
}
294
328
295
- // topology can change between requests, so we need to get it every time
329
+ // Topology can change between requests, so we need to get it every time.
296
330
var ti * topologyInfo
297
331
if client != nil {
298
332
ti , err = newTopologyInfo (ctx , client )
@@ -306,7 +340,7 @@ func (e *Exporter) Handler() http.Handler {
306
340
}
307
341
}
308
342
309
- registry := e .makeRegistry (ctx , client , ti )
343
+ registry := e .makeRegistry (ctx , client , ti , requestOpts )
310
344
311
345
var gatherers prometheus.Gatherers
312
346
0 commit comments