Context Propagation and Span Instrumentation
Propagate trace context across threads and services using Micrometer Observation and OpenTelemetry.
Why Context Propagation Matters
In a distributed system, a single user request hops across threads, queues, and services. Distributed tracing stitches these hops together using a shared trace context (a trace ID plus the current span ID).
- If the context is lost, your trace breaks into disconnected fragments.
- Spring Boot 4 uses Micrometer Observation as the unified API and OpenTelemetry (or Brave) as the tracing bridge.
- The challenge: keep the active span attached as work crosses thread and process boundaries.
This lesson shows how to instrument spans and propagate context both in-process (across threads) and across services (over HTTP/messaging headers).
The Observation API
Micrometer's ObservationRegistry is the entry point. An Observation abstracts both metrics and a tracing span, so one instrumentation point feeds both pillars.
Observation.createNotStarted(name, registry)builds it.observe(Runnable)opens a scope, runs the code, and closes it — making the span the active one for the current thread.
While the scope is open, any nested instrumentation (HTTP client, JDBC, logging MDC) automatically becomes a child span.
import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationRegistry;
@Service
public class OrderService {
private final ObservationRegistry registry;
public OrderService(ObservationRegistry registry) {
this.registry = registry;
}
public Order place(Long id) {
return Observation.createNotStarted("order.place", registry)
.lowCardinalityKeyValue("order.type", "standard")
.observe(() -> doPlace(id));
}
private Order doPlace(Long id) {
// child spans created here join the same trace
return new Order(id);
}
}All lessons in this course
- Context Propagation and Span Instrumentation
- Circuit Breakers and Bulkhead Isolation
- Rate Limiting, Retry, and Time Limiters
- Correlating Logs, Metrics, and Traces