Observability vs. Monitoring: Metrics, Logs, and Traces in Distributed Systems

Monitoring detects that a system has departed from expected behavior. Observability provides the correlated evidence to investigate where the behavior emerged, which requests were affected, and which hypothesis to test next.

An API begins responding slowly. The dashboard confirms that P95 latency has increased, but traffic is stable and the error rate has barely moved. The service is technically available, yet users are waiting almost a second for an operation that normally completes in 200 milliseconds.

The monitoring system has detected the symptom. It has not explained which dependency consumed the time, whether every request was affected, what changed before the degradation, or which mitigation is safe.

That distinction is the practical boundary between monitoring and observability. Monitoring checks expected conditions. Observability gives engineers enough correlated evidence to investigate behavior they did not anticipate.

Metrics quantify the symptom. Traces reconstruct the execution path. Logs provide event-level context. None of them is sufficient by itself, and collecting all three does not automatically make a system observable. The capability emerges only when the signals share consistent identity, semantics, ownership, and operational purpose.

This guide explains how to design that capability, how to avoid telemetry that is expensive but diagnostically weak, and how to validate that the resulting system actually improves production decisions.

Monitoring and observability are not synonyms

Monitoring and observability overlap, but they describe different capabilities.

Google's SRE definition of monitoring focuses on collecting, processing, aggregating, and displaying quantitative data about a system. Monitoring is therefore an operational activity: define signals, evaluate conditions, visualize behavior, and notify people or automation when a condition requires action.

Observability is a property of the system and its instrumentation. A system is observable when an engineer can use its externally emitted evidence to ask new questions about internal behavior without first deploying new diagnostic code. OpenTelemetry describes this in terms of being able to investigate novel problems and answer why a behavior is occurring.

The distinction is not that monitoring uses metrics while observability uses three tools. Modern monitoring may use metrics, logs, traces, synthetic checks, profiles, and events. The distinction is the kind of question the system lets you answer.

What monitoring answers

Monitoring is effective when the condition can be defined before it happens:

These are known questions with explicit measurements and evaluation logic.

What observability supports

Observability becomes necessary when the investigation is not known in advance:

Observability does not guarantee automatic root-cause identification. It provides the evidence needed to reduce the search space, form a hypothesis, and test it. A trace can show where time accumulated without proving why it accumulated. A log can show a timeout without proving whether the dependency, the network, or local resource starvation caused it.

Operational comparison

DimensionMonitoringObservability
Primary purposeDetect and track expected conditionsInvestigate behavior, including unanticipated failure modes
Typical questionIs the service violating an objective?What path, dependency, state, or change explains the behavior?
InputsChecks, metrics, logs, traces, events, profilesThe same signals, correlated with consistent context and semantics
OutputDetection, notification, trend, statusEvidence, narrowed hypotheses, causal reconstruction, validation
Failure modeMissed or noisy alertsData exists but cannot be joined into an investigation
Success criterionImportant conditions are detected with acceptable precision and speedAn engineer can explain scope and test a mitigation without adding emergency instrumentation
Monitoring detects; observability supports investigation Monitoring rules detect an expected service violation, while correlated telemetry supports investigation, hypothesis formation, mitigation, and validation. System behavior Monitoring rules Correlated telemetry Expected condition violated? Continue evaluation Alert or automation Investigation Hypothesis Test or mitigation Validation No Yes correlated signals
Diagram 1 — Monitoring detects; observability supports investigation. Monitoring rules detect an expected service violation, while correlated telemetry supports investigation, hypothesis formation, mitigation, and validation.

The monitoring path determines that a known condition requires attention. The observability path supplies the evidence used after detection to understand scope, construct a hypothesis, and validate the response.

The central design decision is therefore not “Which observability product should we buy?” It is “Which production questions must an engineer be able to answer, and which signals must be correlated to answer them?”

The three core telemetry signals

Metrics, logs, and traces remain the most useful operational model for understanding distributed applications. Calling them the “three pillars” is convenient, but it is not a complete definition of observability. OpenTelemetry also models context, baggage, events, resources, and profiles. The three-signal model is valuable because each signal has a different cost and diagnostic shape.

