Your Logs Are Lying to You — And Slowing Everything Down
There's a particular kind of developer confidence that kicks in right after you wire up logging for the first time. You've got visibility. You've got traceability. You've got evidence if something goes wrong at 2 a.m. on a holiday weekend.
Then six months later, your app is crawling, your storage costs look like a mortgage payment, and your on-call engineer is drowning in noise trying to find the one log line that actually matters.
Logging done poorly isn't just unhelpful — it's actively destructive. And the scary part? Most teams don't realize it until the damage is already baked into production.
The Myth of "Log Everything, Sort It Out Later"
This is one of the most expensive philosophies in software engineering, and it's shockingly common. The logic sounds reasonable: disk is cheap, debugging is hard, so why not capture everything? The problem is that logging isn't free, even when it feels like it should be.
Every log statement is a function call. It involves string formatting, I/O operations, and depending on your setup, network calls to a centralized logging service. In a high-throughput system processing thousands of requests per second, those tiny costs compound into something that shows up hard in your latency metrics.
One real-world example that gets passed around in SRE circles: a mid-sized e-commerce company discovered that nearly 40% of their request latency on peak traffic days was attributable to synchronous logging calls that were blocking the main execution thread. They weren't logging maliciously — they'd just never audited what they were logging or how. A Black Friday traffic spike turned a minor inefficiency into a full-scale incident.
Synchronous vs. Asynchronous Logging: The Decision Nobody Makes Deliberately
Most developers inherit a logging setup rather than design one. And inherited setups often default to synchronous logging — meaning your application literally waits for the log write to complete before moving on.
For low-traffic internal tools, that's fine. For anything customer-facing that needs to scale, it's a ticking clock.
Asynchronous logging decouples the act of writing a log from your application's critical path. Your app fires off the log event to a buffer or queue and keeps moving. A separate process handles the actual write. Frameworks like Log4j2 in Java, Serilog in .NET, and Winston in Node.js all support async logging, but you have to configure it intentionally — the defaults won't save you.
The tradeoff worth understanding: async logging can lose log entries if your app crashes before the buffer flushes. For most production systems, that's an acceptable risk. For financial transaction systems or compliance-heavy environments, you'll need to think more carefully about durability guarantees.
Log Levels Exist for a Reason. Use Them.
If your production environment is running at DEBUG level, stop reading this article and go fix that right now. Seriously.
Log levels — TRACE, DEBUG, INFO, WARN, ERROR, FATAL — aren't just organizational labels. They're a runtime throttle. Production systems should almost always run at INFO or higher, with the ability to temporarily drop to DEBUG on specific services when you're actively investigating an issue.
The pattern that works well in larger engineering orgs is dynamic log level adjustment — the ability to change log verbosity on a running service without a redeploy. Tools like Dropwizard, Spring Boot Actuator, and AWS CloudWatch Logs support this. It means you get the silence you need at scale, with the option to open the firehose when something actually breaks.
Structured Logging Isn't Optional Anymore
If you're still writing free-form log strings like "User 1234 failed to log in at " + timestamp, you're creating work for your future self and your entire team.
Structured logging — emitting logs as key-value pairs or JSON — transforms your logs from a wall of text into queryable data. That matters enormously when you're using aggregation tools like Datadog, Splunk, Elastic Stack (ELK), or Grafana Loki.
Structured logs let you filter by user ID, request duration, error code, or any other field without writing regex patterns at midnight. They also compress better, index faster, and cost less to store and query in most cloud logging services.
The switch feels annoying for about a week. Engineers grumble about verbosity. Then the first time someone finds a production bug in under three minutes because they could filter by error_code: 429 across a million log entries, the grumbling stops.
Sampling: The Strategy Most Teams Skip
Not every log entry needs to be persisted. This sounds obvious, but it's rarely acted on.
Log sampling means you capture a statistically meaningful percentage of routine log events rather than all of them. For high-frequency, low-value events — health checks, successful authentication, routine cache hits — sampling at 1% or 10% gives you the visibility you need without the volume explosion.
Tools like OpenTelemetry make sampling first-class functionality, and if you're not already thinking about observability through an OTel lens, now is a good time to start. The framework is vendor-neutral, widely adopted across US tech companies, and designed specifically to handle the tradeoffs between signal and noise at scale.
Sampling does require intentionality. Errors and anomalies should almost always be logged at 100%. The goal is to reduce volume on the boring stuff, not the stuff that actually needs your attention.
What Good Logging Actually Looks Like
Here's a rough checklist that holds up well across most production environments:
- Use structured, machine-readable formats (JSON is the standard for most modern stacks)
- Run async logging in production unless you have a specific durability requirement that demands otherwise
- Set appropriate log levels per environment — verbose in dev, disciplined in prod
- Sample aggressively for high-frequency routine events
- Centralize and index logs so they're queryable, not just searchable by eyeball
- Set retention policies — logs older than 30 or 90 days are rarely useful and always expensive
- Audit your logging regularly — treat it like any other piece of infrastructure that can accumulate debt
The Cost Angle Nobody Talks About Enough
Cloud logging isn't cheap. AWS CloudWatch, Google Cloud Logging, Datadog — they all charge based on ingestion volume, storage, and query volume. Engineering teams at startups routinely get blindsided by logging bills that rival their compute costs.
One pattern worth adopting: route only WARN and above to your paid observability platform, and send INFO and below to cheaper long-term storage like S3 with Athena for ad-hoc querying. You get the alerting and dashboarding where you need it, without paying premium rates to store every health check ping from the last six months.
Build It Like Infrastructure, Not an Afterthought
The teams that handle logging well treat it the same way they treat database schema design or API contracts — as something that requires deliberate architecture, not just a library import and a few console.log statements sprinkled around.
Logging strategy is one of those engineering decisions that's nearly invisible when it's done right and painfully obvious when it isn't. The time to think about it is before you're in an incident, not during one.
Get your logging right, and you'll ship faster, debug quicker, and spend less. That's the kind of compounding return that makes good engineering culture actually worth building.