Health names the dominant critical event; activity keeps criticals visible
This commit is contained in:
@@ -175,7 +175,7 @@ def list_endpoints():
|
|||||||
row['uptimedisplay'] = _format_uptime(state.uptimeseconds)
|
row['uptimedisplay'] = _format_uptime(state.uptimeseconds)
|
||||||
row['status'] = ('never', 'quiet', 'reporting')[rank]
|
row['status'] = ('never', 'quiet', 'reporting')[rank]
|
||||||
row['machines'] = machines.get(state.assetid, [])
|
row['machines'] = machines.get(state.assetid, [])
|
||||||
row['health'] = _health_for(state, critical.get(state.assetid, 0))
|
row['health'] = _health_for(state, critical.get(state.assetid))
|
||||||
data.append(row)
|
data.append(row)
|
||||||
|
|
||||||
return paginated_response(data, page, per_page, total)
|
return paginated_response(data, page, per_page, total)
|
||||||
@@ -258,30 +258,48 @@ def _machines_for_assets(assetids):
|
|||||||
|
|
||||||
|
|
||||||
def _critical_counts_for_assets(assetids):
|
def _critical_counts_for_assets(assetids):
|
||||||
"""{assetid: count} of critical events in the stability window."""
|
"""{assetid: (total, dominant_eventid)} of critical events in the window.
|
||||||
|
|
||||||
|
Broken down BY EVENT ID, not just totalled. A bare count says "418
|
||||||
|
critical", which tells an operator nothing about what to do; naming the
|
||||||
|
event that dominates - service timeout, application crash - is the
|
||||||
|
difference between a number and a lead.
|
||||||
|
"""
|
||||||
if not assetids:
|
if not assetids:
|
||||||
return {}
|
return {}
|
||||||
cutoff = _naive_utcnow() - timedelta(hours=48)
|
cutoff = _naive_utcnow() - timedelta(hours=48)
|
||||||
rows = (db.session.query(EndpointEvent.assetid,
|
rows = (db.session.query(EndpointEvent.assetid, EndpointEvent.eventid,
|
||||||
db.func.count(EndpointEvent.endpointeventid))
|
db.func.count(EndpointEvent.endpointeventid))
|
||||||
.filter(EndpointEvent.assetid.in_(assetids),
|
.filter(EndpointEvent.assetid.in_(assetids),
|
||||||
EndpointEvent.eventid.in_(CRITICAL_EVENT_IDS),
|
EndpointEvent.eventid.in_(CRITICAL_EVENT_IDS),
|
||||||
EndpointEvent.eventtime.isnot(None),
|
EndpointEvent.eventtime.isnot(None),
|
||||||
EndpointEvent.eventtime >= cutoff)
|
EndpointEvent.eventtime >= cutoff)
|
||||||
.group_by(EndpointEvent.assetid)
|
.group_by(EndpointEvent.assetid, EndpointEvent.eventid)
|
||||||
.all())
|
.all())
|
||||||
return dict(rows)
|
|
||||||
|
perasset = {}
|
||||||
|
for assetid, eventid, count in rows:
|
||||||
|
total, dominant, best = perasset.get(assetid, (0, None, 0))
|
||||||
|
total += count
|
||||||
|
if count > best:
|
||||||
|
dominant, best = eventid, count
|
||||||
|
perasset[assetid] = (total, dominant, best)
|
||||||
|
return {assetid: (total, dominant)
|
||||||
|
for assetid, (total, dominant, _best) in perasset.items()}
|
||||||
|
|
||||||
|
|
||||||
def _health_for(state, criticalcount):
|
def _health_for(state, critical):
|
||||||
"""Worst-of rollup: a stopped watched service, or a recent critical event.
|
"""Worst-of rollup: a stopped watched service, or a recent critical event.
|
||||||
|
|
||||||
Deliberately a PHRASE, not a score. "eDNC stopped" tells an operator what
|
Deliberately a PHRASE, not a score. "eDNC stopped" tells an operator what
|
||||||
to do; a percentage does not.
|
to do; a percentage does not - and neither does "418 critical", which is
|
||||||
|
why the dominant event is named rather than merely counted.
|
||||||
"""
|
"""
|
||||||
if criticalcount:
|
if critical:
|
||||||
return {'level': 'critical',
|
total, dominant = critical
|
||||||
'label': f'{criticalcount} critical' if criticalcount > 1 else '1 critical'}
|
title = event_title(dominant) if dominant else 'critical'
|
||||||
|
label = title if total == 1 else '{} x{}'.format(title, total)
|
||||||
|
return {'level': 'critical', 'label': label}
|
||||||
|
|
||||||
stopped = []
|
stopped = []
|
||||||
try:
|
try:
|
||||||
@@ -517,6 +535,20 @@ def panel_activity(asset_id: int):
|
|||||||
.limit(15)
|
.limit(15)
|
||||||
.all())
|
.all())
|
||||||
|
|
||||||
|
# The newest 15 of ANY severity can be entirely routine logons while the
|
||||||
|
# health rollup is shouting about a burst of crashes underneath them - the
|
||||||
|
# page then contradicts itself for no visible reason. Pull the newest
|
||||||
|
# criticals separately and merge, so what health is reporting is always
|
||||||
|
# present in the feed that is supposed to explain it.
|
||||||
|
criticals = (EndpointEvent.query
|
||||||
|
.filter(EndpointEvent.assetid == asset_id,
|
||||||
|
EndpointEvent.eventid.in_(CRITICAL_EVENT_IDS))
|
||||||
|
.order_by(EndpointEvent.eventtime.desc())
|
||||||
|
.limit(5)
|
||||||
|
.all())
|
||||||
|
seen = {e.endpointeventid for e in events}
|
||||||
|
events.extend(e for e in criticals if e.endpointeventid not in seen)
|
||||||
|
|
||||||
commands = (EndpointCommand.query
|
commands = (EndpointCommand.query
|
||||||
.filter_by(assetid=asset_id)
|
.filter_by(assetid=asset_id)
|
||||||
.order_by(EndpointCommand.createdat.desc())
|
.order_by(EndpointCommand.createdat.desc())
|
||||||
@@ -560,6 +592,15 @@ def panel_activity(asset_id: int):
|
|||||||
# Undated rows sort last rather than crashing the comparison.
|
# Undated rows sort last rather than crashing the comparison.
|
||||||
rows.sort(key=lambda r: (r['eventtime'] is not None, r['eventtime']), reverse=True)
|
rows.sort(key=lambda r: (r['eventtime'] is not None, r['eventtime']), reverse=True)
|
||||||
|
|
||||||
|
# Trim to the cap without dropping the criticals that were fetched on
|
||||||
|
# purpose: they keep their place in time, but they survive the cut.
|
||||||
|
if len(rows) > 15:
|
||||||
|
keep = [r for r in rows if r['severity'] == 'critical'][:5]
|
||||||
|
rest = [r for r in rows if r not in keep]
|
||||||
|
rows = sorted(keep + rest[:15 - len(keep)],
|
||||||
|
key=lambda r: (r['eventtime'] is not None, r['eventtime']),
|
||||||
|
reverse=True)
|
||||||
|
|
||||||
return success_response([{
|
return success_response([{
|
||||||
'title': r['title'],
|
'title': r['title'],
|
||||||
'severity': r['severity'],
|
'severity': r['severity'],
|
||||||
|
|||||||
Reference in New Issue
Block a user