Metrics: detect and quantify

A metric is a numeric measurement associated with time and a bounded set of dimensions. Metrics are designed for aggregation. They answer how much, how often, how long, and how behavior changes over time.

Common metric instruments include:

The exact instrument model depends on the telemetry standard and backend. The OpenTelemetry Metrics API, for example, defines counters, gauges, up-down counters, and histograms, while its data model describes how aggregated values and distributions are represented.

Useful service metrics include:

A metric is efficient because many events become one time series. That efficiency is also its limitation. A P95 value can show that 5% of requests exceeded a duration threshold, but it normally cannot tell you which individual requests were slow or what happened inside them.

For a deeper treatment of end-to-end performance and latency budgets, keep the system-level design question separate from the statistical interpretation of percentiles. For the latter, use the dedicated article on latency percentiles P50, P95, and P99.

Decision rule for metrics

Use a metric when the question requires aggregation across many events and the dimensions can remain bounded.

Do not put request IDs, transaction IDs, timestamps, raw URLs, email addresses, or user IDs into metric labels. Those values belong in logs or traces because their near-unique nature creates a new time series for each distinct label set.

Logs: preserve event context

A log is a record of an event. Its diagnostic value depends less on the sentence it contains than on the structure and context attached to it.

A weak log entry says:

Text
Something went wrong while processing the request.

It provides no stable operation name, service identity, result, error classification, duration, or correlation field. During an incident, engineers must infer context from surrounding lines, hostnames, and timestamps. That approach fails quickly when requests cross concurrent services.

A stronger structured record might be:

JSON
{
  "timestamp": "2026-07-12T22:14:08.417Z",
  "severity": "ERROR",
  "service.name": "authorization-api",
  "service.version": "2026.07.12.3",
  "deployment.environment": "production",
  "operation": "authorize",
  "result": "timeout",
  "trace_id": "4e8f2c7b6bb44df19cd9d6f0db8916a2",
  "span_id": "a1729f6b1c83e402",
  "correlation_id": "order-8129",
  "dependency": "risk-service",
  "duration_ms": 1842,
  "pool_wait_ms": 1614,
  "error_code": "DEPENDENCY_CONNECTION_ACQUIRE_TIMEOUT"
}

This record supports several investigative paths:

OpenTelemetry's logging specification explicitly supports correlation through time, trace context, and resource context. Including Trace ID and Span ID in log records lets an engineer move from a trace waterfall to the precise events emitted during that execution.

Fields that should be consistent

At minimum, application logs should use stable names for:

The specific schema should follow a shared convention rather than each team inventing its own names. OpenTelemetry Semantic Conventions exist precisely to provide common naming across languages, libraries, and platforms.

What not to log

More detail is not automatically better. Logs can create security, privacy, and cost risks. Avoid recording credentials, access tokens, complete payment data, personal data without a defined purpose, or full request and response bodies by default. Redaction and filtering must be part of the telemetry pipeline, not an afterthought after sensitive data reaches a backend.

Distributed traces: reconstruct execution

A distributed trace represents the path of an operation across process and network boundaries. It is composed of spans. Each span describes one operation with a start time, end time, attributes, events, status, and a parent relationship or link.

A simplified request path might be:

Text
Client
  -> API Gateway
    -> Authorization API
      -> Risk Service
        -> Database
        -> External Rules API

A trace turns that topology into a timed execution. It can show that the Authorization API completed 70 milliseconds of local work, waited 620 milliseconds for a connection to the Risk Service, spent 130 milliseconds in the dependency itself, and returned after 820 milliseconds overall.

That distinction matters. Without the waiting span or attribute, an engineer may blame the downstream service because it appears in the request path. With the complete timing, the evidence points instead to local connection acquisition or concurrency control.

