Monitoring and Observability Patterns
Adapted from: Brendan Burns, Designing Distributed Systems (O'Reilly), Chapter 14 — rewritten and condensed for teaching.
Services run 24/7 across time zones. Reliability means noticing problems before customers do — and having enough signal to understand why. Four building blocks show up in almost every observability stack:
| Concept | Role |
|---|---|
| Logging | One execution / one place in code |
| Metrics | Aggregates over many requests over time |
| Alerting | Rules that interrupt you when something crosses a line |
| Tracing | Rebuild one user request across many services |
flowchart LR
APP[Service]
LOG[Logs]
MET[Metrics]
ALERT[Alerts]
TRACE[Traces]
APP --> LOG
APP --> MET
APP --> TRACE
LOG --> ALERT
MET --> ALERT
Logging
At heart, logging is still “something happened here with this data” — printf with better manners. Volume is the enemy: useful while debugging a hot component; spam during healthy steady state (and expensive to store/search).
Libraries usually add:
- Timestamps — order and deltas between lines
- Request context — thread / user / request IDs so parallel work is separable
- Levels — filter noise without deleting code paths
Typical levels:
| Level | Use |
|---|---|
| Debug | Verbose; on only when investigating |
| Info | Normal operational breadcrumbs |
| Warning | Concerning but not fatal |
| Error | Something bad; someone should look soon |
| Fatal | Unrecoverable; process exits after the line |
Default runtime level is often Info or Warning; flip Debug on for a class/component when an incident needs detail (conditional logging). Be careful: turning on heavy debug for every request can cause the next outage via latency.
What to log: errors/exceptions almost always; “weird” cases (a path that took 30s); not a play-by-play of every function. Ask: what would I wish I had logged when debugging the hardest bug in this code?
Check: logging
Logging practices
1 / 2How do logs differ from metrics?
Pick an answer to see if you are right.
Hands On: Leveled log filter
Metrics
Metrics characterize general execution as time series: instantaneous state and how it changes.
Three useful shapes (Prometheus-style vocabulary):
| Type | Idea | Examples |
|---|---|---|
| Histogram | Distribution over an interval | Latency, request/response size |
| Count | Monotonic integral | Total requests served |
| Value (gauge) | Up and down | CPU %, memory bytes |
Counts often become rates (derivative): requests now minus requests one minute ago → requests/minute. Tiny windows (e.g. per-ms) look spiky; average the rate over a sensible window.
Prometheus is primarily pull/scrape: the server asks apps for the current metric snapshot. Short-lived batch jobs may finish before a scrape — use a push gateway so jobs push metrics that Prometheus still scrapes.
Basic request monitoring
Start with request count (interesting as a rate), then enrich with labels like HTTP status (200, 404, 500). Labels must be a small discrete set — do not put raw latency or unbounded customer IDs on a counter label.
Latency is its own histogram (p50 vs p99 matter). You can still label latency histograms by status class to compare error vs success latency.
Advanced request monitoring
- Request/response size histograms (correlate with slowness; watch growth over time)
- Split queue wait vs processing latency — scale out vs optimize code
- Coarse geography as a label; fine customer analytics often via log search (metrics stay cheap aggregates; logs stay rich)
Check: metrics
Metrics shapes
1 / 2Why is HTTP status a good Prometheus label on a request counter, but raw latency is not?
Pick an answer to see if you are right.
Hands On: Rates, error ratio, latency buckets
Alerting
Logs and metrics help after you know something is wrong. Alerting tells you to look — ideally before a customer-reported incident (CRI).
Basic alerting
Rules on metric queries + static thresholds, e.g.:
- p90 latency > 500ms
- HTTP 500s > 1% of requests
Those thresholds effectively encode your SLO: what “good enough” means. Tune for users and on-call health — constant pages and false alarms cause burnout and ignored pages. Alerting is lifelong maintenance as the system and monitors evolve.
Not every metric needs an alert; many exist only for dashboards and debugging. Application quality still tracks alert quality.
Anomaly detection
Static global thresholds miss 100% outage for 1% of users while the fleet average looks fine. Anomaly / per-cohort detection is harder but increasingly necessary as systems grow.
Check: alerting
Alert design
1 / 2Why treat alert thresholds as tied to SLOs?
Pick an answer to see if you are right.
Hands On: Should we page?
Tracing
Per-service logs and metrics show all traffic mixed together. Tracing reconstructs one user request across microservices.
Practical approach:
- Mint a correlation / trace ID at the edge (random large ID, or hash of stable request traits).
- Attach it to every log/metric emission.
- Propagate it on outbound calls (e.g. HTTP header
x-my-apps-correlation-id) into each service’s request context.
Prefer OpenTelemetry SDKs and backends over a one-off home-grown stack — vendor-agnostic instrumentation is already a solved community problem.
flowchart LR
EDGE[Edge + trace id]
A[Service A]
B[Service B]
C[Service C]
EDGE -->|header| A --> B --> C
Check: tracing
Distributed tracing
1 / 2What problem does a correlation ID solve that per-service metrics alone do not?
Pick an answer to see if you are right.
Hands On: Propagate and group by trace
Aggregating Information
Observability data grows fast. Aggregation (and tiering) keeps it queryable and affordable.
- Cross-replica log search —
ktail-style fan-in, or ship to Elasticsearch / cloud log search - Prefer managed log and metrics services for something this critical
- Downsample metrics (e.g. 1s → 1m after a week; store averages not one arbitrary sample)
- For logs: keep errors, sample a fraction, or build app-specific compressions
- Cold storage when you need long retention / compliance but rare access — slower queries, lower cost; some SaaS products tier automatically
Check: aggregation
Aggregation and retention
1 / 2Why downsample old high-resolution metrics?
Pick an answer to see if you are right.
Hands On: Downsample a time series
- Observability rests on logs, metrics, alerts, and traces — each answers a different question.
- Log levels + context; metric histograms / counts / gauges, labels carefully, pull + push gateway for batch.
- Alerts encode SLOs; watch on-call load and cohort blind spots (anomaly detection).
- Trace IDs (prefer OpenTelemetry) rebuild one request across services; aggregate and downsample/tier storage so signal stays affordable.
Further Reading
- Brendan Burns — Designing Distributed Systems (O'Reilly), Chapter 14 (Monitoring and Observability Patterns)
- Common Failure Patterns — next: thundering herds, silent zeros, and other recurring outages
- Coordinated Batch Processing — batch pipelines that still need metrics and push gateways
- Important Distributed System Concepts — SLOs, percentiles, and reliability vocabulary
- Prometheus documentation — scrape model, metric types, PromQL
- OpenTelemetry — vendor-agnostic traces, metrics, and logs
- Google SRE Book — Monitoring Distributed Systems — four golden signals and alerting philosophy