Engineering
Your Logs Should Explain Decisions, Not Narrate Code
The most useful production logs capture a decision, its inputs, and its outcome. Everything else competes for attention and retention when an incident is already moving fast.
· Vight engineering · 6 min read
Logging practice
Record the fork in the road.
Applications often log what the code is doing: entering a method, calling a dependency, receiving a response, leaving the method. Distributed tracing already captures much of that shape with timing and parent-child context.
Logs are more valuable when they capture what the trace cannot infer: why a branch was taken, which policy rejected a request, whether a fallback was deliberate, and which business-safe identifiers let an operator connect the event to a customer report.
A strong log line is not a transcript. It is a small piece of decision evidence.
01
Log information that changes the diagnosis
Before adding a log, ask what an operator could conclude from it that they could not conclude from a span. A message such as “calling payment service” adds little when a client span already names the service, operation, duration, and status.
A message such as “payment routed to backup processor because primary circuit is open” explains behavior. Include the reason, the selected path, the relevant policy or state, and a stable correlation identifier. Leave secrets, credentials, and unnecessary personal data out of the event entirely.
Decision
Name the branch the application selected, not the method it entered.
Reason
Record the safe inputs or policy state that caused that branch.
Outcome
Say whether the operation continued, degraded, retried, or stopped.
02
Use fields for questions you will actually ask
Structured fields are useful when they support a known investigation: service, environment, version, deployment, trace ID, span ID, route, error type, retry count, and a safe domain identifier. A random collection of object properties is structured storage, not structured logging.
Field names should be stable across services. If one team emits customer_id, another accountId, and a third tenant, the incident query becomes an archaeology exercise. Choose a small semantic vocabulary and review it like an API.
03
Severity is a routing decision
Severity should describe the operational consequence, not the developer's surprise. A handled cache miss is not an error. A retry that succeeds may be informational or a metric. A failed request that needs investigation is an error even if the code expected the exception type.
When everything unusual is marked error, error searches stop representing customer impact and alerts built on log severity become noisy. Reserve the highest levels for conditions that should change what an operator does.
04
Delete logs as deliberately as you add them
Logging reviews should remove events that duplicate spans, repeat the same failure at every layer, or never appear in an incident query. Volume is only one cost; low-value events also make high-value evidence harder to find.
A practical test is to sample a recent incident and label every log line as decisive, supporting, or irrelevant. Keep the first category, be selective with the second, and remove or demote the third. Production logging improves through subtraction.
Trace the path, measure the population, and use logs for the moments when the application chose one future over another.