Metrics, traces, and logs converge into a diagnosis Metrics show a latency increase, traces locate waiting before a dependency call, and structured logs identify connection acquisition timeouts; the three signals converge into one diagnosis. Slow authorization requests Metrics P95 rose 220 ms → 890 ms Traffic and errors stable Traces 620 ms before dependency call Only one operation and region Logs Connection acquire timeouts Pool wait and version context Correlated diagnosis
Diagram 2 — Metrics, traces, and logs converge into a diagnosis. Metrics show a latency increase, traces locate waiting before a dependency call, and structured logs identify connection acquisition timeouts; the three signals converge into one diagnosis.

Metrics establish impact and trend. Traces identify the degraded path. Logs explain the state and events associated with that path. The diagnosis depends on joining them, not reading them as isolated dashboards.

A trace localizes time; it does not automatically prove cause

A long span is evidence of where elapsed time was observed. It may represent:

The next decision is to compare traces, inspect resource metrics, and find state-specific logs. Observability supports causal analysis; it does not replace it.

Trace ID, Span ID, and Correlation ID

These identifiers are related but solve different problems.

Trace ID

A Trace ID identifies the complete distributed execution represented by one trace. Every span in that trace shares the same Trace ID.

The W3C Trace Context specification defines interoperable propagation through the traceparent and optional tracestate headers. The traceparent value carries the trace identifier, parent span identifier, version, and trace flags in a vendor-neutral format.

Example:

Text
traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01

The Trace ID in this example is:

Text
0af7651916cd43dd8448eb211c80319c

Span ID

A Span ID identifies one operation inside a trace. Parent and child Span IDs reconstruct the causal tree or graph.

A trace may contain spans for:

Each span has its own Span ID but retains the Trace ID of the distributed execution.

Correlation ID

A Correlation ID is an application-defined identifier used to associate events that belong to a logical workflow. It is not a replacement for trace context and is not standardized by W3C Trace Context.

A single business workflow may outlive one trace. For example, an order may be created synchronously, processed asynchronously, retried hours later, and reconciled the next day. Those executions may produce several traces while sharing one stable order or workflow correlation identifier.

Conversely, one trace may involve several business entities. Forcing a single domain identifier to serve as the Trace ID can break trace generation, sampling assumptions, and interoperability.

When to use each identifier

IdentifierScopeGenerated byLifetimePrimary use
Trace IDOne distributed executionTracing SDK or compatible tracing systemDuration of that traceJoin spans and correlated logs across services
Span IDOne operation within a traceTracing SDKDuration of the spanReconstruct parent-child execution and local timing
Correlation IDApplication or business workflowApplication, gateway, workflow engine, or domain componentMay span multiple traces and long-running processesJoin domain events, asynchronous stages, or retries

Propagation decision

Propagate W3C trace context across supported synchronous and asynchronous boundaries. Preserve application correlation fields only when they have a defined owner, lifecycle, and data classification.

Do not copy arbitrary user-supplied values into trusted correlation fields without validation. Do not overload baggage with large or sensitive values: propagated context travels through service boundaries and can increase request size or expose data to components that do not need it.

OpenTelemetry without backend lock-in

OpenTelemetry provides vendor-neutral APIs, SDKs, semantic conventions, context propagation, the OpenTelemetry Protocol, and the Collector. It standardizes how telemetry is produced and moved. It does not provide the complete observability outcome by itself.

What OpenTelemetry solves

OpenTelemetry helps standardize:

What OpenTelemetry does not decide

It does not decide:

Those remain architecture and operating-model decisions.

OpenTelemetry instrumentation and collection architecture Applications and zero-code instrumentation emit telemetry through OpenTelemetry SDKs and OTLP to a Collector, which processes and routes metrics, logs, and traces to separate backends. Application code Zero-code instrumentation OpenTelemetry API and SDK OTLP export OpenTelemetry Collector Processors batch · filter · redact · sample Metrics backend Logs backend Traces backend
Diagram 3 — OpenTelemetry instrumentation and collection architecture. Applications and zero-code instrumentation emit telemetry through OpenTelemetry SDKs and OTLP to a Collector, which processes and routes metrics, logs, and traces to separate backends.

