Drowning in Data: When Your Logs Know Everything Except What You Need
Photo: William Murphy from Dublin, Ireland, CC BY-SA 2.0, via Wikimedia Commons
There's a particular kind of 3 AM misery that has nothing to do with the actual bug. The service is down, your PagerDuty is screaming, and you crack open the logs expecting answers. What you get instead is a wall of text so dense it looks like a Kafka novel — and not the good kind. You scroll. You grep. You scroll some more. Somewhere in those forty million lines from the last six hours is the error that matters. Probably.
This is the logging paradox, and it wrecks teams more consistently than most developers want to admit. Too little logging and you're flying blind. Too much, and you've essentially built a very expensive noise machine.
The Flood: When More Is Actively Worse
It usually starts with good intentions. Someone gets burned by a production incident where there wasn't enough context to diagnose the problem. The post-mortem conclusion: log everything. So DEBUG statements get sprinkled throughout the codebase like confetti. Every function entry, every database call, every HTTP request and response, every loop iteration — all of it hitting your logging pipeline.
For a while, it feels responsible. Thorough, even.
Then something actually breaks.
A mid-sized e-commerce company — the kind running a few hundred microservices across AWS — once shared a story that's become almost archetypal in platform engineering circles. During a Black Friday incident, their checkout service started silently dropping orders. Not crashing. Not throwing 500s. Just quietly eating purchase requests.
They had logging. Boy, did they have logging. Roughly 2.3 million log lines per minute across their production cluster. When they went hunting for the root cause, they were effectively trying to find a specific conversation at a stadium concert. The signal existed. It was just acoustically indistinguishable from everything else.
The culprit — a misconfigured retry budget on a downstream payment processor call — took four hours to identify. The fix itself took eleven minutes.
The Desert: When Silence Is Also Lying to You
Flip the scenario. You've got a lean, disciplined team that decided to keep logging minimal. Only errors. Only the important stuff. Production stays clean and queryable. Everyone feels smart.
Until the weird bug shows up.
The weird bug is the one that doesn't reproduce locally. It doesn't show up in staging. It happens in production, intermittently, under specific load conditions or with specific user data shapes, and it leaves almost no trace because you made a philosophical decision six months ago that INFO-level logs were bloat.
Without breadcrumbs, you're not debugging — you're archaeologizing. You're trying to reconstruct what happened from artifacts and inference. This is how teams end up spending two weeks chasing a bug that a single well-placed log line would have surfaced in an afternoon.
Both failure modes share a root cause: logging decisions made without a clear framework for what logging is actually for.
What Logging Is Actually For
Here's the reframe that helps: logs are not a recording of what your application did. They're a tool for answering specific questions under pressure, at 3 AM, when you're stressed and the business is losing money.
That framing changes everything about what deserves to be logged.
Start with the questions you'll actually ask during an incident. Not hypothetical questions — real ones, based on the classes of problems your system has actually experienced or is likely to experience. What user triggered this? What was the state of this object when the failure occurred? Which downstream service returned an unexpected response? What was the queue depth at the time?
If a log line doesn't help answer one of those questions, it's paying rent in your storage budget without pulling its weight.
A Practical Framework (That Isn't Just 'Use Log Levels Correctly')
Everyone already knows to use log levels. The advice to "put debug stuff at DEBUG and serious stuff at ERROR" has been in every logging tutorial since roughly 2003. It's not wrong, but it's not sufficient.
Here's what actually helps:
Log state, not steps. "Processing order 84721 for user 9938" is useful. "Entering processOrder function" is not. The difference is that state-based logging tells you what was happening, not just that something was happening.
Log at boundaries, not interiors. The edges of your system — where it talks to external services, where it accepts user input, where it hands off to queues or databases — are where things go wrong. Interior function calls within a tight domain boundary are usually noise.
Treat every ERROR log like a pager alert. If your ERROR logs aren't actionable, they're training your team to ignore them. This is how you end up with a 40,000-line ERROR log that nobody reads. Ruthlessly downgrade anything that isn't genuinely alertable.
Sample aggressively in high-volume paths. If you're logging every single HTTP request and your service handles 10,000 requests per second, you don't need all of them. Log 1% and you've still got 100 data points per second to work with. Modern observability platforms like Datadog, Honeycomb, and Grafana all support sampling — use it.
Build a "what broke last time" checklist. After every production incident, add the log lines that would have surfaced the problem faster. This is how your logging strategy actually matures over time, rather than accumulating randomly.
The Structured Logging Argument
If there's one technical shift that does more to solve this problem than any amount of discipline, it's moving to structured logging — emitting JSON or key-value pairs instead of free-form strings.
The reason is simple: structured logs are queryable. You can filter by user_id or order_status or service_name without writing fragile regex patterns. You can aggregate, you can correlate, you can actually find the thing you're looking for without scrolling through a wall of prose.
When logs are structured, volume becomes less catastrophic because you can slice through it. When they're unstructured strings, every extra log line is pure cost.
Calibration Is a Maintenance Task
The final thing worth saying: logging strategy isn't a one-time architectural decision. It's maintenance work, the same as dependency updates or test coverage. Systems evolve, failure modes shift, and the questions you need to answer in incidents change.
Schedule a quarterly logging review. Look at what you're actually querying during incidents versus what you're generating. Prune the stuff that's never been useful. Add coverage where you've been flying blind.
The goal isn't perfect logging. It's logging that makes the next bad day a little less bad — where the primary error in your system is something you can actually find.