Fleet ranked endpoints by raw critical-event counts, so a machine with a noisy but harmless event log outranked one with a mapped drive down or a blocking service stopped. Volume is not severity, and the aggregation ran across the whole fleet on every page load. Rank operational blockers above degraded conditions above event noise, and cache the verdict per asset so Fleet reads a row instead of recomputing 48h of history. Transitions are written only when a verdict changes, capped at 50 rows per asset. Absence of a policy binding must never suppress a verdict: drives and events are not policy-gated, and services fall back to a built-in default impact when no mapping applies. Event 1001 drops to informational because the WER bucket pairs with 1000 and double-counted every crash. Parallelize the Fleet first-paint loaders that were awaiting serially.
61 lines
2.9 KiB
Python
61 lines
2.9 KiB
Python
"""Curated Windows event catalog: id -> human title and severity.
|
|
|
|
Single server-side source of truth shared by the recent-events asset panel and
|
|
the stability dashboard card, so a 4625 reads as "Failed logon (warning)" in
|
|
both places without either restating the mapping. The set of IDs here MUST stay
|
|
in step with CURATED_EVENT_IDS in plugin.py; a test asserts they match.
|
|
|
|
Severity vocabulary matches the dashboard card renderer: 'critical', 'warning',
|
|
'info'. The IDs marked critical are the ones an operator/tech should act on
|
|
without being asked - unexpected shutdown, crash, filesystem corruption, SCM
|
|
timeout. Logon activity is informational history unless it is a failure.
|
|
"""
|
|
|
|
# id -> (title, severity, channel)
|
|
EVENT_CATALOG = {
|
|
4624: ('Successful logon', 'info', 'Security'),
|
|
4625: ('Failed logon', 'warning', 'Security'),
|
|
4634: ('Logoff', 'info', 'Security'),
|
|
4672: ('Special privileges assigned', 'info', 'Security'),
|
|
4697: ('Service installed', 'warning', 'Security'),
|
|
4698: ('Scheduled task created', 'warning', 'Security'),
|
|
41: ('Unexpected shutdown', 'critical', 'System'),
|
|
4618: ('Monitored security event', 'warning', 'Security'),
|
|
55: ('File system corruption', 'critical', 'System'),
|
|
7011: ('Service timeout', 'critical', 'System'),
|
|
10016: ('DCOM permission error', 'warning', 'System'),
|
|
# Windows Error Reporting trio on the Application channel. 1000 is the
|
|
# faulting-application record (app name, version, faulting module, exception
|
|
# code) and is the one that says what actually broke; 1001 is the WER bucket
|
|
# record Windows writes alongside it; 1002 is a hang rather than a crash, so
|
|
# it is a warning - the app is unresponsive, not gone.
|
|
#
|
|
# 1001 is deliberately NOT critical. Windows writes it ALONGSIDE 1000 for the
|
|
# same crash, so counting both double-counted every fault: a box with 2200
|
|
# crashes reported "Application crash x4400". It also won the dominant-event
|
|
# tie often enough to displace 1000, which is the record that actually names
|
|
# the faulting module. Kept curated so the history panel still shows it, but
|
|
# it no longer drives the fleet health verdict - 1000 speaks for the crash.
|
|
1000: ('Application error', 'critical', 'Application'),
|
|
1001: ('Application crash', 'info', 'Application'),
|
|
1002: ('Application hang', 'warning', 'Application'),
|
|
}
|
|
|
|
# The IDs a tech should see surfaced fleet-wide on the dashboard stability card.
|
|
CRITICAL_EVENT_IDS = tuple(
|
|
eventid for eventid, (_t, severity, _c) in EVENT_CATALOG.items()
|
|
if severity == 'critical'
|
|
)
|
|
|
|
|
|
def event_title(eventid):
|
|
"""Human title for a curated event id, or a generic fallback."""
|
|
entry = EVENT_CATALOG.get(eventid)
|
|
return entry[0] if entry else 'Event {}'.format(eventid)
|
|
|
|
|
|
def event_severity(eventid):
|
|
"""Severity ('critical'|'warning'|'info') for a curated event id."""
|
|
entry = EVENT_CATALOG.get(eventid)
|
|
return entry[1] if entry else 'info'
|