the metrics, logs, and traces triad
Imagine you run a busy restaurant and want to understand how it is doing. You could keep running tallies — plates served per hour, average wait time (those are metrics). You could keep a diary of notable events — 'oven broke at 7pm', 'large party arrived' (those are logs). Or you could follow one single customer's whole visit from door to dessert, timing each step (that is a trace). These three views of the same kitchen are the classic 'three pillars' people use to make a system observable.
Each pillar has a precise shape and a precise cost. A metric is a number measured over time — a counter (requests served), a gauge (memory in use right now), or a histogram (the distribution of request durations). Metrics are tiny and cheap to store and aggregate, so they are great for dashboards and alerts, but a single number throws away the detail of any individual event. A log is a timestamped record of a discrete event, ideally structured as key-value fields (see structured logging); logs keep per-event detail but their volume and cost grow with traffic. A trace follows ONE request as it flows across functions and services, recording each step (called a span) and how long it took; a trace is the only one of the three that shows you the causal path and where the time went within a single request. The three are complementary: metrics tell you THAT something changed, traces show you WHERE in the request the time went, and logs give the WHY at a specific point.
It matters because no single pillar answers every question, and using the wrong one is wasteful or impossible. You would not store a per-request trace as a metric (you would lose the request identity), nor scan billions of logs to compute an average latency (a metric does that in one cheap number). The modern honest refinement: the 'three pillars' framing can mislead if you store them as three disconnected silos — the real win comes when one wide structured event can be rolled up into a metric, kept as a log, and stitched into a trace, so you move between views without re-instrumenting. OpenTelemetry exists largely to unify them.
metric: http_request_duration_seconds{route="/pay"} histogram, p99 = 0.8s log: {ts:..., level:"error", route:"/pay", user:4821, err:"timeout"} trace: /pay (820ms) -> auth (12ms) -> charge (790ms!) -> receipt (18ms)
Same incident, three views: the metric flags slow /pay, the trace localises the cost to charge(), the log says why (a timeout).
A common misconception is that you must buy three separate tools. You do not — and storing the three as disconnected silos is the failure mode the field is moving away from; the goal is to navigate from a metric spike straight to the exact traces and logs behind it.