Why are structured logs preferable to free-text lines, and which fields should every entry carry?
A free-text line has to be parsed with fragile regular expressions; a structured entry (typically JSON) is machine-readable by construction — and uniform fields like timestamp, service, level and trace ID are what make entries from different systems comparable.
Compare the two shapes:
# free text — every producer invents its own wording
2026-09-17 10:12:04 Payment failed for user 4711 after 3 retries
# structured — the same facts as named fields
{"timestamp":"2026-09-17T10:12:04Z","service":"payment-api","level":"ERROR",
"trace_id":"7f3c9a...","user_id":4711,"retries":3,"event":"payment_failed"}
The free-text version is readable by a human and almost useless to a machine: to count failed payments per service you would need a parser per wording, and any change to the message breaks it. The structured version can be indexed, filtered, aggregated and joined without anyone writing a pattern.
The minimum field set matters as much as the format:
- Timestamp — with time zone, so entries from different hosts can be ordered.
- Service (and ideally host, version) — so you know where it came from.
- Level — so filtering and alerting work.
- Trace ID — the correlation key that lets a log line be joined to the request that produced it, and therefore to metrics and traces from the same request.
That last field is the bridge between logging and observability: without a shared identifier, three pillars of data stay three separate piles.
Go deeper:
OpenTelemetry: Logs — how structured logs are modelled as a signal and correlated with traces via IDs.