error tracking
why
errors are only useful if they can be counted and compared over time. grouping by a stable code plus boundary keeps today's error and next month's recurrence of the same error in one bucket — seeing it once is signal, a thousand times is an incident. a reworded message or moved boundary otherwise shatters history, and incident response degrades into grepping disconnected log lines.
rule
every typed diagnostic error that reaches a person or a log is grouped by its stable code, counted, and attached to the correlation id and boundary that produced it. an error is a first-class durable fact. without stable grouping you cannot tell new from recurring; with it, one code + boundary query reveals the pattern and recurrence.
what is tracked
diagnostic errors define the typed shape. tracking adds the accounting layer:
| layer | owns |
|---|---|
| diagnostic error | stable code, boundary, cause, remediation — the contract. |
| logging | every raised diagnostic is logged as a structured error event with correlation id. |
| tracking | grouping by code + boundary, counts over time, first/last seen, sample payload. |
| alerting | threshold rules over tracked groups, per metrics and alerts. |
grouping and noise
group by the stable diagnostic code and boundary — never by message string. provider errors map to the local diagnostic that wrapped them; the original cause is preserved as a field, not as the grouping key. wording changes must not fragment history.
do not
- track raw exceptions with no stable code — they group into noise.
- swallow a diagnostic without logging it because "it's expected" — expected
failures are logged at
warnwith the same structure, or explicitly modeled as a semantic state, not silently dropped. - alert on every occurrence — alert on rate or persistence, per metrics and alerts.
- let the tracking call itself throw and break the request path; tracking is best-effort after the diagnostic is composed.
verification
pick three distinct diagnostic codes. for each, confirm: logs contain its structured event with correlation id; the tracking store groups them under one key unchanged by wording; the rate over a probe window matches the count of logged events. raise one deliberate diagnostic in a non-production environment and confirm it appears end-to-end.
good and bad
bad
log: "error creating user: timeout connecting to auth provider"log: "auth provider connection timed out (attempt 2)"log: "auth service unavailable"log: "createUser failed, provider down"
dozens of phrasings, so you cannot query "auth provider timeout"; you do not know if it recurs (ten times today?) or is a one-off; at incident time you grep and guess they share a root cause. history shatters on every rewording, so a regression looks brand-new and recurrence counts — signal vs incident — can never be computed. responders burn the recovery window reconstructing what the system already knew.
good
// logged with stable fields{code: "auth.provider.timeout",boundary: "authentication adapter",correlationId: "c_9f2a",cause: "connection timeout (5s)",timestamp: "2025-08-26T14:23:18Z"}
one stable code groups every auth timeout regardless of logger or wording. the tracking system counts them under that single key; one query on code + boundary reveals 47 occurrences in the last hour, all from provider adapter, 40 in the last 5 minutes (clear incident). the correlation id finds the exact operation that hit it.