On this page
TL;DR: Monitoring tells you what broke. Observability tells you why it broke and how to fix it. The clearest one-sentence distinction: monitoring answers the questions you already knew to ask; observability gives you the power to ask new questions (Dash0 2026). In practice, monitoring detects that error rates spiked to 12% observability traces that spike to a specific service dependency three hops away that started timing out after a config change 8 minutes ago. Both are required. Neither replaces the other. In 2026, OpenTelemetry has become the de-facto standard for collecting the three (now four) observability signals: metrics, logs, traces, and profiles. Every major cloud provider has first-class OTel support.
The One-Sentence Distinction (That Unlocks Everything Else)
Monitoring: Is something wrong?
Observability: What is wrong, why is it wrong, and how do I fix it?
A concrete example, a user reports that checkout is occasionally hanging:
| Monitoring tells you | Observability tells you | |
|---|---|---|
| Symptom | Error rate: 12% (above 5% threshold) | Which specific request type is failing |
| Where | API pod CPU: 85% | Which service dependency is the bottleneck |
| When | Alert fired at 14:32:07 | The config change at 14:24 that preceded it |
| Why | ❌ Cannot determine root cause | Payment service P95 latency increased from 120ms to 4.2s after config deploy |
| Fix path | Alert → engineer investigates manually | Trace shows the slow path; engineer fixes without guessing |
The difference in practice: monitoring reduces MTTR from days to hours (you know something is wrong). Observability reduces MTTR from hours to minutes (you know what to fix). The gap between those two outcomes is the business case for observability.
What Is Monitoring?
Monitoring is the foundational practice of tracking system health and performance by collecting and analysing predefined metrics against configured thresholds.
What monitoring does well:
- Detects anomalies you anticipated when you set up the alerting
- Tracks resource utilisation (CPU, memory, disk, network)
- Measures response times and error rates at the service level
- Pages the on-call engineer when a threshold is breached
- Produces dashboards for known performance indicators
The core limitation of monitoring alone: Monitoring answers questions you already knew to ask. When something goes wrong in a way you did not anticipate, a race condition, an unexpected service interaction, a latency spike caused by a dependency four hops away, monitoring tells you that something is wrong but cannot tell you what or why. The engineer must then investigate manually by correlating data from multiple isolated tools.
What monitoring looks like in practice:
# Prometheus alert rule — traditional monitoring
- alert: HighErrorRate
expr: rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) > 0.05
for: 2m
labels:
severity: critical
annotations:
summary: "Error rate above 5% for 2 minutes"
# This tells you WHAT — not WHYThis alert fires when error rate exceeds 5% for 2 minutes. It tells you nothing about which service, which request type, which dependency, or which code change caused it. That investigation begins after the alert, and with monitoring alone, it requires manually hunting through disconnected log files and dashboards.
What Is Observability?
Observability is a property of a system, not a tool. An observable system is designed to explain its own internal state from external outputs. You can ask it questions you did not anticipate when you built it, without deploying new instrumentation code.
The theoretical definition (control theory origin): Observability originally described whether you could infer the internal state of a system from its outputs. In software, this translates to: can you understand what is happening inside a distributed system by examining its telemetry signals?
What makes a system observable:
- It emits high-cardinality, high-dimensional telemetry
- Telemetry signals are correlated with shared context (trace IDs, service names, deployment versions)
- You can query telemetry data ad-hoc, not just view pre-built dashboards
- Root cause analysis is possible without deploying new instrumentation code
The power: asking unanticipated questions. An observable system lets you ask: “Show me all requests from users in Australia using the iOS app that hit the payment service with a response time > 2 seconds in the last 30 minutes, grouped by error type.” That query could not have been anticipated when the dashboards were built. It arises from a specific incident. Observability makes it answerable.
The Four Pillars of Observability (2026)