The Collector decouples applications from backend-specific ingestion and centralizes cross-cutting controls such as batching, retries, filtering, redaction, and sampling. Small environments may export directly, but a Collector becomes valuable when telemetry policy must be changed without redeploying every service.

Automatic instrumentation and manual instrumentation

OpenTelemetry documentation distinguishes code-based and zero-code approaches. They should be combined rather than treated as competing choices.

Automatic or zero-code instrumentation is useful for:

It quickly reveals technical topology and baseline timing.

Manual instrumentation is required for:

Automatic instrumentation may show that an HTTP call took 800 milliseconds. Manual instrumentation may reveal that 650 milliseconds were spent waiting for a limited permit before the HTTP client was invoked.

A defensible instrumentation sequence

  1. Establish consistent resource identity: service name, version, environment, region, and instance or workload identity where appropriate.
  2. Enable automatic instrumentation for standard protocols and libraries.
  3. Define the critical user and business operations that require manual spans or metrics.
  4. Apply semantic conventions before inventing custom attribute names.
  5. Add trace and span context to structured logs.
  6. Define attribute cardinality budgets and sensitive-data rules.
  7. Load-test the telemetry path and measure application overhead, Collector saturation, dropped data, and backend ingestion cost.
  8. Validate the signals through a controlled failure or game-day scenario.

The last step is essential. Instrumentation that looks complete in a demo can fail under concurrency, asynchronous execution, partial sampling, or incident-level volume.

How to choose between RED, USE, and the Golden Signals

RED, USE, and the Four Golden Signals are not competing standards. They organize different views of the same system.

RED for request-driven services

The RED method, created by Tom Wilkie for service monitoring, focuses on:

RED is a strong default for APIs, RPC services, consumers, and other request-driven components. It reveals whether demand, failure, or latency changed.

USE for resources

Brendan Gregg's USE method evaluates each resource through:

USE applies to CPUs, disks, network interfaces, connection pools, thread pools, queues, memory capacity, and other finite resources.

The saturation dimension is critical. Average utilization can look acceptable while brief intervals reach full capacity and create queues. A five-minute CPU average of 70% does not prove that no one-second interval reached 100%.

The Four Golden Signals for service health

Google SRE's Four Golden Signals are:

They provide a compact operational view of user-facing service behavior and resource pressure.

How to choose

QuestionFrameworkExample signal
Are users receiving slower or failed operations?RED or Golden SignalsRequest duration distribution and error ratio
Has demand changed?RED or Golden SignalsRequests per second or messages per second
Is a finite resource becoming a bottleneck?USE or Golden SignalsQueue depth, pool waiters, throttled CPU time
Why did service latency increase?RED to detect, USE to localizeP95 by operation, then pool saturation and wait time
Which view should drive paging?SLO and symptom-oriented service signalsError-budget burn, availability, or latency SLI
RED detects service impact; USE tests resource pressure A service-latency alert leads from RED metrics to USE analysis of connection pools, CPU, and queue age, producing a hypothesis about local resource waiting. User-visible latency increases RED / Golden Signals Traffic or errors changed? Inspect duration by operation USE analysis Connection pool saturation CPU utilization Queue age Hypothesis: local resource wait Traffic stable
Diagram 4 — RED detects service impact; USE tests resource pressure. A service-latency alert leads from RED metrics to USE analysis of connection pools, CPU, and queue age, producing a hypothesis about local resource waiting.

RED and the Golden Signals show the user-visible symptom. USE examines whether a finite resource explains it. The methods become useful when they lead to the next decision, not when they exist as three separate dashboard folders.

Cardinality: when one label breaks the metrics system

Metric systems identify a time series by the metric name plus its complete label set. Every unique combination creates another series with storage, memory, indexing, query, and network cost.

This metric is dangerous:

Text
http_requests_total{
  user_id,
  transaction_id,
  request_id,
  timestamp
}

Every request can create a new label combination. The metric stops behaving like an aggregate and becomes an expensive event store implemented in the wrong signal.

A more defensible design is:

Text
http_requests_total{
  service,
  operation,
  status_code,
  region
}

These dimensions are bounded and support operational aggregation.

