Stage 4 · Provision
Observability-Driven Design
Distributed Tracing
OpenTelemetry, context propagation, and debugging across dozens of microservices.
Why Distributed Tracing?
In a microservices architecture, a single user request may traverse 10-30 services. When that request is slow or fails, you need to know which service caused the problem. Distributed tracing follows the request through every service and shows exactly where time was spent.
OpenTelemetry
OpenTelemetry (OTel) is the CNCF standard for telemetry collection. It provides SDKs for traces, metrics, and logs in every major language. OTel auto-instrumentation libraries capture traces without code changes for popular frameworks and libraries.
# Install: pip install opentelemetry-distro opentelemetry-exporter-otlp
# Run: opentelemetry-instrument python app.py
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
provider = TracerProvider()
processor = BatchSpanProcessor(OTLPSpanExporter())
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)
tracer = trace.get_tracer("payment-service")
with tracer.start_as_current_span("process_payment") as span:
span.set_attribute("payment.amount", 99.99)
span.set_attribute("payment.currency", "USD")
# Child spans are automatically linkedThe tracer creates spans for each operation. Child spans are automatically linked to parent spans, creating a tree that represents the full request flow.
Context Propagation
Context propagation is how trace context passes from one service to the next. The trace ID and span ID are injected into HTTP headers (W3C Trace Context: traceparent). The next service extracts the context and creates child spans.
Service A Service B Service C
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Span: A │──traceparent──►│ Span: B │──traceparent──►│ Span: C │
│ trace: T │ header │ trace: T │ header │ trace: T │
│ parent: -│ │ parent: A │ │ parent: B │
└──────────┘ └──────────┘ └──────────┘
All three spans share trace ID T, forming a trace tree:
T
├── A (root)
│ └── B (child of A)
│ └── C (child of B)The W3C traceparent header carries trace ID, parent span ID, and sampling flags. Every service in the chain extracts and re-injects this header.
Spans and Span Attributes
A span represents a single operation within a trace. Spans have a name, start time, end time, status, and attributes. Attributes are key-value pairs that provide context — HTTP method, database query, user ID, error message.
Sampling Strategies
Tracing generates enormous volumes of data. Sampling controls how many traces are collected. Always-on sampling is too expensive. Always-off loses data. Head-based and tail-based sampling provide balanced approaches.
| Strategy | How It Works | Tradeoff |
|---|---|---|
| Always On | Collect every trace | Expensive, high storage |
| Probability | Sample X% of traces | May miss rare errors |
| Head-based | Decide at trace start | Cannot filter by result |
| Tail-based | Decide after trace completes | Can filter errors/slows, more complex |
Tracing Backends
| Backend | Type | Strength |
|---|---|---|
| Jaeger | Open source | CNCF project, Kubernetes-native |
| Zipkin | Open source | Simple, well-established |
| Tempo | Grafana | Object storage, cost-effective |
| Datadog APM | Commercial | Full-stack observability |
Jaeger is the standard open-source tracer. Grafana Tempo is cheaper at scale because it uses object storage. Both integrate well with Grafana for visualization.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.