The classic three pillars (logs, metrics, traces) have been joined by a fourth in 2026: profiles. OpenTelemetry’s profiling signal is graduating from experimental to stable.
Pillar 1: Metrics: WHAT and WHEN
Metrics are numerical measurements aggregated over time. They answer: Is the system behaving normally? How is performance trending?
http_request_duration_seconds{service="checkout", status="500"} 4.237
http_requests_total{service="checkout", method="POST"} 12847
memory_usage_bytes{pod="checkout-7d9f4b-xyz"} 847382016Strengths: Low storage cost, fast to query, excellent for alerting, long retention. Best for known failure modes.
Limitation: Aggregated by nature, metrics lose individual request detail. A P99 latency of 4 seconds tells you that 1% of requests are slow; it does not tell you which requests, which users, or which code path.
Key tools: Prometheus (collection, storage), Grafana (visualisation), OpenTelemetry Metrics (collection standard)
Pillar 2: Logs: WHAT HAPPENED (in detail)
Logs are discrete, timestamped records of individual events. They answer: What exactly happened at a specific moment?
{
"timestamp": "2026-09-06T14:32:07.843Z",
"level": "ERROR",
"service": "checkout",
"trace_id": "7a3b2c1d9e4f5a6b",
"message": "Payment service timeout after 4200ms",
"user_id": "usr_8472",
"payment_provider": "stripe",
"request_id": "req_9847234"
}The critical rule: always include trace_id in structured logs. This links log lines to the distributed trace, making it possible to navigate from a metric alert → the trace → the specific log line that explains the root cause. Without trace_id, logs are disconnected from the trace, you must search by time and service name, which is imprecise and slow.
Strengths: Maximum detail, the “why” of specific events, actionable error messages.
Limitation: High storage cost at scale. Slow to query compared to metrics. Must be structured and searchable (JSON, not free-text) to be useful at volume.
Key tools: Loki (log aggregation), Elasticsearch + Kibana (ELK), OpenTelemetry Logs
Pillar 3: Traces: WHERE and HOW
Distributed traces follow a single request through every service it touches. They answer: Where in the system did the slow/failed request spend its time?
Request ID: req_9847234 Total: 4,287ms
[checkout-api ] 0ms ──────────────────────────── 4,287ms
[auth-service ] 5ms ─── 23ms
[inventory-service ] 28ms ─── 85ms
[payment-service ] 113ms ───────────────────────────── 4,174ms ← SLOW
[stripe-api ] 115ms ─────────────────────── 4,167ms ← EXTERNAL TIMEOUT
[notification-svc ] 4,220ms ─ 4,285msThis trace shows exactly where the 4.2 second latency came from: the Stripe API call timed out. Without distributed tracing, diagnosing this would require checking logs in checkout, payment-service, and the Stripe integration separately, then correlating by timestamp. With a trace, it takes seconds.
The trace-log correlation pattern (essential): When a trace shows a slow or failed span, navigate directly to the logs for that specific service at that specific trace ID. The log line shows what happened. The trace shows where. The metric showed that something was wrong. All three together answer the full question.
Key tools: Tempo (trace storage, open source), Jaeger (distributed tracing, open source), OpenTelemetry Traces, Datadog APM (commercial)
Pillar 4: Profiles: WHY the code is slow (2026 addition)
Continuous profiling captures CPU flame graphs from production services, not occasional profiles run manually in development, but always-on profiling at near-zero overhead using eBPF.
What profiles reveal that traces do not: Traces show that payment-service spent 400ms in a function called applyDiscounts. Profiles show that applyDiscounts is slow because it is doing an O(n²) nested loop over a discount table, and a specific call path in the database layer is responsible for 80% of that time.
Key tools: Parca, Pyroscope (continuous profiling, eBPF-based, open source)
OpenTelemetry: The Standard That Ended Vendor Lock-In

Before OpenTelemetry, every observability tool used its own instrumentation SDK. Switching from Datadog to Grafana Cloud meant re-instrumenting the entire application. Teams were locked in by instrumentation cost.
OpenTelemetry (OTel) in 2026: The de-facto standard for collecting metrics, logs, traces, and profiles from distributed systems. Every major cloud provider has first-class OTel support. The standard is vendor-neutral, instrument once, route to any backend.
The OTel architecture:
Application
│ OTel SDK (auto-instrumentation or manual)
│ OTLP/gRPC
▼
OTel Collector (gateway/aggregator)
│ Batching, retry, sampling, routing
▼
┌──────────────┬───────────────┬─────────────────┐
│ Prometheus │ Tempo/Jaeger │ Loki/ES │
│ (Metrics) │ (Traces) │ (Logs) │
└──────────────┴───────────────┴─────────────────┘
All queryable together in GrafanaZero-code auto-instrumentation (Node.js):
// instrument.js — add before any application code
// Zero manual code changes — OTel instruments automatically
require('@opentelemetry/auto-instrumentations-node/register');
// Sets up:
// - Automatic HTTP request tracing (incoming + outgoing)
// - Database query tracing (PostgreSQL, MySQL, Redis)
// - Automatic metric collection
// - Context propagation across async boundaries
// Environment variables:
// OTEL_SERVICE_NAME=checkout-api
// OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
// OTEL_TRACES_SAMPLER=parentbased_traceidratio
// OTEL_TRACES_SAMPLER_ARG=0.1 # Sample 10% of tracesManual trace + log correlation (for the important paths you want full context on):
const { trace, context } = require('@opentelemetry/api');
const logger = require('./logger'); // pino or winston with JSON output
async function processPayment(userId, amount, provider) {
const tracer = trace.getTracer('checkout-service');
return tracer.startActiveSpan('processPayment', async (span) => {
const traceId = span.spanContext().traceId;
// Always include traceId in logs — links log → trace
logger.info({ traceId, userId, amount, provider }, 'Payment processing started');
try {
span.setAttributes({
'payment.user_id': userId,
'payment.amount': amount,
'payment.provider': provider,
});
const result = await callPaymentProvider(provider, amount);
span.setStatus({ code: 1 }); // OK
logger.info({ traceId, result: 'success' }, 'Payment completed');
return result;
} catch (error) {
span.recordException(error);
span.setStatus({ code: 2, message: error.message }); // ERROR
// This log is findable from the trace when the span shows an error
logger.error({ traceId, error: error.message, provider }, 'Payment failed');
throw error;
} finally {
span.end();
}
});
}The Monitoring vs Observability Comparison (Full)

