← All writing
Shipping & Ops·Sep 3, 2026·6 min read

Your logs are useless until the one night you need them

Nobody reads logs on a normal day, so their quality never gets tested until an incident — at which point you discover they're unsearchable, unlinked, and missing the one field that would have told you what happened.

H

Hammad Iqbal

Software Engineer

Logging feels done the moment `console.log` prints something useful during development. Then a request fails for one customer at 1am, you open the logs, and you're staring at ten thousand lines of unstructured text with no way to isolate that user's request, no timestamp you can correlate across services, and no record of the input that caused the error. The logs existed the whole time. They just weren't built for the only situation that matters.

In brief
  • Log quality is only ever tested during an incident, which is the worst time to find out it's bad.
  • A request ID threaded through every log line is the difference between grep and guesswork.
  • Log the inputs and the decision, not just the error — the stack trace tells you where, not why.

Unstructured logs don't survive scale

A line like `user login failed` is fine when you have one server and ten users. Once you have real traffic it's a needle in a haystack you can't query — you can't filter by user, by endpoint, or by error type, because none of those are fields, they're just words in a sentence. Structured logging, where each line is JSON with consistent keys, costs almost nothing to adopt and turns your log store into something you can actually ask questions of.

Without a correlation ID, you're reconstructing from memory

One user action fans out into a dozen log lines across the API, the worker queue, and two external calls. If nothing ties them together, an incident becomes an exercise in matching timestamps by eye and hoping you didn't miss one. Generate a request ID at the edge, attach it to every log line, and pass it downstream in a header.

  • Generate the ID as early as possible — middleware, before any handler runs
  • Put it in every log line automatically via the logger's context, not by hand
  • Return it in the response headers so a user can quote it in a bug report
  • Forward it to third-party calls so their support team can find the same request

Log the decision, not just the failure

A stack trace tells you which line threw. It rarely tells you why that line threw on this request and not the last thousand. The logs that actually shorten an incident record the inputs and the branch taken: which plan the user was on, which feature flag evaluated true, what the external API returned before you tried to parse it. That context is cheap to write when you're coding the path and impossible to recover once you're debugging it.

Takeaway

Treat the logs as a feature with exactly one user — the person debugging an incident at 1am — and build them for that person. On every other day it won't matter, and that's the point.

Have a project this kind of thinking applies to?

Tell me what you're building — I read every message myself.

Available for new projects

4+

Years exp.

8+

Projects shipped

<6h

Avg. reply time

Let's build something

Tell me about your project.

Share what you're building, your timeline, and the best way to reach you.