mongodb_plugin: replica set members state charts added
Ilya committed
Feb 23, 2017 at 02:18 UTC
e3c740c2bd0a54ab43af91338d4bcf3ef2574282
1 file changed
+109
-40
python.d/mongodb.chart.py
+109
-40
@@ -3,6 +3,7 @@
3
# Author: l2isbad
4
5
from base import SimpleService
6
+from copy import deepcopy
7
try:
8
from pymongo import MongoClient
9
from pymongo.errors import PyMongoError
@@ -15,6 +16,19 @@ except ImportError:
16
priority = 60000
17
retries = 60
18
19
+REPLSET_STATES = [
20
+ ('1', 'primary'),
21
+ ('8', 'down'),
22
+ ('2', 'secondary'),
23
+ ('3', 'recovering'),
24
+ ('5', 'startup2'),
25
+ ('4', 'fatal'),
26
+ ('7', 'arbiter'),
27
+ ('6', 'unknown'),
28
+ ('9', 'rollback'),
29
+ ('10', 'removed'),
30
+ ('0', 'startup')]
31
+
32
# charts order (can be overridden if you want less charts, or different order)
33
ORDER = ['read_operations', 'write_operations', 'active_clients', 'journaling_transactions',
34
'journaling_volume', 'background_flush_average', 'background_flush_last', 'background_flush_rate',
@@ -139,12 +153,11 @@ CHARTS = {
153
['errors_user', 'user', 'incremental', 1, 1]
154
]},
155
'wiredtiger_cache': {
142
- 'options': [None, "Amount of space taken by cached data/dirty data in the cache and maximum cache size",
156
+ 'options': [None, "Amount of space taken by cached data and by dirty data in the cache",
157
"KB", 'resource utilization', 'mongodb.wiredtiger_cache', 'stacked'],
158
'lines': [
159
['wiredTiger_bytes_in_cache', 'cached', 'absolute', 1, 1024],
146
- ['wiredTiger_dirty_in_cache', 'dirty', 'absolute', 1, 1024],
147
- ['wiredTiger_maximum_in_conf', 'maximum', 'absolute', 1, 1024]
160
+ ['wiredTiger_dirty_in_cache', 'dirty', 'absolute', 1, 1024]
161
]},
162
'wiredtiger_pages_evicted': {
163
'options': [None, "Pages evicted from the cache",
@@ -218,6 +231,8 @@ class Service(SimpleService):
231
self.error(error)
232
return False
233
234
+ self.repl = 'repl' in server_status
235
+ self.databases = self.connection.database_names()
236
self._create_charts(server_status)
237
238
return True
@@ -225,7 +240,7 @@ class Service(SimpleService):
240
def _create_charts(self, server_status):
241
242
self.order = ORDER[:]
228
- self.definitions = CHARTS
243
+ self.definitions = deepcopy(CHARTS)
244
self.ss = dict()
245
246
for elem in ['dur', 'backgroundFlushing', 'wiredTiger', 'tcmalloc', 'cursor', 'commands']:
@@ -255,8 +270,6 @@ class Service(SimpleService):
270
self.order.remove('command_total_rate')
271
self.order.remove('command_failed_rate')
272
258
- self.databases = self.connection.database_names()
259
-
273
for dbase in self.databases:
274
self.order.append('_'.join([dbase, 'dbstats']))
275
self.definitions['_'.join([dbase, 'dbstats'])] = {
@@ -269,17 +282,61 @@ class Service(SimpleService):
282
]}
283
self.definitions['dbstats_objects']['lines'].append(['_'.join([dbase, 'objects']), dbase, 'absolute'])
284
285
+ if server_status.get('repl'):
286
+ hosts = server_status['repl']['hosts']
287
+ for host in hosts:
288
+ chart_name = '_'.join([host, 'state'])
289
+ self.order.append(chart_name)
290
+ self.definitions[chart_name] = {
291
+ 'options': [None, "%s state" % host, "state",
292
+ 'replication', 'mongodb.replication_state', 'line'],
293
+ 'lines': [
294
+ ]}
295
+ for state, description in REPLSET_STATES:
296
+ self.definitions[chart_name]['lines'].append(['_'.join([host, 'state', state]), description, 'absolute', 1, 1])
297
+
298
+
299
300
def _get_raw_data(self):
301
raw_data = dict()
302
303
+ raw_data.update(self.get_serverstatus_() or dict())
304
+ raw_data.update(self.get_dbstats_() or dict())
305
+ raw_data.update(self.get_replsetgetstatus_() or dict())
306
+
307
+ return raw_data or None
308
+
309
+ def get_serverstatus_(self):
310
+ raw_data = dict()
311
try:
312
raw_data['serverStatus'] = self.connection.admin.command('serverStatus')
313
+ except PyMongoError:
314
+ return None
315
+ else:
316
+ return raw_data
317
+
318
+ def get_dbstats_(self):
319
+ raw_data = dict()
320
+ raw_data['dbStats'] = dict()
321
+ try:
322
for dbase in self.databases:
279
- raw_data[dbase] = self.connection[dbase].command('dbStats')
323
+ raw_data['dbStats'][dbase] = self.connection[dbase].command('dbStats')
324
+ except PyMongoError:
325
+ return None
326
+ else:
327
+ return raw_data
328
+
329
+ def get_replsetgetstatus_(self):
330
+ if not self.repl:
331
+ return None
332
+
333
+ raw_data = dict()
334
+ try:
335
+ raw_data['replSetGetStatus'] = self.connection.admin.command('replSetGetStatus')
336
except PyMongoError:
281
- return None
282
- return raw_data
337
+ return None
338
+ else:
339
+ return raw_data
340
341
def _get_data(self):
342
"""
@@ -291,66 +348,78 @@ class Service(SimpleService):
348
return None
349
350
to_netdata = dict()
294
- server_status = raw_data['serverStatus']
295
-
296
- to_netdata.update(update_dict_key(server_status['opcounters'], 'readWriteOper'))
297
- to_netdata.update(update_dict_key(server_status['globalLock']['activeClients'], 'activeClients'))
298
- to_netdata.update(update_dict_key(server_status['connections'], 'connections'))
299
- to_netdata.update(update_dict_key(server_status['mem'], 'memory'))
300
- to_netdata.update(update_dict_key(server_status['globalLock']['currentQueue'], 'currentQueue'))
301
- to_netdata.update(update_dict_key(server_status['asserts'], 'errors'))
302
- to_netdata['page_faults'] = server_status['extra_info']['page_faults']
303
- to_netdata['record_moves'] = server_status['metrics']['record']['moves']
351
+ serverStatus = raw_data['serverStatus']
352
+ dbStats = raw_data['dbStats']
353
+ replSetGetStatus = raw_data.get('replSetGetStatus')
354
+
355
+ # serverStatus
356
+ to_netdata.update(update_dict_key(serverStatus['opcounters'], 'readWriteOper'))
357
+ to_netdata.update(update_dict_key(serverStatus['globalLock']['activeClients'], 'activeClients'))
358
+ to_netdata.update(update_dict_key(serverStatus['connections'], 'connections'))
359
+ to_netdata.update(update_dict_key(serverStatus['mem'], 'memory'))
360
+ to_netdata.update(update_dict_key(serverStatus['globalLock']['currentQueue'], 'currentQueue'))
361
+ to_netdata.update(update_dict_key(serverStatus['asserts'], 'errors'))
362
+ to_netdata['page_faults'] = serverStatus['extra_info']['page_faults']
363
+ to_netdata['record_moves'] = serverStatus['metrics']['record']['moves']
364
365
if self.ss['dur']:
306
- to_netdata['journalTrans_commits'] = server_status['dur']['commits']
307
- to_netdata['journalTrans_journaled'] = int(server_status['dur']['journaledMB'] * 100)
366
+ to_netdata['journalTrans_commits'] = serverStatus['dur']['commits']
367
+ to_netdata['journalTrans_journaled'] = int(serverStatus['dur']['journaledMB'] * 100)
368
369
if self.ss['backgroundFlushing']:
310
- to_netdata['background_flush_average'] = int(server_status['backgroundFlushing']['average_ms'] * 100)
311
- to_netdata['background_flush_last'] = int(server_status['backgroundFlushing']['last_ms'] * 100)
312
- to_netdata['background_flush_rate'] = server_status['backgroundFlushing']['flushes']
370
+ to_netdata['background_flush_average'] = int(serverStatus['backgroundFlushing']['average_ms'] * 100)
371
+ to_netdata['background_flush_last'] = int(serverStatus['backgroundFlushing']['last_ms'] * 100)
372
+ to_netdata['background_flush_rate'] = serverStatus['backgroundFlushing']['flushes']
373
374
if self.ss['cursor']:
315
- to_netdata['cursor_timedOut'] = server_status['metrics']['cursor']['timedOut']
316
- to_netdata.update(update_dict_key(server_status['metrics']['cursor']['open'], 'cursor'))
375
+ to_netdata['cursor_timedOut'] = serverStatus['metrics']['cursor']['timedOut']
376
+ to_netdata.update(update_dict_key(serverStatus['metrics']['cursor']['open'], 'cursor'))
377
378
if self.ss['wiredTiger']:
319
- wired_tiger = server_status['wiredTiger']
320
- to_netdata.update(update_dict_key(server_status['wiredTiger']['concurrentTransactions']['read'],
379
+ wired_tiger = serverStatus['wiredTiger']
380
+ to_netdata.update(update_dict_key(serverStatus['wiredTiger']['concurrentTransactions']['read'],
381
'wiredTigerRead'))
322
- to_netdata.update(update_dict_key(server_status['wiredTiger']['concurrentTransactions']['write'],
382
+ to_netdata.update(update_dict_key(serverStatus['wiredTiger']['concurrentTransactions']['write'],
383
'wiredTigerWrite'))
384
to_netdata['wiredTiger_bytes_in_cache'] = wired_tiger['cache']['bytes currently in the cache']
325
- to_netdata['wiredTiger_maximum_in_conf'] = wired_tiger['cache']['maximum bytes configured']
385
to_netdata['wiredTiger_dirty_in_cache'] = wired_tiger['cache']['tracked dirty bytes in the cache']
386
to_netdata['wiredTiger_unmodified_pages_evicted'] = wired_tiger['cache']['unmodified pages evicted']
387
to_netdata['wiredTiger_modified_pages_evicted'] = wired_tiger['cache']['modified pages evicted']
388
389
if self.ss['tcmalloc']:
331
- to_netdata.update(server_status['tcmalloc']['generic'])
332
- to_netdata.update(dict([(k, v) for k, v in server_status['tcmalloc']['tcmalloc'].items()
390
+ to_netdata.update(serverStatus['tcmalloc']['generic'])
391
+ to_netdata.update(dict([(k, v) for k, v in serverStatus['tcmalloc']['tcmalloc'].items()
392
if int_or_float(v)]))
393
394
if self.ss['commands']:
395
for elem in ['count', 'createIndexes', 'delete', 'eval', 'findAndModify', 'insert', 'update']:
337
- to_netdata.update(update_dict_key(server_status['metrics']['commands'][elem], elem))
396
+ to_netdata.update(update_dict_key(serverStatus['metrics']['commands'][elem], elem))
397
339
- for dbase in self.databases:
340
- dbase_dbstats = raw_data[dbase]
341
- dbase_dbstats = dict([(k, v) for k, v in dbase_dbstats.items() if int_or_float(v)])
342
- to_netdata.update(update_dict_key(dbase_dbstats, dbase))
398
+ # dbStats
399
+ for dbase in dbStats:
400
+ to_netdata.update(update_dict_key(dbStats[dbase], dbase))
401
+
402
+ # replSetGetStatus
403
+ if replSetGetStatus:
404
+ members = replSetGetStatus['members']
405
+ for member in members:
406
+ for elem in REPLSET_STATES:
407
+ state = elem[0]
408
+ to_netdata.update({'_'.join([member['name'], 'state', state]): 0})
409
+ to_netdata.update({'_'.join([member['name'], 'state', str(member['state'])]): member['state']})
410
411
return to_netdata
412
413
def _create_connection(self):
414
conn_vars = {'host': self.host, 'port': self.port}
348
- if 'server_selection_timeout' in dir(MongoClient):
415
+ if hasattr(MongoClient, 'server_selection_timeout'):
416
conn_vars.update({'serverselectiontimeoutms': self.timeout})
417
try:
418
connection = MongoClient(**conn_vars)
419
if self.user and self.password:
420
connection.admin.authenticate(name=self.user, password=self.password)
421
+ # elif self.user:
422
+ # connection.admin.authenticate(name=self.user, mechanism='MONGODB-X509')
423
server_status = connection.admin.command('serverStatus')
424
except PyMongoError as error:
425
return None, None, str(error)
@@ -359,11 +428,11 @@ class Service(SimpleService):
428
429
430
def update_dict_key(collection, string):
362
- return dict([('_'.join([string, k]), int(round(v))) for k, v in collection.items()])
431
+ return dict([('_'.join([string, k]), int(round(v))) for k, v in collection.items() if int_or_float(v)])
432
433
434
def int_or_float(value):
366
- return isinstance(value, int) or isinstance(value, float)
435
+ return isinstance(value, (int, float))
436
437
438
def in_server_status(elem, server_status):