import time from decimal import Decimal from sanic import Blueprint, response bp = Blueprint(__name__) # a day, 7 days and 30 days in milliseconds DAY_MSEC = 86400000 WEEK_MSEC = 604800000 MONTH_MSEC = 2592000000 def get_status(manager): res = {} for name, state in manager.state.items(): # ignore unitialized workers if state is None: continue res[name] = state worker = manager.workers[name] res[name]['description'] = worker.service['description'] return res def get_graphs(manager): res = {} for name, worker in manager.workers.items(): # skip adapters without latency if 'latency' not in worker.adapter.spec['db']: continue cur = manager.conn.cursor() cur.execute(f""" SELECT timestamp, latency FROM {name} ORDER BY timestamp DESC LIMIT 50 """) qres = cur.fetchall() res[name] = qres return res def _raw_uptime(cur, service_name: str, worker, time_period: int) -> str: """Calculate uptime for a service given a timeframe.""" max_tstamp = time.time() * 1000 min_tstamp = max_tstamp - time_period t_period = max_tstamp - min_tstamp # get all polls that failed cur.execute(f""" SELECT COUNT(*) FROM {service_name} WHERE status = 0 AND timestamp > ? """, (min_tstamp, )) row = cur.fetchone() down_hits = row[0] # total downtime in milliseconds downtime = down_hits * worker.service['poll'] * 1000 # calculate total downtime in percentage percent = Decimal(downtime) / Decimal(t_period) return str(Decimal(100) - percent) def calc_uptime(manager, time_frame): res = {} for name, worker in manager.workers.items(): cur = manager.conn.cursor() res[name] = _raw_uptime(cur, name, worker, time_frame) return res @bp.get('/api/status') async def get_full_status(request): manager = request.app.manager return response.json({ 'status': get_status(manager), 'graph': get_graphs(manager), # uptime stuff 'uptime': calc_uptime(manager, DAY_MSEC), 'week_uptime': calc_uptime(manager, WEEK_MSEC), 'month_uptime': calc_uptime(manager, MONTH_MSEC), }) @bp.get('/api/quick') async def quick_status(request): """basically /api/status without the graphs""" manager = request.app.manager return response.json({ 'status': get_status(manager), # uptime stuff 'uptime': calc_uptime(manager, DAY_MSEC), 'week_uptime': calc_uptime(manager, WEEK_MSEC), 'month_uptime': calc_uptime(manager, MONTH_MSEC), })