Part 8 · Observability
Logs, Metrics & Traces: The Three Pillars
“Checkout took 20 seconds and failed” — but checkout touches eleven components. How logs, metrics and traces each answer a different question, how to instrument with OpenTelemetry, and how linking them takes you from “something's wrong” to “here's why” in minutes.
On this page
The Problem
A customer writes in: "Checkout took 20 seconds and then failed." You look at your system. Checkout touches:
- the API gateway,
- the cart, pricing, inventory and payment services,
- a Kafka event (a message sent through Kafka, a system that passes messages between services),
- two databases and a Redis cache (a very fast store that keeps often-used data in memory),
- a third-party payment provider.
Which one was slow? Was it only this customer, or everyone? Did it start after this morning's deploy?
With one server, you could log in over SSH (a secure remote login) and read the log file. Now you have 40 services running on 300 containers. A container is a small, isolated box that runs one program, and containers start and stop all the time. So you can't do that any more. You need the system to tell you what it is doing. This is called observability. Observability means you can understand what happens inside a system by looking at the data it produces. It is built on three kinds of data: logs, metrics and traces.
The Core Idea
Think about how a hospital understands a patient.
- Metrics are the vital-signs monitor: heart rate, blood pressure and temperature. These are all numbers measured over time. You can see at a glance that something is wrong ("heart rate jumped to 140"), and you can set alarms.
- Logs are the doctor's and nurses' notes: detailed, timestamped entries. "10:42 patient reported chest pain; administered medication X." They tell you what happened in detail.
- Traces are like following one patient's whole journey through the hospital: reception → triage → X-ray → blood test → specialist → pharmacy, with how long each step took. They show where the time went for one specific case.
In one line: a log is one event written down, a metric is a number measured over time, and a trace is the path of one request. You need all three. The monitor tells you something is wrong, the journey shows you where, and the notes tell you why.
How It Works
1. Logs: detailed records of events
A log is a timestamped record of something that happened: a request, an error, a decision.
Unstructured logs are plain sentences. People can read them, but machines find them hard to search:
2027-03-08 10:42:13 ERROR Payment failed for user 42 order 5521 after 3012ms: card declinedStructured logs put each fact in its own named field. They are usually written as JSON (a text format made of key-value pairs). They are much better:
{ "timestamp": "2027-03-08T10:42:13.482Z", "level": "error", "service": "payment-service", "message": "payment failed", "user_id": 42, "order_id": "5521", "duration_ms": 3012, "error_code": "card_declined", "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736", "version": "2027.03.08-1"}Now you can search and filter by any field ("all error_code=card_declined in the last hour, grouped by version").
Logging best practices:
- Use log levels:
DEBUG(development detail),INFO(normal events),WARN(unusual but handled),ERROR(something failed),FATAL(the service is crashing). In production, usually log at INFO and above. - Include context: request ID, trace ID, user or tenant ID, service name, version, and duration.
- Use correlation IDs. A correlation ID is a unique label that you attach to one request. Create a request ID at the edge (the first server that receives the request). Pass it to every service in an HTTP header (extra information sent with a request). Then you can find all log lines for one request across the whole system.
- Centralise logs. Ship logs from every container to one searchable place: the ELK/Elastic stack, OpenSearch, Grafana Loki, Splunk, Datadog or cloud logging services. Local log files on containers disappear when the container does.
- Never log secrets or sensitive data: passwords, tokens, full card numbers, OTPs. Be careful with personal data (Part 9). Mask or remove it.
- Watch the cost. Logging everything at high traffic can cost more than the servers themselves. Sample the noisy success logs (keep only a small share, for example 1 in 100) and keep all errors. Also set a retention period, which is how long you keep data. For example, keep 7–30 days of searchable logs, and move older ones to cheap object storage.
2. Metrics: numbers over time
A metric is a number that you measure and record again and again over time, such as "requests per second". It often has labels (also called dimensions or tags). A label is a small name-value tag, such as region=eu, that lets you split the number into groups.
Metric types:
- Counter: only goes up (total requests, total errors). You usually look at its rate ("errors per second").
- Gauge: goes up and down (memory used, queue length, active connections, temperature).
- Histogram: counts values in buckets (for example, how many requests took under 50 ms, under 100 ms, under 250 ms). From the buckets you can work out percentiles (post 8). A percentile is the value below which a given share of requests fall. For example, p95 = 200 ms means 95% of requests were faster than 200 ms. Use histograms for latency, not averages.
- Summary: works out percentiles inside each service (on the client side). It is simpler, but you can't combine the percentiles of many servers into one correct overall percentile. So histograms are usually preferred.
Why metrics are powerful:
- Cheap to store: a number every 10–60 seconds, no matter how much traffic there is.
- Fast to query over long periods ("show error rate for the last 30 days").
- Perfect for dashboards and alerts.
The cardinality trap. Cardinality means how many different values something can have. A time series is one list of numbers over time. Every unique combination of labels creates its own separate time series:
Never use unbounded values (user IDs, order IDs, email addresses, full URLs with IDs) as metric labels. Put those in logs and traces instead.
Pull vs push:
- Pull: the metrics system scrapes each service. This means it reads (downloads) the current numbers from the service's
/metricsendpoint every few seconds. Prometheus (a popular open-source metrics system) works this way. - Push: services send metrics to a collector (StatsD, OpenTelemetry OTLP, many SaaS agents).
What should you measure? Three proven frameworks
The Four Golden Signals come from Google's SRE book. SRE (Site Reliability Engineering) is the way Google runs services reliably. The four signals apply to any service that users call:
- Latency: how long requests take. Track the time of failed requests separately.
- Traffic: how much demand (requests per second).
- Errors: the rate of failed requests.
- Saturation: how "full" the service is (CPU, memory, queue depth, connection pool usage).
The RED method is for services that answer requests: Rate (requests per second), Errors (how many fail) and Duration (how long they take).
The USE method (from Brendan Gregg) is for resources like CPU, disks and network: Utilisation (how busy), Saturation (how much work is waiting), Errors.
A good default: RED for every service, USE for every resource, and business metrics like orders per minute, sign-ups and payment success rate. Business metrics often catch problems that technical metrics miss.
3. Traces: following one request across services
A distributed trace records the full path of one request through all the services it touches, with the time of each step. "Distributed" means the request travels across many services.
- A trace is the whole journey, identified by a trace ID.
- A span is one step in that journey (one service call, one database query), with a start time, a duration, attributes and a parent span.
Trace 4bf92f35… POST /checkout (total 3,240 ms)
│
├─ api-gateway [■■ ] 12 ms
├─ cart-service: get cart [ ■■■ ] 38 ms
│ └─ redis GET cart:42 [ ■ ] 2 ms
├─ pricing-service: calculate [ ■■■■ ] 61 ms
│ └─ postgres SELECT prices [ ■■■ ] 44 ms
├─ inventory-service: reserve [ ■■■ ] 40 ms
└─ payment-service: charge [ ■■■■■■■■■■■■■■■■■■■■■■■■■■■] 3,012 ms ← here!
└─ HTTP POST payment-provider [ ■■■■■■■■■■■■■■■■■■■■■■■■■■] 2,998 msOne glance shows that the payment provider is the slow part, not your code.
How it works: context propagation. Context propagation means passing the trace information from one service to the next. When service A calls service B, it sends the trace ID and its own span ID in an HTTP header. The W3C Trace Context standard (a shared web standard) defines this header:
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01 version-trace_id-parent_span_id-flagsService B continues the same trace and creates child spans. You must also pass the context through queues and events by putting it in the message headers. If you do not, the trace breaks wherever work is done later (asynchronously, Part 6).
Sampling. Sampling means recording only some requests instead of all of them. Recording every span of every request is expensive at high traffic. You have two options:
- Head sampling: decide at the start (for example, keep 1% of traces). Simple, but you might miss rare errors.
- Tail sampling: hold the spans for a short time, then decide after the request has finished. Keep all slow or failed traces plus a small share of normal ones. This is more useful, but it needs more infrastructure.
Tools: Jaeger, Zipkin, Grafana Tempo, and commercial tools like Datadog, Honeycomb, New Relic and Dynatrace.
OpenTelemetry: one standard for all three
OpenTelemetry (OTel) is an open standard and a set of tools for producing and collecting traces, metrics and logs. "Vendor-neutral" means it is not tied to one company's product. It is a project of the Cloud Native Computing Foundation (CNCF), a non-profit that hosts open-source cloud projects.
- SDKs and auto-instrumentation for most languages. Instrumentation means adding code that records traces, metrics and logs. With auto-instrumentation, many frameworks, HTTP clients and database drivers record data without you writing that code.
- The OTel Collector receives data, processes it (samples it, filters it, removes sensitive fields) and exports it to the storage tools (backends) you choose. Services send data to it with OTLP, the OpenTelemetry protocol.
- Standard names ("semantic conventions") for common attributes (extra details attached to data), like
http.routeanddb.system.
- 1Services with the OTel SDKauto-instrumented HTTP, gRPC and database calls
- 2OTel Collectorsamples, filters, strips sensitive fields, batches
- 3Prometheus / Grafana
- 4Tempo / Jaeger
- 5Loki / Elasticsearch
If you instrument once with OpenTelemetry, you can switch vendors without rewriting your code.
Connecting the three pillars
- 🔔 checkout p99 > 2 s
- open latency histogram
- exemplar trace_id 4bf92f…
- open trace 4bf92f…
- payment span = 3,012 ms of 3,240
- filter trace_id = 4bf92f…
- “provider timeout, retrying”
The real power comes from linking them:
- An alert fires: "checkout p99 latency > 2 s" (metric).
- You open the latency graph and click on an exemplar, a sample trace attached to a histogram bucket, to jump to a slow trace.
- The trace shows the payment span is slow. You click it to see its logs (they share the
trace_id), which say "provider timeout, retrying".
That path from metric → trace → logs takes minutes instead of hours, if you include trace IDs in logs and use consistent service names and labels everywhere.
Monitoring vs observability
- Monitoring answers known questions, such as "Is the error rate above 1%?" or "Is the disk full?" You decide in advance what to watch.
- Observability is the ability to answer new questions you didn't plan for: "Why are checkouts slow only for Android users on app version 5.2 in Pune paying with a specific bank?"
Good observability needs rich, high-cardinality context. High cardinality means a field can have very many different values, like user ID or device. You attach user, device, version, region and similar fields to events and traces. Then you can group and filter the data in any way during an investigation. Tools like Honeycomb made this "wide events" approach popular. A wide event is one record that carries many fields.
Trade-offs
- Logs: rich detail and flexible search, but expensive at volume, noisy, and a risk of leaking sensitive data.
- Metrics: cheap, fast, great for alerts and long-term trends, but low detail and cardinality limits. They can tell you that something is wrong, rarely why.
- Traces: the best tool for "where is the time going?" across services, but they need instrumentation everywhere and context propagation (including through queues), and sampling may miss cases.
- More telemetry: better visibility, but higher costs (storage, processing, vendor bills) and some performance overhead. Budget for it, and trim what you never use.
In the Real World
Google's Dapper. Google described Dapper, its internal distributed tracing system, in a 2010 paper. It showed that tracing could run across Google's huge systems with very low overhead by using sampling. Dapper inspired Zipkin (built at Twitter) and Jaeger (built at Uber), which were both later open-sourced.
Prometheus. Prometheus was built at SoundCloud in 2012, inspired by Google's internal monitoring, and became the second project (after Kubernetes) to graduate in the Cloud Native Computing Foundation. "Graduate" means it reached the top maturity level. Together with Grafana (a tool for dashboards and graphs), it is one of the most common open-source monitoring setups today.
OpenTelemetry's origins. OpenTelemetry was formed in 2019 by merging two earlier projects, OpenTracing and OpenCensus, to end the confusion of competing standards. It's now supported by nearly every observability vendor.
Charity Majors and Honeycomb. Charity Majors and colleagues at Honeycomb helped popularise the modern meaning of "observability": being able to ask new questions of production using rich, high-cardinality event data. Their book Observability Engineering is a standard reference.
Cost surprises. Many companies have written about their logging and monitoring bills growing faster than their infrastructure. Sampling, retention policies, dropping unused metrics and the OTel Collector's filtering have become essential cost controls.
Interview Questions
Q1What are the three pillars of observability, and what does each answer?
Metrics — numbers over time — answer “is something wrong, and how much?” and drive dashboards and alerts. Traces — one request's path across services — answer “where is the time going?”. Logs — detailed event records — answer “what exactly happened, and why?”.
Q2Why use histograms rather than averages for latency?
Averages hide the tail. Histograms record counts per latency bucket, so you can compute p95 and p99 and — unlike client-side summaries — merge them across servers.
Q3What is metric cardinality, and why does it matter?
The number of unique label combinations; each one is a separate time series. Unbounded labels like user_id or order_id create millions of series and overwhelm the metrics backend. Put such IDs in logs and traces instead.
Q4How does distributed tracing work across services and queues?
Each hop propagates the trace context — trace ID and parent span ID, usually in the W3C traceparent header — and creates child spans with timings. For async flows, the context must travel in message headers, or the trace breaks at the queue.
Q5Head sampling vs tail sampling?
Head sampling decides at the start of a request (keep 1%) — cheap, but it can miss rare errors. Tail sampling buffers spans and decides after the request finishes, keeping all slow or failed traces plus a small share of normal ones — more useful, but it needs collector infrastructure.
Q6What's the difference between monitoring and observability?
Monitoring checks known conditions you decided to watch in advance. Observability is being able to answer new, unplanned questions about production by slicing rich, high-cardinality context on events and traces.
Key Takeaways
- Logs say what happened in detail, metrics show trends and alerts as numbers over time, and traces show where time goes for one request across services.
- Use structured JSON logs with correlation/trace IDs, centralise them, and never log secrets.
- Use counters, gauges and histograms (histograms for latency and percentiles). Follow Golden Signals / RED / USE, and avoid high-cardinality labels.
- Tracing needs context propagation (W3C
traceparent, including through queues) and smart sampling (keep slow and failed traces). - Instrument with OpenTelemetry, and link the three pillars (metric → trace → logs) to go from "something's wrong" to "here's why" in minutes.
Further Reading
- Site Reliability Engineering by Google (chapter "Monitoring Distributed Systems", which introduces the Four Golden Signals)
- The OpenTelemetry documentation ("Concepts")
- The Prometheus documentation (overview, metric types, naming best practices, and "Histograms and summaries")
- The Dapper paper, "Dapper, a Large-Scale Distributed Systems Tracing Infrastructure" (Google, 2010)
- Brendan Gregg's article "The USE Method"
- The W3C Trace Context specification
- Observability Engineering by Charity Majors, Liz Fong-Jones and George Miranda
Published by Jainik · Last updated · How these lessons are made
Keep learning
Part of the study guide
Related series