Correlation — linking the three pillars of observability through shared identifiers.
Trace ID as an anchor:
trace_id.trace_id as label.trace_id to structured log.OpenTelemetry (automatic correlation):
1import { trace, context, SpanStatusCode } from "@opentelemetry/api";23const tracer = trace.getTracer("my-app");45async function handleRequest(req) {6 return tracer.startActiveSpan("handleRequest", async (span) => {7 const traceId = span.spanContext().traceId;8 logger.info({ traceId, message: "Processing request" });910 try {11 const result = await callService(req);12 span.setStatus({ code: SpanStatusCode.OK });13 return result;14 } catch (err) {15 span.setStatus({ code: SpanStatusCode.ERROR, message: err.message });16 span.recordException(err);17 throw err;18 } finally {19 span.end();20 }21 });22}
Loki + Tempo (Grafana stack):
1# Structured log with trace_id2{3 "level": "info",4 "message": "Request processed",5 "traceID": "abc123",6 "spanID": "def456",7 "service": "orders-api",8 "duration_ms": 429}
Grafana Explore:
trace_id.trace_id → "View trace" → see the full path.Exemplars in Prometheus:
1http_request_duration_seconds_bucket{le="0.1"} # histogram2# Exemplar: {trace_id="abc123"} attached to bucket
Summary: Trace ID → single key for navigating between traces → logs → metrics.