A log line reading "failed to process order for user after retry" is readable by a human and useless to a machine. You cannot filter by user, count by failure reason, or join it to the request that caused it. At ten requests per second that is tolerable. At production scale it means your logs exist but cannot answer questions.
Structured logging emits events with named fields instead of sentences. Same information, radically different queryability.
What changed in 2026
- Wide events gained ground over many small lines. Emitting one rich event per unit of work, carrying everything known about it, proved cheaper and more useful than scattering many narrow log lines through the code path.
- Trace correlation became standard. Attaching trace and span identifiers to log events, tying logs to distributed traces automatically, moved into default framework configuration.
- Cost discipline tightened. As log volumes and ingestion prices rose, sampling strategies and retention tiering became normal engineering concerns rather than afterthoughts.
- Redaction moved to emission time. Filtering sensitive fields before they leave the process replaced the fragile practice of scrubbing at ingestion.
Fields worth having on every event
| Field |
Why |
| Timestamp with timezone |
Ordering across services; ambiguity here ruins investigations |
| Level |
Filtering and alerting |
| Service and version |
Which deployment produced this |
| Trace and span identifier |
Ties the log to a distributed trace |
| Request or correlation identifier |
Reconstructs one user's journey |
| User or tenant identifier |
Scoped investigation; use an opaque identifier |
| Duration for completed operations |
Performance analysis without separate metrics |
| Error type and category |
Aggregation by failure mode, not by message text |
The correlation identifier is the one that changes everything. Without it, debugging a user report means guessing which log lines relate to their request. With it, one query returns the whole story across every service involved.
Note the error field guidance: log a stable error type alongside the message. Message strings get reworded, which silently breaks every dashboard and alert built on them. A stable enumerated type survives copy edits.
Wide events over many lines
The instinct is to log at each step: received request, validated input, queried database, called service, returned response. That produces five events per request, each carrying partial context, requiring a join to reconstruct anything.
The alternative is accumulating context through the request and emitting one wide event at the end containing everything — the inputs, the decisions, the timings of each phase, the outcome. One event per unit of work, with fifty fields rather than five events with ten.
This is cheaper, because ingestion cost is dominated by event count as much as by bytes. It is also more useful, because every question about that request is answerable from one record with no joins. Add intermediate events only for things that need to survive a crash mid-request.
Pair this with tracing rather than duplicating it. Traces show structure and timing across services; logs carry the detail. The setup for the trace side is in OpenTelemetry setup guide.
Common mistakes
- Interpolating values into the message. That is a string log wearing a structured format. Put values in fields.
- No correlation identifier. The single biggest limiter on log usefulness.
- Logging personal data. Redact at emission; assume anything in the log store is broadly readable.
- Alerting on message text. Rewording the message breaks the alert. Use stable error types.
- Debug level in production without sampling. The fastest way to a very large bill.
FAQ
Does structured logging cost more?
Per event, slightly more bytes. In practice it costs less, because you can sample intelligently and stop logging things you were only emitting in case someone grepped for them.
Should logs be JSON?
For machine consumption, yes. Most logging libraries emit JSON to the collector while rendering human-readable output locally in development.
How long should logs be retained?
Tier it: short retention on high-volume debug data, longer on errors and audit events. Uniform long retention across everything is where costs get out of hand.
Do I still need metrics?
Yes. Metrics are cheap for aggregate trends and alerting. Logs answer specific questions. Deriving metrics from logs works and costs more.
Where to go next
For distributed tracing, read OpenTelemetry setup guide. For error semantics at the API boundary, API error design.