Prometheus documentation explicitly warns that high-cardinality or unbounded values such as user IDs and email addresses should not be used as labels. The same principle applies beyond Prometheus: almost-unique dimensions belong in logs or traces, not metric identity.

Why cardinality multiplies

Assume one request-duration metric uses these observed dimensions:

The theoretical upper bound is:

Text
12 × 40 × 5 × 6 = 14,400 time series

Add 100,000 active user IDs:

Text
14,400 × 100,000 = 1,440,000,000 possible combinations

The backend may not observe every combination, but each new unique label set still becomes a new time series. Even a small fraction of that upper bound can overwhelm ingestion, memory, retention, and query performance.

Cardinality is not only a storage problem

High cardinality also causes:

Cardinality explosion Service, operation, status, and region produce 14,400 possible metric series; adding 100,000 user IDs raises the theoretical combination count to 1.44 billion. Bounded labels service: 12 · operation: 40 status: 5 · region: 6 14,400 possible series user_id: 100,000 Up to 1.44 billion combinations Ingestion, memory, query, and cost risk
Diagram 5 — Cardinality explosion. Service, operation, status, and region produce 14,400 possible metric series; adding 100,000 user IDs raises the theoretical combination count to 1.44 billion.

Bounded operational dimensions already multiply. Adding a user-level identifier changes the metric from an aggregate signal into an unbounded series generator.

A label decision test

Before adding a metric label, ask:

  1. Is the set of values bounded?
  2. What is the current and projected number of distinct values?
  3. Does the dimension support an operational decision or only curiosity?
  4. Can the question be answered through logs or traces instead?
  5. What happens if a malformed client creates arbitrary values?
  6. Is the dimension required at full resolution or can it be normalized?

For HTTP metrics, use normalized routes such as /orders/{orderId} rather than raw paths such as /orders/8129.

Trace sampling as an engineering decision

Tracing every request may be acceptable at low volume, but it can become expensive in high-throughput systems. Sampling is the decision to retain and export only part of the trace population.

The objective is not to minimize data at any cost. It is to preserve enough evidence to answer operational questions while keeping application overhead, Collector capacity, backend ingestion, and retention within budget.

Head sampling

Head sampling decides near the start of the trace, before the final outcome is known.

Advantages:

Limitations:

Tail sampling

Tail sampling decides after enough spans have arrived to evaluate the trace outcome.

Advantages:

Limitations:

The OpenTelemetry Collector tail-sampling processor groups spans by Trace ID and requires consistent routing so all spans for a trace reach the same Collector instance responsible for the decision.

A defensible sampling policy

A common starting policy is:

Thresholds must be operation-specific. A 500-millisecond threshold may be severe for a cache lookup and normal for a long-running report.

What can go wrong

How to validate sampling

Track the sampling system itself:

Sampling is successful when investigators can still compare healthy and degraded executions, preserve rare failures, and query the trace backend during peak incidents.

Alert on impact, diagnose with causes

An alert should communicate that a condition requires action. The most reliable paging signals usually express user or service impact:

Google SRE recommends SLO-based alerting because it aligns the page with reliability as users experience it. Prometheus guidance similarly recommends alerting on symptoms and using consoles to identify causes.

Symptom signals

Examples:

Cause signals

Examples:

Cause signals are valuable for diagnosis and sometimes for prevention. They are weaker as primary paging rules because the same cause may have no user impact, while user impact may occur through a cause that was never encoded.

When a cause alert is justified

A cause-based page can be appropriate when:

Disk exhaustion, certificate expiration, exhausted capacity reservations, and replication failure can justify preventive alerts. The decision depends on actionability and consequence, not a blanket rule that cause alerts are always wrong.

Alert quality criteria

A page should have:

How to prevent alert fatigue

Alert fatigue is not simply “too many alerts.” It is the loss of trust caused by alerts that are noisy, duplicated, non-actionable, stale, or poorly prioritized.

Google SRE warns that low-priority pages disrupt work and can cause serious alerts to receive less attention. It also recommends controlling alert fan-out so one abnormal condition does not generate several independent pages.

Common causes

