Observability vs Monitoring: What Matters
Cover photo by Kevin Ku on Unsplash
Monitoring tools are great. I rely on them daily to tell me when a service is down or when CPU usage spikes. If you have a predictable system where you know exactly which metrics might fail, monitoring is perfect. It is efficient, cost-effective, and tells you the ‘what’ of your system.
The problem with dashboards
I once spent three hours staring at a flatlined request rate graph. Everything was green. The CPU was fine, memory was stable, and the API reported zero errors. Users, however, were getting empty responses. My monitoring told me the system was healthy, but the system was clearly broken. This is where monitoring fails.
Moving to observability
Observability is about asking new questions without shipping new code. It relies on traces, logs, and context, not just aggregate metrics. To see the difference, look at how we track a failed request. Here is the naive approach with standard logging:
// Naive loggingconsole.log('Error processing request: ' + userId);That helps if I happen to be tailing logs at the exact millisecond, but it tells me nothing about the request lifecycle. It lacks context. If I want observability, I need to attach spans and baggage to my request flow.
// Observability approachtracer.startSpan('process-payment', (span) => { span.setTag('user.id', userId); span.log({ event: 'database_query_start' }); // Execute logic});Now, if things break, I can query by user.id and see the entire path that specific request took through my microservices (or even my messy monolith, honestly, I don’t judge architecture choices as much as I used to).
Is this just more overhead?
“But Namir, observability is just a fancy marketing term for logs with extra steps.” That is a fair point. If you have a small project or a static site, you probably do not need full-blown distributed tracing. You are likely better off with simple error tracking and basic uptime checks. Observability adds cost, both in terms of data storage and the mental overhead of instrumenting your code properly. I am not suggesting you add tracing to every single function call.
Where to start
Start by making your logs structured. Stop dumping raw strings into stdout. Use JSON. If you can query your logs by user ID, request ID, and status code, you have already moved halfway toward observability.
Focus on the user journey. Instead of monitoring a CPU percentage, trace the time it takes for a login attempt to resolve. If that time spikes, you have a signal. You can then look at the associated traces to see if the database is lagging or if a third-party API is hanging.
Reliability is not about preventing every possible failure. It is about understanding what happened when things inevitably fall apart. Monitoring tells you that you are on fire. Observability tells you exactly which room is burning and why the sprinkler system didn’t trigger. I prefer to know why.