Micrometer
Micrometer
Micrometer is the application observability facade for the JVM ecosystem. It provides a vendor-neutral API for metrics collection and — as of Micrometer 1.10 / Spring Boot 3.x — also for distributed tracing. It is to metrics what SLF4J is to logging: write instrumentation once, bind to any backend at configuration time.
Two Distinct Sub-Projects
Micrometer Metrics (Original)
The original Micrometer (io.micrometer:micrometer-core) provides:
MeterRegistry— the central registry, accepts meter registrations- Meter types:
Counter,Gauge,Timer,DistributionSummary,LongTaskTimer,FunctionCounter,FunctionTimer - Dimensional (tagged) metrics:
registry.counter("http.requests", "method", "GET", "status", "200") - Registry implementations for Prometheus, Datadog, InfluxDB, CloudWatch, Graphite, and many more
Micrometer Tracing (New in 1.10 / Boot 3)
io.micrometer:micrometer-tracing provides a tracing API facade. Bridges connect it to concrete implementations:
io.micrometer:micrometer-tracing-bridge-otel— OpenTelemetry SDK backendio.micrometer:micrometer-tracing-bridge-brave— Brave/Zipkin backend (legacy)
Micrometer Tracing replaces Spring Cloud Sleuth for Spring Boot 3.x. Sleuth is incompatible with Boot 3 and is no longer maintained.
Micrometer Observation (Unified API)
ObservationRegistry and @Observed provide a single API that produces both metrics and traces simultaneously from one instrumentation point. This is the preferred approach for new instrumentation in Boot 3.
@Service
public class OrderService {
private final ObservationRegistry observationRegistry;
public Order getOrder(String orderId) {
return Observation.createNotStarted("order.fetch", observationRegistry)
.lowCardinalityKeyValue("service", "order-service")
.observe(() -> repository.findById(orderId));
}
}Micrometer Tracing Architecture
Application Code
│
▼
Micrometer Tracing API (io.micrometer:micrometer-tracing)
│
├──▶ Bridge: OTel (micrometer-tracing-bridge-otel)
│ │
│ ▼
│ OpenTelemetry SDK
│ │
│ ├──▶ Zipkin Exporter → Zipkin UI
│ ├──▶ OTLP Exporter → Jaeger / Grafana Tempo
│ └──▶ Console Exporter (dev)
│
└──▶ Bridge: Brave (micrometer-tracing-bridge-brave)
│
▼
Brave / Zipkin Reporter → Zipkin UI
Use only one bridge at runtime. The OTel bridge is recommended for new projects.
Spring Boot 3 Auto-Configuration
When spring-boot-starter-actuator is present alongside a tracing bridge, Spring Boot 3 auto-configures:
| Bean | Purpose |
|---|---|
ObservationRegistry | Central observation registry |
Tracer | Micrometer Tracing facade (backed by OTel or Brave) |
HttpServerObservationFilter | Instruments all incoming HTTP requests |
ObservationWebClientCustomizer | Instruments all WebClient requests |
MeterRegistry (composite) | Collects metrics, ships to configured backends |
PrometheusRegistry | Exposes /actuator/prometheus (if dependency present) |
Core Meter Types
Counter
Monotonically increasing value. Use for: requests handled, errors thrown, events published.
Counter counter = Counter
.builder("bff.aggregation.calls")
.description("Number of dashboard aggregations performed")
.tag("type", "dashboard")
.register(registry);
counter.increment(); // +1
counter.increment(5.0); // +5Timer
Records latency and throughput. Automatically exposes count, sum, max, and percentile buckets.
Timer timer = Timer
.builder("bff.aggregation.latency")
.description("End-to-end dashboard aggregation latency")
.tag("type", "dashboard")
.publishPercentiles(0.50, 0.95, 0.99) // publish as gauges
.publishPercentileHistogram() // publish as histogram buckets (for Prometheus)
.register(registry);
timer.record(() -> doAggregation()); // synchronous
timer.record(Duration.ofMillis(42)); // manualGauge
Point-in-time value. Use for: queue depth, active connections, thread count.
// Gauge backed by a collection size
registry.gauge("bff.pending.requests", pendingRequestQueue, Queue::size);
// Gauge backed by an AtomicInteger
AtomicInteger activeConnections = registry.gauge(
"bff.active.connections",
new AtomicInteger(0)
);DistributionSummary
Like a Timer but for non-time values (bytes, queue depths, batch sizes).
DistributionSummary summary = DistributionSummary
.builder("bff.response.payload.bytes")
.baseUnit("bytes")
.register(registry);
summary.record(responseBody.length());Prometheus Integration
Add io.micrometer:micrometer-registry-prometheus to the classpath. Spring Boot auto-registers it and exposes /actuator/prometheus.
management:
endpoints:
web:
exposure:
include: health, prometheus, metrics
metrics:
export:
prometheus:
enabled: true
tags:
# Common tags applied to all meters
application: ${spring.application.name}
environment: ${spring.profiles.active:default}Prometheus scrapes this endpoint and stores time-series data for Grafana queries.
Tracing Configuration
Full application.yml for OTel + Zipkin
management:
tracing:
sampling:
probability: 1.0 # 1.0 = 100% (dev); 0.1 = 10% (prod)
zipkin:
tracing:
endpoint: http://localhost:9411/api/v2/spans
otlp:
tracing:
# For Jaeger or Grafana Tempo via OTLP
endpoint: http://localhost:4318/v1/tracesFull build.gradle Dependencies
dependencies {
// Actuator (required for auto-configuration)
implementation 'org.springframework.boot:spring-boot-starter-actuator'
// Micrometer Tracing — OTel bridge
implementation 'io.micrometer:micrometer-tracing-bridge-otel'
// OTel exporter — choose one (or both)
implementation 'io.opentelemetry:opentelemetry-exporter-zipkin'
// implementation 'io.opentelemetry:opentelemetry-exporter-otlp'
// Metrics — Prometheus
implementation 'io.micrometer:micrometer-registry-prometheus'
// Reactor instrumentation (for WebFlux reactive chain tracing)
implementation 'io.micrometer:micrometer-tracing'
}Manual Span Creation
Inject Tracer (Micrometer facade, not OTel's directly) for manual spans:
@Autowired
private Tracer tracer;
public Mono<Result> doWork(String input) {
Span span = tracer.nextSpan()
.name("custom.operation")
.tag("input.type", getType(input))
.start();
return performWork(input)
.doOnError(e -> span.error(e))
.doFinally(signal -> span.end());
}Reactive Pipeline Considerations
In WebFlux (Project Reactor), ThreadLocal-based MDC does not propagate across operator boundaries. Micrometer Tracing stores the active span in the Reactor Context, which does travel across operators.
For structured logging to include trace IDs in WebFlux, use the MdcContextLifter + Hooks.onEachOperator pattern described in P5-BFF-Observability-Testing — OBS-04.
Micrometer vs. Spring Cloud Sleuth
| Aspect | Spring Cloud Sleuth | Micrometer Tracing |
|---|---|---|
| Spring Boot compatibility | Boot 2.x only | Boot 3.x (required) |
| Maintenance status | Discontinued | Active |
| Tracing API | Brave-first | Vendor-neutral facade |
| OTel support | Limited, bolt-on | Native bridge |
| Auto-config | Spring Cloud BOM | Spring Boot BOM |
Do not use Spring Cloud Sleuth with Spring Boot 3.x. The dependency will not resolve from current Spring Cloud 2024.0.x BOMs.
BFF-Specific Metrics
In a BFF-Pattern context, these metrics are most valuable:
http.server.requests — per-route latency + throughput (auto)
spring.cloud.gateway.requests — SCG route-level metrics (auto with SCG)
resilience4j.circuitbreaker.* — circuit breaker state and calls (auto with R4J)
bff.aggregation.calls — custom: aggregation invocation rate
bff.aggregation.latency — custom: end-to-end aggregation latency
bff.downstream.errors — custom: downstream error rate by service
Related Concepts
- Distributed-Tracing — the tracing concept Micrometer implements
- Spring-Cloud-Gateway — auto-instrumented by Micrometer when on classpath
- Resilience4j — circuit breaker metrics integrated with Micrometer
- Project-Reactor — reactive runtime with special MDC/context propagation needs
- BFF-Pattern — the architectural pattern being instrumented
Related Observability Patterns
- Metrics-and-Dashboards — Micrometer is the implementation facade; Metrics-and-Dashboards covers the pattern-level measurement frameworks (RED, USE, Four Golden Signals) that Micrometer metrics feed into
- SLO-SLI-SLA — Micrometer metrics (request duration histograms, error counters) are the raw data source for computing SLI ratios (good events / valid events) that define SLOs
- Structured-Logging — Micrometer's Observation API bridges metrics and trace context; Structured-Logging defines the JSON field schema that includes traceId for metrics-to-log correlation