43 lines
1.7 KiB
Python
43 lines
1.7 KiB
Python
"""Deterministic baseline for the cause categories. Needle has to beat this."""
|
|
import re
|
|
|
|
PROBE = re.compile(r"(^|/)(\.env|\.git|wp-|wp/|wp$|wordpress|blog/wp|phpmyadmin|cgi-bin|\.aws|\.ssh|xmlrpc|userfiles|@fs/|etc/passwd)", re.I)
|
|
DEP = re.compile(r"dial|connection refused|eof|no such host|upstream|unavailable|broken pipe|reset by peer", re.I)
|
|
CAP = re.compile(r"timeout|deadline exceeded|pool|memory limit|oom|too many|queue full|exhaust", re.I)
|
|
BUG = re.compile(r"panic|nil pointer|index out of range|typeerror|referenceerror|deadlock|unhandled|chunkloaderror|segfault", re.I)
|
|
LIFE = re.compile(r"healthz|readyz|/ping|retry|cancel|keepalive|vital|\bcls\b|ttfb|fcp|lcp|snapshot|replay|unchanged|session\.load", re.I)
|
|
|
|
|
|
def fields(text):
|
|
d = {}
|
|
for part in text.split(" | "):
|
|
k, _, v = part.partition(": ")
|
|
d[k.lower()] = v
|
|
return d
|
|
|
|
|
|
def classify(text):
|
|
f = fields(text)
|
|
status = int(f.get("status") or 0)
|
|
route = f.get("route", "")
|
|
blob = " ".join([f.get("title", ""), f.get("message", ""), route])
|
|
if PROBE.search(route):
|
|
return "scanner_probe"
|
|
if BUG.search(blob):
|
|
return "service_defect"
|
|
if CAP.search(blob):
|
|
return "capacity_saturation"
|
|
if DEP.search(blob):
|
|
return "dependency_unreachable"
|
|
if status == 401:
|
|
return "client_credential_issue"
|
|
if status in (502, 503, 504):
|
|
return "dependency_unreachable"
|
|
if status >= 500:
|
|
return "service_defect"
|
|
if status == 404:
|
|
return "stale_reference"
|
|
if LIFE.search(blob) or status in (200, 202, 204, 301, 302, 304, 308, 499) or (status == 0 and f.get("kind") in ("span", "log")):
|
|
return "expected_lifecycle"
|
|
return "needs_review"
|