What is the role of the Brave vs OpenTelemetry bridge in Micrometer Tracing, and what dependencies do you need to export spans to Zipkin?
answer
- Micrometer Tracing = facade, bridge = real tracer
- bridge-brave OR bridge-otel — never both
- Brave -> zipkin-reporter-brave; OTel -> opentelemetry-exporter-zipkin
- endpoint default :9411/api/v2/spans
- sampling.probability default 0.1 gates export
basics
~20 sMicrometer Tracing defines a vendor-neutral API; a bridge plugs in a real tracer — either Brave or OpenTelemetry. To send spans to Zipkin you add the bridge plus a Zipkin reporter/exporter dependency; Spring Boot auto-configures the endpoint.
solid answer
~40 sMicrometer Tracing is a **facade**: it exposes a neutral `Tracer`/propagation API but does no tracing itself. You must add exactly one **bridge** that supplies the actual implementation: `micrometer-tracing-bridge-brave` (Brave, the Zipkin-native tracer) or `micrometer-tracing-bridge-otel` (OpenTelemetry SDK). To ship spans to **Zipkin**, add a reporter matching your bridge: with Brave use `zipkin-reporter-brave`; with the OTel bridge use `opentelemetry-exporter-zipkin`. Spring Boot's `ZipkinAutoConfiguration` then wires a sender pointing at `management.zipkin.tracing.endpoint` (default `http://localhost:9411/api/v2/spans`). Choose **Brave** if you're Zipkin-centric and want the lightest path; choose **OTel** if you want the OpenTelemetry ecosystem, OTLP export, and to send to Tempo/Jaeger/collectors. You never put both bridges on the classpath — they conflict.
code
groovy · 23 lines// --- Option A: Brave bridge -> Zipkin (lightweight, Zipkin-centric) ---
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'io.micrometer:micrometer-tracing-bridge-brave'
implementation 'io.zipkin.reporter2:zipkin-reporter-brave'
}
// --- Option B: OpenTelemetry bridge -> Zipkin (OTel ecosystem) ---
// dependencies {
// implementation 'org.springframework.boot:spring-boot-starter-actuator'
// implementation 'io.micrometer:micrometer-tracing-bridge-otel'
// implementation 'io.opentelemetry:opentelemetry-exporter-zipkin'
// }
// NOTE: never combine bridge-brave and bridge-otel in the same app.
// application.yml
// management:
// tracing:
// sampling:
// probability: 1.0 # dev: export everything (default is 0.1)
// zipkin:
// tracing:
// endpoint: http://localhost:9411/api/v2/spansgo deeper
Know you need actuator + a bridge + a Zipkin reporter.
Explain the facade/bridge split and the default endpoint and sampling probability.
Justify Brave vs OTel per use case and debug an empty-Zipkin situation systematically.
Standardize the tracing stack across services, weigh OTel Collector/OTLP vs direct Zipkin, and manage migration/cost.
## The facade + bridge model Micrometer Tracing does not implement spans or propagation. It defines abstractions — `io.micrometer.tracing.Tracer`, `Span`, `Propagator`, `BaggageManager` — and delegates to a real tracing library through a **bridge**. This is the same 'pick your implementation' pattern as SLF4J. You must include **exactly one** bridge. ## The two bridges 1. **Brave bridge** — `io.micrometer:micrometer-tracing-bridge-brave`. Brave is the tracer originally built for Zipkin/OpenZipkin. It is lightweight and the most direct route if your backend is Zipkin. Propagation uses Brave's `Propagation` (B3 native, W3C supported). 2. **OpenTelemetry bridge** — `io.micrometer:micrometer-tracing-bridge-otel`. This delegates to the **OpenTelemetry SDK**. Choose it to join the broader OTel ecosystem: OTLP protocol, the OpenTelemetry Collector, auto-instrumentation agents, and backends like Grafana Tempo or Jaeger. Propagation uses OTel's `TextMapPropagator`. **Never add both** — you get two `Tracer` beans / conflicting auto-configuration. Pick one per application. ## Exporting to Zipkin The bridge produces spans in memory; an **exporter/reporter** serializes and sends them. Match the reporter to the bridge: - **Brave -> Zipkin**: add `io.zipkin.reporter2:zipkin-reporter-brave`. It uses the Zipkin v2 JSON format over HTTP. - **OTel -> Zipkin**: add `io.opentelemetry:opentelemetry-exporter-zipkin`. Spring Boot's **`ZipkinAutoConfiguration`** detects the reporter and configures the sender from: - `management.zipkin.tracing.endpoint` — default `http://localhost:9411/api/v2/spans`. - Related properties for connect/read timeouts and encoding. ## Sampling gates export Export is downstream of the **sampling decision**. `management.tracing.sampling.probability` (default **0.1** = 10%) controls what fraction of traces are recorded and thus exported. In dev you typically set it to `1.0`. A common 'nothing shows up in Zipkin' cause is leaving the default 0.1 (or 0) and only sending a few requests. ## Choosing a bridge — decision factors - **Zipkin-only, minimal footprint, existing Brave/Sleuth-B3 fleet** -> Brave bridge + zipkin-reporter-brave. - **Multi-backend / future-proofing / OTel Collector / OTLP / Tempo / Jaeger** -> OTel bridge + the matching exporter (`opentelemetry-exporter-otlp` for OTLP, `opentelemetry-exporter-zipkin` for Zipkin). - **Agent-based auto-instrumentation** (OpenTelemetry Java agent) generally pairs with the OTel path. ## What Spring Boot auto-configures With actuator + a bridge + a reporter on the classpath, Boot wires: the `Tracer`, the `ObservationHandler`s that translate observations to spans, the propagators, and the Zipkin sender. You usually only set the endpoint and sampling probability. ## Gotchas - **Both bridges present** -> startup/bean conflicts. Enforce one via dependency management. - **Bridge without reporter** -> spans are created and appear in logs (trace IDs) but nothing reaches Zipkin. - **Reporter mismatched to bridge** (e.g. otel exporter with brave bridge) -> not wired. - **Endpoint wrong / Zipkin down** -> spans dropped; the reporter typically logs and moves on rather than failing requests. - **Sampling 0.1 default** -> most traces silently not exported; looks like it's 'not working'. - **OTel bridge != OTLP automatically**: the OTel bridge still needs an exporter dependency for whatever protocol/backend you target.
- You added `micrometer-tracing-bridge-brave` and see trace IDs in your logs, but Zipkin is empty. What are the likely causes?Most likely: (1) no exporter dependency (`zipkin-reporter-brave`) so spans are created but never sent; (2) sampling probability at the default 0.1 or 0, so few/no traces are recorded; (3) wrong or unreachable Zipkin endpoint. Trace IDs in logs only prove the bridge works, not that export is wired.
- When would you pick the OpenTelemetry bridge over Brave?When you want the OpenTelemetry ecosystem: OTLP export to an OTel Collector, backends like Grafana Tempo or Jaeger, alignment with OTel auto-instrumentation agents, or vendor-neutral portability. Brave is preferable when you're Zipkin-only and want the lightest, most direct setup.
saying these in an interview costs you the question
- Putting both the Brave and OTel bridges on the classpath.
- Expecting spans in Zipkin with a bridge but no exporter/reporter dependency.
- Forgetting that the default sampling probability is 0.1, so most traces are never exported.
- Pairing an OTel exporter with the Brave bridge (or vice versa).