Distributed tracing — Micrometer Tracing with OpenTelemet… — Cracked Java
// Spring Framework & Spring Boot · Spring Boot Actuator, Observability
SeniorSystem DesignBig Tech

Distributed tracing — Micrometer Tracing with OpenTelemetry / Zipkin.

Distributed tracing follows a single request as it hops across services, stitching the per-service spans into one end-to-end trace so you can see where the latency lives. In a microservice call chain — gateway → orders → inventory → payment — a log line on its own tells you nothing about the whole request. Tracing assigns a trace ID that propagates across every hop and a span ID per unit of work, so the entire journey is reconstructable.

Micrometer Tracing replaced Sleuth in Boot 3

In Spring Boot 3 the old Spring Cloud Sleuth is gone, replaced by Micrometer Tracing — a vendor-neutral tracing facade (mirroring Micrometer's metrics facade). It doesn't trace by itself; it bridges to a concrete tracer:

  • OpenTelemetry via micrometer-tracing-bridge-otel
  • Brave/Zipkin via micrometer-tracing-bridge-brave

You pick one bridge plus a reporter dependency to send spans to a collector.

<dependency>
  <groupId>io.micrometer</groupId>
  <artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
<dependency>
  <groupId>io.opentelemetry</groupId>
  <artifactId>opentelemetry-exporter-zipkin</artifactId>
</dependency>
management:
  tracing:
    sampling:
      probability: 0.1        # sample 10% of traces
  zipkin:
    tracing:
      endpoint: http://zipkin:9411/api/v2/spans

What you get for free

Boot's instrumentation auto-creates spans for incoming HTTP requests, RestClient/WebClient/RestTemplate outbound calls, and more — propagating context via W3C traceparent headers. Crucially, the trace and span IDs are injected into the MDC, so your log pattern can print them:

%5p [${spring.application.name},%X{traceId:-},%X{spanId:-}]

Now a log line carries the trace ID, and you pivot from a Zipkin/Jaeger waterfall straight to the matching logs.

Sampling is the production lever

Tracing every request is expensive in storage and overhead, so you sampleprobability: 0.1 keeps 10%. Sampling decisions propagate, so a trace is captured whole or not at all (no half-traces). For manual spans, inject Tracer or annotate with @NewSpan/@SpanTag.

Mark your status