Log Levels Beyond INFO/DEBUG: Structured Logging That Aids Triage
Most logs are unstructured strings nobody can query at 3am. Structured logging takes one quarter to roll out and pays back forever.
Why text logs fail under triage
Unstructured text logs work for human reading. They fail when the question is ‘show me all errors from tenant X in the last hour’, grep does not understand ‘errors’ or ‘tenant X.’ You end up greping for vague substrings and missing things.
Structured logs (JSON, with named fields) make the same query a one-liner. level=error AND tenant_id="X" AND ts > -1h. The investment is one-time; the dividend is every incident.
The five levels worth keeping
- FATAL: process is going down.
- ERROR: something failed; user-impacting.
- WARN: something unusual; investigate later.
- INFO: normal operations; high-level flow.
- DEBUG: detailed diagnostics; off in production.
- Skip TRACE in 2026; it competes with distributed tracing and rarely earns its keep.
The structured fields that matter
Every log line should have: ts, level, msg, service, trace_id, span_id. Add tenant_id, user_id, req_id for the request-scoped context.
The trace_id field is the killer one, it lets you jump from log to trace in your observability tool with one click. Without it, the two are separate worlds.
The three-line setup
In Node.js: npm install pino; replace console.log with logger.info({ tenant_id, ... }, ‘message’). Three lines.
In Python: stdlib logging + python-json-logger formatter. Same idea; three lines.
In Go: slog from the standard library. Two lines.
Every modern language has a structured logger that is one import away. The investment is the change in writing style, not the library.
Antipatterns
- String concatenation in log messages. Defeats the structure.
- Logging at INFO inside hot loops. Storage death.
- No correlation IDs. Traces and logs cannot be cross-referenced.
What to do this week
Three moves. (1) Pick one service; switch to a structured logger this week. (2) Add trace_id propagation if you have tracing set up. (3) Update your runbook to use structured queries instead of grep.