Logs, metrics or traces?
| Dimension | Logs | Metrics | Distributed tracing |
|---|---|---|---|
| In one line | Timestamped records of events | Numbers aggregated over time | One request’s path through the services, as timed spans |
| One unit of data | A text line or JSON object per event | A sample of a labelled time series, such as a counter, gauge or histogram | A span: trace ID, parent span ID, name, start, duration, status |
| Best at answering | What exactly happened to this request, and why? | How much, how fast, and is it getting worse? | Where did the time go, and which hop failed? |
| Cost grows with | Traffic and verbosity: GB ingested, stored and scanned | The number of series (label combinations), not traffic | Traffic times spans per request, unless you sample |
| Sampling | Drop DEBUG and noisy repeats; keep every error | Not needed: the data is already aggregated | The norm: head (a fixed share) or tail (keep errors and slow traces) |
| Alerting | Possible through log-based metrics or queries; slower and costlier | The usual basis for alerts and SLOs | Rarely on traces themselves; on metrics derived from spans |
| Breaks when | Lines are free text, or share no ID, so ten services’ logs can’t be joined | A label has unbounded values, or someone averages percentiles | One service in the path doesn’t pass the header on, so the trace splits |
| Standards | Syslog (RFC 5424); OpenTelemetry log data model | Prometheus exposition format; StatsD; OpenTelemetry metrics | W3C Trace Context; OpenTelemetry traces |
| Joins to the others by | trace_id and span_id fields on each line | Exemplars: sample values that carry a trace ID | The trace ID, which finds the logs; span data can produce rate, error and duration metrics |
| Where it’s stored | CloudWatch Logs, Cloud Logging, Azure Monitor Logs, Loki, Elasticsearch, OpenSearch, ClickStack | Prometheus, CloudWatch metrics, Cloud Monitoring, Azure Monitor Metrics | X-Ray, Cloud Trace, Application Insights, Jaeger, Zipkin, ClickStack |
Rule of thumb
You need all three, in this order: metrics to notice (alert on rate, errors and duration), traces to find the slow or failing hop, and logs for the details of that one request. Make them join from the start: the same service name everywhere and the trace ID in every log line.
Sources
- OpenTelemetry docs: Observability primer (logs, metrics, traces)
- OpenTelemetry specification: Logs data model (TraceId and SpanId fields)
- OpenTelemetry specification: Metrics data model (exemplars)
- OpenTelemetry docs: Sampling (head and tail)
- Prometheus docs: Metric and label naming (high-cardinality caution)
- Prometheus docs: Histograms and summaries (quantiles can’t be aggregated)
- Prometheus docs: Exposition formats
- RFC 5424: The Syslog Protocol
- W3C: Trace Context
- Amazon CloudWatch pricing (per-GB logs, per-metric and per-GB metrics)
- AWS docs: What is Amazon CloudWatch? (metric filters, Application Signals)
- Grafana Labs blog: The RED Method
- Grafana Loki docs: Overview
- AWS docs: What is AWS X-Ray?
- Google Cloud docs: Cloud Trace overview
- Microsoft Learn: Application Insights overview
- Jaeger docs