A practical review

For each alert, ask:

  1. What decision should the recipient make?
  2. Must a human act now?
  3. What user or system objective is threatened?
  4. Can the same condition be grouped at service or incident level?
  5. Does the notification contain enough context to begin triage?
  6. Is there a runbook, and has it been exercised?
  7. What is the expected alert-to-incident ratio?
  8. When was the rule last useful?

An alert with no immediate action should become a ticket, report, or dashboard annotation rather than a page.

What an operational dashboard must show

A dashboard is not a wall of available metrics. It is a decision interface.

Each panel should answer a production question. A service landing dashboard should let an on-call engineer determine impact, scope, recent change, and the next investigative path within minutes.

Recommended hierarchy

1. User and SLO impact

2. Demand and scope

3. Service behavior

4. Saturation and dependencies

5. Recent changes

What not to include

Dashboard decision table

PanelQuestion answeredFollow-up action
SLO burn rateIs the incident significant enough to page?Declare, escalate, or continue observation
Request duration by operationWhich operation is degraded?Filter traces and compare healthy versus slow requests
Dependency durationWhere is time accumulating?Inspect child spans, dependency metrics, and timeouts
Queue ageIs work waiting longer than allowed?Reduce intake, scale consumers, or remove the bottleneck
Deployment markersDid behavior change near a release?Compare versions; canary, rollback, or falsify the deployment hypothesis
Pool saturationIs local resource waiting involved?Inspect concurrency, limits, leaks, and downstream capacity

The primary dashboard should not attempt to replace the trace or log backend. It should direct the engineer to the next high-value query.

Production case: an API becomes slow without failing

Consider a generic authorization-api with the following normal behavior:

At 22:10 UTC, P95 rises to 890 ms. P99 reaches 1.7 seconds. Traffic remains near 9,200 requests per second and the error ratio increases only from 0.4% to 0.6%.

The service is not “down,” but it is consuming its latency budget and user-visible performance has degraded.

Step 1 — Detect the symptom

The alert should be tied to the latency SLI or error-budget burn, not merely to CPU or a pool metric.

Observed:

Text
P95: 220 ms -> 890 ms
P99: 410 ms -> 1,700 ms
Request rate: 9,100 -> 9,200 requests/s
Error ratio: 0.4% -> 0.6%

Initial conclusion:

Step 2 — Establish scope

Break down bounded dimensions:

The degradation appears only in:

Text
operation = authorize
region = west
service.version = 2026.07.12.3

Other operations and regions remain within their normal distributions.

Decision:

Step 3 — Compare healthy and slow traces

A healthy trace:

Text
Gateway                         12 ms
Authorization API local work    58 ms
Risk Service call              118 ms
Database lookup                 31 ms
Total                          219 ms

A slow trace:

Text
Gateway                         13 ms
Authorization API local work    71 ms
Connection acquisition wait    623 ms
Risk Service call              131 ms
Database lookup                 34 ms
Total                          872 ms

The remote call itself is only 13 milliseconds slower than normal. Most additional latency occurs before the call begins.

Slow trace with a dominant connection-wait span A request trace totals 872 milliseconds, with 623 milliseconds spent waiting to acquire a connection before a 131-millisecond dependency call. Gateway · 13 ms Authorization local work · 71 ms Connection acquisition wait · 623 ms Risk Service · 131 ms Database · 34 ms Total · 872 ms
Diagram 6 — Slow trace with a dominant connection-wait span. A request trace totals 872 milliseconds, with 623 milliseconds spent waiting to acquire a connection before a 131-millisecond dependency call.

The trace localizes the dominant delay to connection acquisition. It does not yet prove why the pool is saturated or whether the new version caused it.

Step 4 — Correlate logs by Trace ID

Search structured logs for slow traces:

JSON
{
  "service.name": "authorization-api",
  "service.version": "2026.07.12.3",
  "operation": "authorize",
  "trace_id": "4e8f2c7b6bb44df19cd9d6f0db8916a2",
  "event": "connection_pool.acquire",
  "pool.active": 40,
  "pool.idle": 0,
  "pool.waiters": 173,
  "pool_wait_ms": 623,
  "result": "acquired"
}