| Dimension | Monitoring | Observability |
|---|---|---|
| Core question | “Is something wrong?” | “What is wrong, why, and how to fix it?” |
| Data type | Predefined metrics and thresholds | High-cardinality, high-dimension telemetry (metrics + logs + traces + profiles) |
| Query flexibility | Pre-built dashboards | Ad-hoc exploration, query anything |
| Failure modes covered | Known, anticipated failures | Unknown, unanticipated failures |
| Root cause analysis | Manual, after the alert | Automated path: metric alert → trace → log |
| System understanding | Individual component health | End-to-end distributed system behaviour |
| Cardinality | Low–medium (aggregated) | High (raw event data with full context) |
| Typical MTTR impact | Days → hours | Hours → minutes |
| Storage cost | Low (aggregated metrics) | Higher (raw traces + logs) |
| Setup complexity | Low, thresholds and dashboards | Higher, instrumentation, correlation, SLO definition |
| 2026 standard | Prometheus + Grafana | OpenTelemetry + Grafana Stack (Tempo + Loki + Prometheus) |
When You Have Monitoring Without Observability (The Production Pain Pattern)
The pattern repeats: a monitoring alert fires at 2am. The on-call engineer gets paged. They open 5 different tools:
- Grafana: error rate spike visible
- Datadog: CPU looks normal
- Kibana: logs from 3 services, no clear pattern
- PagerDuty: the alert
- Slack: last deployment was 40 minutes ago
They spend 90 minutes correlating data manually, find the root cause (a config change in an upstream service), roll back, and spend another hour writing the postmortem.
With observability: Alert fires. Engineer opens Grafana. Clicks the trace linked from the alert. Sees the slow span. Navigates to the log for that trace ID. Reads the error. Identifies the config change from the deployment tag on the trace. Rolls back. Total time: 12 minutes.
The MTTR math: The difference between 90-minute and 12-minute MTTR at an enterprise costing $300K/hour of downtime is $345,000 saved per incident. Even at a $10,000/hour SaaS product, it is $13,000 per incident. Observability investment pays back in prevented incident costs.
The Practical Stack: Monitoring + Observability Together
Neither replaces the other. The right architecture uses monitoring as the detection layer and observability as the investigation layer.
The open-source observability stack (2026 default):
Collection: OpenTelemetry Collector (unified ingestion for all signals)
Metrics: Prometheus → Grafana (dashboards, alerting)
Logs: Loki → Grafana (log exploration, linked from traces)
Traces: Tempo → Grafana (distributed tracing, linked to logs)
Profiles: Parca or Pyroscope → Grafana (continuous profiling)
Alerting: Grafana Alerting → PagerDuty / Slack (routes from Prometheus)
SLOs: Grafana SLO definitions with error budget trackingMonthly cost at 100K requests/day (self-hosted on Kubernetes):
- Prometheus + Grafana: ~$50–100/month infrastructure
- Loki (log ingestion): ~$30–80/month depending on log volume
- Tempo (trace storage): ~$20–60/month with 10% sampling
- OTel Collector: negligible
- Total self-hosted stack: ~$100–250/month
Managed alternatives:
- Grafana Cloud (free tier covers small workloads): $0–$50/month at moderate volume
- Datadog (full APM + observability): $200–$2,000+/month depending on host count
- New Relic: similar to Datadog in pricing model
- AWS CloudWatch: cost-effective if already on AWS but less flexible querying
How InApps Implements Observability
InApps implements the full observability stack as part of DevOps Consulting engagements, always included in Phase 4 of the standard 6-phase DevOps implementation.
InApps observability standard:
Collection: OpenTelemetry Collector (all services instrument via OTel SDK)
eBPF auto-instrumentation where applicable (no code changes)
Metrics: Prometheus with recording rules + alert rules
Traces: Tempo (Grafana Labs) for trace storage; 10% sampling default
Logs: Loki with structured JSON logging requirement (trace_id mandatory)
Profiles: Parca (continuous CPU profiling) for high-traffic services
Visualisation: Grafana — unified dashboards for all four signals
Alerting: Grafana Alerting → PagerDuty (P1/P2) + Slack (P3/P4)
SLOs: Defined per service: availability, latency P99, error rate
Minimum instrumentation standard for all services:
- /health and /ready endpoints (liveness + readiness)
- Structured JSON logging with trace_id field
- OTel SDK or auto-instrumentation
- Prometheus /metrics endpoint
- Service-level SLO defined with error budgetInApps observability deliverables:
- DORA metric dashboard (deployment frequency, lead time, MTTR, change failure rate), automated, always current
- Service dependency map (auto-generated from traces)
- SLO dashboard with error budget burn rate
- Alert runbooks for every configured alert
- On-call rotation design and escalation policy
- 30-day MTTR baseline before and 30-day measurement after implementation
Get observability implementation →, InApps installs the full OTel stack, defines SLOs, configures alerting, and delivers DORA metric dashboards in one engagement.
Frequently Asked Questions
What is the difference between observability and monitoring?
Monitoring answers questions you already knew to ask, it detects known failure modes by comparing predefined metrics to thresholds. Observability answers questions you didn’t know to ask, it lets you investigate any system condition, anticipated or not, by examining high-cardinality telemetry (metrics, logs, traces, profiles) correlated with shared context. Monitoring tells you WHAT broke. Observability tells you WHY it broke and HOW to fix it. Both are required; neither replaces the other.
What are the three pillars of observability?
The three classic pillars are: (1) Metrics, numerical measurements aggregated over time; answer “is something wrong?” and “how is performance trending?”; (2) Logs, discrete, timestamped event records; answer “what exactly happened?”; (3) Traces, end-to-end paths of single requests across services; answer “where in the system did this request spend its time?”. In 2026, a fourth pillar is emerging: Profiles, continuous CPU flame graphs using eBPF, answering “why is the code slow?” OpenTelemetry is the de-facto standard for collecting all four.
What is OpenTelemetry and why does it matter?
OpenTelemetry (OTel) is an open-source observability framework that standardises how metrics, logs, traces, and profiles are collected and exported from distributed systems. Before OTel, every observability tool used its own instrumentation SDK, switching tools meant re-instrumenting the entire application. OTel is vendor-neutral: instrument once, route to any backend (Prometheus, Datadog, Grafana, etc.). In 2026, it is the de-facto industry standard with first-class support from every major cloud provider.
Can monitoring replace observability?
No. Monitoring detects anticipated failure modes, when CPU exceeds 85%, when error rate exceeds 5%. When a novel failure occurs, an unexpected service interaction, a race condition, a latency spike caused by a dependency three hops away, monitoring fires an alert but cannot explain the root cause. Investigation requires navigating multiple disconnected tools manually. Observability provides the correlated context (trace + log + metric) that makes root cause analysis possible in minutes instead of hours. In microservices architectures with 10+ services, monitoring alone becomes inadequate for incident investigation.
What is high-cardinality data in observability?
High-cardinality data means telemetry with many unique values, user IDs, request IDs, trace IDs, geographic regions, app versions. Low-cardinality data (aggregated metrics) loses this detail: it tells you the overall error rate but not which users, which requests, or which code path is failing. Observability requires high-cardinality telemetry to answer specific questions about specific events. This is why traces and structured logs (with trace_id, user_id, service version) are essential, they preserve the detail that makes root cause analysis possible.
Key Takeaways
- Monitoring = WHAT (and WHEN). Observability = WHY and HOW. Both are required; observability builds on monitoring.
- The distinction: Monitoring answers questions you already knew to ask. Observability gives you the power to ask new, unanticipated questions.
- Four pillars (2026): Metrics (WHAT is wrong) + Logs (WHAT happened in detail) + Traces (WHERE in the system) + Profiles (WHY the code is slow). OpenTelemetry collects all four.
- OpenTelemetry is the de-facto standard. Instrument once, route to any backend. Vendor-neutral. First-class support from every major cloud provider.
- The critical correlation: Metrics alert → navigate to trace → navigate to log at that trace_id. This is the investigation path that reduces MTTR from hours to minutes.
- Always include
trace_idin structured logs. Without it, logs and traces are disconnected, you lose the investigation path. - The MTTR math: 90-minute vs 12-minute incident resolution at $300K/hour downtime cost = $345,000 per incident. Observability investment pays back in prevented incident costs.
- Open-source stack: OpenTelemetry Collector + Prometheus + Loki + Tempo + Grafana. Cost: $100–$250/month self-hosted.
- High-cardinality telemetry is what separates observability from monitoring, user IDs, trace IDs, request IDs, deployment versions preserved in raw events.
- InApps stack: OTel SDK auto-instrumentation → Collector → Prometheus + Loki + Tempo + Grafana → PagerDuty. DORA metrics dashboard as a contract deliverable.
Work with us
Need a team that can do this on your codebase?
Tell us what you are shipping and we will send back a scope, a team shape and a fee. No obligation.
Book a free call




