Observability & Tracing

structured logging

Picture two ways of taking notes during a shift. One person writes free-flowing sentences: 'user 4821 had a slow checkout, took about 800ms, on the new build'. Another fills in a form with labelled boxes: user=4821, event=checkout, duration_ms=800, build=9f3a. Both record the same facts, but only the second can be sorted, filtered, and totalled by a machine without guessing. Structured logging is the second style: emitting each log event as a set of named fields rather than a single human-written sentence.

The contrast is with printf logging — the traditional style where a program writes a free-text line like fprintf(stderr, "user %d slow checkout %dms\n", id, ms). That line is easy to write and easy for a human to read one at a time, but to a tool it is an opaque string: to find 'all checkouts slower than 500ms for build 9f3a' something must re-parse that prose with fragile regular expressions, and the format drifts every time a developer edits the message. Structured logging instead emits a record with explicit key-value fields, commonly serialised as one JSON object per line (sometimes called wide events when each carries many fields). Now a log backend can index by field and answer 'duration_ms > 500 AND build = 9f3a' directly, group by user, and compute aggregates — the log becomes queryable data rather than text to grep. This is the form that lets logs participate in real observability and connect to traces (by carrying a trace id field).

It matters because at production scale the value of a log is whether you can ASK QUESTIONS of it, and only structured fields make that reliable. Two honest engineering concerns come with it. First cardinality: a field like user_id can take millions of distinct values (high cardinality), which is exactly what you want for debugging a single customer but can be expensive for a metrics system to index — so you choose deliberately where high-cardinality fields live. Second volume and cost: logging every event at full detail is expensive, so production systems use log sampling — keeping, say, one in a hundred routine events but all of the errors — which controls cost while preserving the rare signals, at the price that you no longer have EVERY routine event, only a representative sample.

printf style: ERROR user 4821 slow checkout 800ms on build 9f3a structured (JSON): {"level":"error","event":"checkout","user":4821,"duration_ms":800,"build":"9f3a","trace_id":"a1b2"} query the structured form: event="checkout" AND duration_ms>500 AND build="9f3a"

The same event as free text versus named fields: only the structured form can be filtered, grouped, and joined to a trace without fragile parsing.

Structured logging is about the SHAPE (named fields), not the file format: JSON is common but not required. And it is not free — high-cardinality fields and full-volume logging cost money, which is why log sampling and deliberate field choices are part of doing it well.

Also called
structured logsJSON loggingwide eventskey-value logging結構化記錄鍵值日誌