A second log shows that requests still complete, explaining the small error increase. They are waiting rather than immediately failing.

Step 5 — Test competing hypotheses

Possible hypotheses:

  1. The downstream Risk Service is slow.
  2. Network latency increased.
  3. The local connection pool is too small for current concurrency.
  4. Connections are leaked or held longer by version 2026.07.12.3.
  5. A retry policy increased concurrent dependency calls.

Evidence so far weakens hypotheses 1 and 2 because dependency execution time is close to baseline. It supports a local wait hypothesis but does not distinguish insufficient capacity, longer hold time, a leak, or retry amplification.

Inspect:

The version comparison reveals:

Text
2026.07.12.2: 1.02 dependency calls per request
2026.07.12.3: 1.84 dependency calls per request

A new retry path is retrying a class of responses that should not be retried. The extra attempts consume connections, increase waiters, and amplify latency without yet causing a large error spike.

This is a potential retry storm, even though the traffic arriving at the public API has not changed.

Step 6 — Choose a mitigation

Possible mitigations include:

Increasing the pool immediately is tempting but risky. It may transfer saturation to the downstream service, increase connection overhead, or hide the retry defect. The mitigation should remove amplification before adding capacity.

Decision:

For the design relationship between timeouts, retries, and cascading failures, treat each resilience mechanism as part of one load-control system rather than as an isolated library option.

Step 7 — Validate recovery

Do not close the incident because a configuration change succeeded. Validate the system-level outcome:

Text
P95: 890 ms -> 245 ms
P99: 1,700 ms -> 460 ms
Pool waiters: 173 -> 4
Dependency calls/request: 1.84 -> 1.03
Error ratio: 0.6% -> 0.4%
Latency SLO burn: returned below alert threshold

Also verify:

Step 8 — Prevent recurrence

Add or improve:

The complete incident method belongs in a dedicated piece so this article does not duplicate the full investigation framework: how to investigate an incident with metrics, logs, and traces.

Incident investigation flow Incident investigation proceeds from symptom confirmation through scoping, trace comparison, log correlation, hypothesis testing, reversible mitigation, validation, and prevention. Symptom alert Confirm user or SLO impact Scope by operation, region, and version Compare healthy and degraded traces Correlate logs by trace context Form competing hypotheses Test with metrics and change data Choose reversible mitigation Validate latency, errors, saturation, SLO Add prevention and regression tests
Diagram 7 — Incident investigation flow. Incident investigation proceeds from symptom confirmation through scoping, trace comparison, log correlation, hypothesis testing, reversible mitigation, validation, and prevention.

The process moves from impact to scope, execution evidence, hypothesis testing, reversible mitigation, and measurable validation. It avoids jumping directly from one suspicious metric to a permanent configuration change.

Common instrumentation failures

1. Collecting signals that cannot be correlated

Metrics use one service name, logs use another, and traces omit service version. Time zones differ and deployment markers are absent.

Consequence: Engineers spend the incident proving that records belong to the same component.

Correction: Standardize resource identity and timestamps. Inject Trace ID and Span ID into logs. Keep deployment metadata queryable.

2. Instrumenting only framework boundaries

Automatic instrumentation captures HTTP and database calls but not the domain stage that waits for a permit, evaluates a rule set, or activates a fallback.

Consequence: One large span hides the operation that matters.

Correction: Add manual spans or events at decision boundaries, not around every function.

3. Creating one span per trivial function

Excessive spans increase cost and make traces unreadable.

Consequence: Important timing is buried in implementation detail.

Correction: Create spans for remote calls, asynchronous boundaries, expensive stages, and diagnostically meaningful operations.

4. Using raw identifiers as metric labels

Request IDs, user IDs, and raw URLs create unbounded time series.

Consequence: The metrics backend becomes expensive or unavailable during high traffic.

Correction: Normalize dimensions and move unique context to logs or traces.

5. Logging the same exception at every layer

A dependency exception is logged by the client, service, controller, gateway, and global handler.

