NewsBlur/apps/monitor/views/prometheus_mongo.py
2021-09-16 11:57:57 -05:00

191 lines
6 KiB
Python

import os
from django.views import View
from django.shortcuts import render
class MongoGrafanaMetric(View):
def __init__(self):
super(View, self).__init__()
self.dbname = os.environ.get('MONGODB_DATABASE')
host = os.environ.get('MONGODB_SERVER') or 'db_mongo:29019'
if ':' in host:
host, port = host.split(':')
port = int(port)
else:
port = 27017
self.server = (host, port)
@property
def connection(self):
if not hasattr(self, '_connection'):
import pymongo
self._connection = pymongo.MongoClient(self.server[0], self.server[1])
return self._connection
@property
def host(self):
return os.environ.get('MONGODB_SERVER') or 'db_mongo:29019'
def autoconf(self):
return bool(self.connection)
def get_context(self):
raise NotImplementedError('You must implement the get_context function')
def get(self, request):
context = self.get_context()
return render(request, 'monitor/prometheus_data.html', context, content_type="text/plain")
class MongoDBHeapUsage(MongoGrafanaMetric):
def get_context(self):
value = self.connection.admin.command('serverStatus')
try:
value = value['extra_info']['heap_usage_bytes']
except KeyError:
# I am getting this
value = "U"
data = {
'heap_usage_bytes': value
}
return {
"data": data,
"chart_name": 'heap_usage',
"chart_type": 'gauge',
}
class MongoDBObjects(MongoGrafanaMetric):
def get_context(self):
stats = self.connection.newsblur.command("dbstats")
data = dict(objects=stats['objects'])
formatted_data = {}
for k, v in data.items():
formatted_data[k] = f'mongo_objects{{db="{self.host}"}} {v}'
return {
"data": formatted_data,
"chart_name": 'objects',
"chart_type": 'gauge',
}
class MongoDBOpsReplsetLag(MongoGrafanaMetric):
# needs --replSet in docker command but when I do this, newsblur_web cnat connect to mongo
def _get_oplog_length(self):
oplog = self.connection.local.oplog.rs
last_op = oplog.find({}, {'ts': 1}).sort([('$natural', -1)]).limit(1)[0]['ts'].time
first_op = oplog.find({}, {'ts': 1}).sort([('$natural', 1)]).limit(1)[0]['ts'].time
oplog_length = last_op - first_op
return oplog_length
def _get_max_replication_lag(self):
PRIMARY_STATE = 1
SECONDARY_STATE = 2
status = self.connection.admin.command('replSetGetStatus')
members = status['members']
primary_optime = None
oldest_secondary_optime = None
for member in members:
member_state = member['state']
optime = member['optime']
if member_state == PRIMARY_STATE:
primary_optime = optime['ts'].time
elif member_state == SECONDARY_STATE:
if not oldest_secondary_optime or optime['ts'].time < oldest_secondary_optime:
oldest_secondary_optime = optime['ts'].time
if not primary_optime or not oldest_secondary_optime:
raise Exception("Replica set is not healthy")
return primary_optime - oldest_secondary_optime
def get_context(self):
# no such item for Cursor instance
oplog_length = self._get_oplog_length()
# not running with --replSet
replication_lag = self._get_max_replication_lag()
formatted_data = {}
for k, v in oplog_length.items():
formatted_data[k] = f'mongo_oplog{{type="length", db="{self.host}"}} {v}'
for k, v in replication_lag.items():
formatted_data[k] = f'mongo_oplog{{type="lag", db="{self.host}"}} {v}'
return {
"data": formatted_data,
"chart_name": 'oplog_metrics',
"chart_type": 'gauge',
}
class MongoDBSize(MongoGrafanaMetric):
def get_context(self):
stats = self.connection.newsblur.command("dbstats")
data = dict(size=stats['fsUsedSize'])
formatted_data = {}
for k, v in data.items():
formatted_data[k] = f'mongo_db_size{{db="{self.host}"}} {v}'
return {
"data": formatted_data,
"chart_name": 'db_size_bytes',
"chart_type": 'gauge',
}
class MongoDBOps(MongoGrafanaMetric):
def get_context(self):
status = self.connection.admin.command('serverStatus')
data = dict(
(q, status["opcounters"][q])
for q in status['opcounters'].keys()
)
formatted_data = {}
for k,v in data.items():
formatted_data[k] = f'mongo_ops{{type="{k}", db="{self.host}"}} {v}'
return {
"data": formatted_data,
"chart_name": 'ops',
"chart_type": 'gauge',
}
class MongoDBPageFaults(MongoGrafanaMetric):
def get_context(self):
status = self.connection.admin.command('serverStatus')
try:
value = status['extra_info']['page_faults']
except KeyError:
value = "U"
data = dict(page_faults=value)
formatted_data = {}
for k, v in data.items():
formatted_data[k] = f'mongo_page_faults{{db="{self.host}"}} {v}'
return {
"data": formatted_data,
"chart_name": 'page_faults',
"chart_type": 'counter',
}
class MongoDBPageQueues(MongoGrafanaMetric):
def get_context(self):
status = self.connection.admin.command('serverStatus')
data = dict(
(q, status["globalLock"]["currentQueue"][q])
for q in ("readers", "writers")
)
formatted_data = {}
for k, v in data.items():
formatted_data[k] = f'mongo_page_queues{{type="{k}", db="{self.host}"}} {v}'
return {
"data": formatted_data,
"chart_name": 'queues',
"chart_type": 'gauge',
}