KCNA — Tracing and OpenTelemetry
Tracing and OpenTelemetry
Distributed tracing is the third pillar of observability. When a single user request passes through multiple microservices, traces help you understand where time is spent and where failures occur.
Why Tracing?
In a monolith, debugging is straightforward — one process, one log file. In microservices, a single request may touch 10+ services.
User → API Gateway → Auth → Order → Inventory → Payment → Notification
Without tracing:
- “The checkout is slow” → But which service is slow?
- “An order failed” → But where in the chain did it fail?
With tracing:
- See the complete request path with timing for each service
- Identify the exact service causing latency or errors
Key Concepts
Trace
A trace represents the complete journey of a request through the system. It has a unique Trace ID that connects all related work.
Span
A span represents a single unit of work within a trace. Each service call creates a span.
| Span Property | Description |
|---|---|
| Trace ID | Unique ID shared by all spans in the trace |
| Span ID | Unique ID for this specific span |
| Parent Span ID | The span that initiated this span |
| Operation Name | What the span represents (e.g., “HTTP GET /orders”) |
| Start/End Time | Duration of the operation |
| Tags/Attributes | Metadata (HTTP status, error flag, etc.) |
| Logs/Events | Timestamped events within the span |
Trace Visualization
Trace ID: abc-123
├── API Gateway ─────────────────────── 120ms
│ ├── Auth Service ────── 15ms
│ └── Order Service ──────────────── 95ms
│ ├── Inventory ───── 20ms
│ └── Payment ───────── 45ms
│ └── Bank API ──── 30ms
Context Propagation
For tracing to work across services, the trace context must be passed (propagated) between services.
Service A Service B Service C
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Span A │ ── headers ──→│ Span B │ ── headers ──→│ Span C │
│ trace=abc│ traceparent │ trace=abc│ traceparent │ trace=abc│
└──────────┘ └──────────┘ └──────────┘
Context is propagated via HTTP headers:
- W3C Trace Context:
traceparentheader (standard) - B3: Used by Zipkin
- Jaeger: Custom headers
Jaeger (CNCF Graduated)
Jaeger is a distributed tracing platform, originally developed at Uber.
Architecture
Application ──→ Jaeger Agent ──→ Jaeger Collector ──→ Storage ──→ Jaeger Query/UI
(SDK/client) (sidecar/daemon) (processes traces) (ES/Cassandra) (visualization)
| Component | Purpose |
|---|---|
| Jaeger Client | SDK in your application for creating spans |
| Jaeger Agent | Receives spans locally, batches and sends to collector |
| Jaeger Collector | Validates, indexes, and stores traces |
| Storage | Elasticsearch, Cassandra, or Kafka |
| Jaeger Query + UI | Web interface for searching and visualizing traces |
Key Features
- Distributed context propagation across services
- Performance and latency optimization — find slow services
- Root cause analysis — trace errors through the call chain
- Service dependency analysis — visualize service relationships
OpenTelemetry (CNCF Incubating)
OpenTelemetry (OTel) is the emerging standard for collecting all three pillars of observability data — metrics, logs, and traces — through a single framework.
What OpenTelemetry Provides
| Component | Purpose |
|---|---|
| APIs | Standard interfaces for instrumentation |
| SDKs | Language-specific implementations (Go, Java, Python, JS, etc.) |
| Collector | Agent that receives, processes, and exports telemetry data |
| OTLP | OpenTelemetry Protocol — standard wire format |
OpenTelemetry Collector
┌─────────┐ ┌─────────┐ ┌─────────┐
│ App 1 │ │ App 2 │ │ App 3 │
│ (OTel │ │ (OTel │ │ (OTel │
│ SDK) │ │ SDK) │ │ SDK) │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
└──────────────┼──────────────┘
▼
┌──────────────────────────┐
│ OpenTelemetry Collector │
│ ┌──────────────────────┐│
│ │ Receivers ││ ← Receive data (OTLP, Jaeger, Zipkin)
│ ├──────────────────────┤│
│ │ Processors ││ ← Transform, filter, batch
│ ├──────────────────────┤│
│ │ Exporters ││ ← Send to backends
│ └──────────────────────┘│
└──────────────────────────┘
│
┌──────────┼──────────┐
▼ ▼ ▼
Jaeger Prometheus Loki
(traces) (metrics) (logs)
Why OpenTelemetry Matters
| Before OTel | After OTel |
|---|---|
| Separate SDKs for metrics (Prometheus client), traces (Jaeger client), logs (custom) | One unified SDK for all signals |
| Vendor-specific formats | Standard OTLP format |
| Hard to switch backends | Change exporter config, keep instrumentation |
| Fragmented ecosystem | Converged standard |
OpenTelemetry merged OpenTracing and OpenCensus into a single project.
Sampling
In high-traffic systems, collecting every trace is expensive. Sampling reduces the volume:
| Strategy | Description |
|---|---|
| Head-based | Decide to sample at the start of the trace (e.g., 10% of all requests) |
| Tail-based | Decide after the trace completes — sample error traces and slow traces |
| Rate limiting | Collect a fixed number of traces per second |
Tail-based sampling is preferred because it captures interesting traces (errors, slow requests) while dropping routine ones.
KCNA Exam Tips
- Know what a trace and span are — a trace is the full journey, spans are individual steps
- Context propagation passes trace IDs between services via HTTP headers
- Jaeger is a CNCF Graduated distributed tracing platform
- OpenTelemetry is the unified standard for metrics, logs, and traces (CNCF Incubating)
- OpenTelemetry merged OpenTracing and OpenCensus
- The OTel Collector has three stages: Receivers → Processors → Exporters
- Know the difference between head-based and tail-based sampling
What’s Next?
Learn about cost management in cloud-native environments — FinOps practices and resource optimization.