← Back to Home
🧡

Spans, Traces & Context Propagation

The trace ID that ties everything together, and how it rides along with every request.

⏱10 min readπŸ“šDevOps Fundamentals

To use tracing well, you need its vocabulary. A trace is made of spans, connected by IDs, and the magic that keeps them connected across services is context propagation. Let’s break it down.


🎯 Learning Objectives


Spans and Traces

A span is a single named, timed operation β€” one unit of work (an HTTP call, a DB query, a function). A trace is the whole tree of spans for one request.

text
Trace (traceId = abc123)
└─ span: GET /checkout           (root span)
 β”œβ”€ span: call orders-service
 β”‚  └─ span: SELECT order       (child)
 └─ span: call payments-service
    └─ span: POST to bank API   (child)

Each span records:


The IDs That Connect Everything

Three IDs turn a pile of spans into a tree:

ID Meaning
traceId Same for every span in one request β€” the glue
spanId Unique to this individual span
parentId The spanId of the span that caused this one
text
traceId=abc123  spanId=1  parentId=none   GET /checkout
traceId=abc123  spanId=2  parentId=1      call orders
traceId=abc123  spanId=3  parentId=2      SELECT order
traceId=abc123  spanId=4  parentId=1      call payments

Because they share traceId=abc123, Zipkin knows these spans belong together; parentId tells it the nesting. That’s how the waterfall is reconstructed.


Context Propagation β€” The Key Idea

Here’s the crucial part: when service A calls service B, it must pass the trace context along, or B starts a brand-new trace and the story breaks. This passing-along is context propagation, and it happens via HTTP headers.

Zipkin’s classic B3 headers carry the context:

text
GET /pay HTTP/1.1
Host: payments
X-B3-TraceId: abc123
X-B3-SpanId: 4
X-B3-ParentSpanId: 1
X-B3-Sampled: 1

Service B reads these, continues the same trace (abc123), and creates its child spans under it. The modern standard, W3C Trace Context, does the same job with a single traceparent header:

text
traceparent: 00-abc123...-00f067aa0ba902b7-01

⚠ Propagation is where tracing usually breaks

If a trace looks broken (each service shows its own separate trace), the cause is almost always lost context propagation β€” a client that didn’t forward the headers, or an async boundary (queue, thread pool) that dropped them. Forwarding context is the thing to get right.


Sampling β€” You Don’t Trace Everything

Tracing every request in a high-traffic system is expensive. Sampling decides which requests to record. The X-B3-Sampled: 1 header above means β€œrecord this one.” Common strategies:

πŸ’‘ Keep the decision consistent

The sampling decision is made once at the edge and carried in the context, so either the whole trace is recorded or none of it is β€” you never get half a trace.


πŸ§ͺ Hands-on Lab

πŸ“

Reconstruct the Tree

Given these spans, draw the parent-child tree and identify the root span:

traceId=x9  spanId=A  parentId=none
traceId=x9  spanId=B  parentId=A
traceId=x9  spanId=C  parentId=A
traceId=x9  spanId=D  parentId=B

🧠 Knowledge Check

Knowledge Check

What links all the spans of a single request together?

Knowledge Check

Why is context propagation essential for tracing to work across services?


πŸ’Ό Interview Preparation

Interview Q&A

A trace is showing up as several disconnected traces instead of one. What's wrong and how do you fix it?


Summary

You now know the tracing data model β€” spans, traces, the traceId/spanId/parentId relationship β€” and the critical role of context propagation and sampling. Next, we actually instrument a service and send real traces to Zipkin.

Up Next

Instrumenting a Service & Sending Traces to Zipkin

You've mastered this lesson. Continue your journey to becoming a DevOps Engineer.

Start Next Lesson→