Consequence: One failure appears as five independent events and can trigger duplicate alerts.

Correction: Record the event where ownership and context are strongest; propagate structured status without duplicating noise.

6. Sampling without checking coverage

A global 1% head sample is enabled and considered complete.

Consequence: Low-volume operations and rare failures disappear.

Correction: Measure coverage by operation and outcome; preserve errors, slow traces, and a healthy baseline.

7. Alerting on every anomaly

Every resource threshold pages independently.

Consequence: One incident creates a notification storm and the on-call engineer cannot identify the primary impact.

Correction: Page on significant service symptoms, group related causes, and use cause metrics for diagnosis or preventive tickets.

8. Treating observability as a backend migration

The organization changes vendors but keeps inconsistent names, missing context, weak alerts, and decorative dashboards.

Consequence: Query syntax changes; diagnostic capability does not.

Correction: Define questions, schemas, ownership, and validation before selecting or migrating the backend.

Operational checklist

Instrumentation

Metrics

Logs

Traces

Alerts and dashboards

Validation

Conclusion

Monitoring is necessary because engineers cannot respond to a condition they do not detect. Observability is necessary because detection rarely explains a distributed failure.

The practical objective is not to collect the maximum amount of telemetry. It is to create a controlled evidence system:

The final validation is operational. When an unfamiliar incident occurs, the team should be able to determine scope, compare healthy and degraded behavior, test competing hypotheses, apply a reversible mitigation, and prove that the service recovered.

If the system emits millions of records but cannot support that sequence, it has telemetry. It does not yet have useful observability.

That sequence is also the limit of what is worth automating. Once evidence is obtained verifiably, the question stops being what to instrument and becomes who interprets the result: enterprise observability with AI covers where to place a model above these controls without letting it decide whether the system is healthy.

Frequently asked questions

Are observability and monitoring the same thing?

No. Monitoring is the activity of collecting and evaluating signals against expected conditions. Observability is the system's capability to support investigation through its emitted evidence. A mature monitoring system contributes to observability, but dashboards and alerts alone do not guarantee it.

What are the three pillars of observability?

Metrics, logs, and traces are a useful operational model because they provide aggregation, event context, and execution paths. “Three pillars” is a simplification, not a complete technical definition. Context propagation, resource identity, events, baggage, semantic conventions, and profiles may also be part of an observability system.

What is the difference between a Trace ID and a Correlation ID?

A Trace ID identifies one distributed execution and is propagated through tracing standards. A Correlation ID is application-defined and may represent a business workflow that spans several traces. They can coexist, but they should not be treated as interchangeable.

What is OpenTelemetry?

OpenTelemetry is a vendor-neutral observability framework that defines APIs, SDKs, semantic conventions, context propagation, protocols, and a Collector for telemetry such as traces, metrics, and logs. It standardizes instrumentation and transport; it does not choose the operational questions or backend strategy for you.

Should I use RED or USE?

Use RED for request-driven service behavior and USE for finite resources. RED helps detect user-visible changes in rate, errors, and duration. USE helps test whether utilization, saturation, or resource errors explain the symptom. The Four Golden Signals provide a compact service-level view that overlaps with both.

When should I use P95 or P99?

Use the percentile that corresponds to the user population, operation criticality, traffic volume, and SLO you need to protect. P99 exposes tail behavior but can be noisy for low-volume windows. Do not select a percentile because it is fashionable; select it because it represents an explicit reliability objective and has enough observations to be interpreted.

For the full statistical treatment, use the dedicated guide to latency percentiles P50, P95, and P99.

How do I prevent alert fatigue?

Reduce pages to significant, actionable conditions. Group related symptoms, align pages with SLO or high-consequence risk, attach ownership and runbooks, and review alerts that repeatedly fire without requiring action. A page that does not change a decision should become a ticket, report, or dashboard signal.

Technical references

Jorel del Portal

Jorel del Portal

Jorel del Portal is a systems engineer specialized in architecture, integration, resilience and observability of critical platforms. He designs systems, builds products and documents real engineering decisions.