Production Observability & SRE · Lesson 3

Spring Boot, Micrometer, and OpenTelemetry Instrumentation

Instrument a Spring order service with Actuator, Micrometer Observation, tracing, OTLP, bounded dimensions, and tested propagation.

Quick answer

Spring Boot 4.1 uses Micrometer Observation as its primary abstraction for metrics and traces. Instrument the Spring order service once at business boundaries, use low-cardinality keys for aggregate metrics, reserve protected high-cardinality context for traces, and assign one owner to each exporter and propagation path. The application, Java agent, Spring starter, Collector, and backend are separate layers.

Auto-configuration is a starting point, not proof. A healthy Actuator endpoint cannot show that asynchronous context propagated, OTLP export succeeded, dashboards use the emitted schema, or checkout recovered.

Learning objectives

  • Instrument the Spring order service with Spring Boot 4.1 Actuator and Micrometer Observation while preserving signal and exporter ownership.
  • Choose low-cardinality metric keys, high-cardinality trace context, propagation, and OTLP boundaries without duplicating instrumentation.

Prerequisites

Know Spring dependency injection, HTTP request handling, Actuator basics, and the telemetry quality contract from Telemetry Quality and Cardinality.

Evidence and system boundary

Micrometer Observation can create metrics and traces from one observation lifecycle. Spring Boot configures common framework observations and Micrometer registries. Micrometer Tracing bridges tracing implementations. Spring Boot exposes basic OpenTelemetry integration and OTLP exporters, while the OpenTelemetry Java agent and community Spring starter remain separately versioned community options.

Do not add an agent, starter, manual instrumentation, and framework interceptor to the same boundary without a duplication test. Duplicate spans and counters can make an incident look worse and inflate telemetry cost.

@Component
final class OrderObservation {
  private final ObservationRegistry registry;

  OrderObservation(ObservationRegistry registry) {
    this.registry = registry;
  }

  void record(String region, Runnable operation) {
    Observation.createNotStarted("order.submit", registry)
        .lowCardinalityKeyValue("region", region)
        .observe(operation);
  }
}

This example is explanatory and was not executed against a production service. A real convention should use reviewed bounded values and must not attach an order ID or customer identity to metrics.

Instrumentation design

Start at decisions: request accepted, validation rejected, transaction committed, outbox published, reservation consumed, and response completed. Framework HTTP observations already cover transport timing; custom observations should add business boundaries, not reproduce framework spans.

Set stable service.name, environment, and version attributes outside request code. Propagate context across supported executors and reactive boundaries according to Spring documentation. A caller timeout does not roll back a database commit or remote effect, so record stable idempotency and outcome evidence separately from the trace lifecycle.

Metrics may export through a Micrometer registry, including OTLP. Traces may export through Micrometer Tracing and OpenTelemetry. Spring Boot does not automatically make every OpenTelemetry SDK signal an exported Spring signal. Test the exact configured path instead of assuming one OpenTelemetry bean owns logs, metrics, and traces.

Expose only the minimum Actuator surface and protect it independently. Management endpoints are operational interfaces, not public diagnostics. Never expose environment values, request bodies, tokens, or raw configuration merely to improve observability.

Production failure scenario

After enabling an OpenTelemetry agent, the Spring order service emits two server spans per request and trace context disappears in an @Async reservation step. Metrics remain visible, so the team initially blames the tracing backend.

Operators compare instrumentation libraries, disable duplicate ownership, test the configured task context propagation, and confirm OTLP export at the Collector. They verify that new order requests produce one server span, one business observation, linked asynchronous evidence, and unchanged bounded metrics. A passing test does not claim production recovery; user SLI and durable order outcomes remain separate checks.

Common misconceptions

  • Actuator health is not end-to-end business availability.
  • Micrometer Observation and the OpenTelemetry API are not interchangeable configuration surfaces.
  • Adding an agent does not automatically preserve every async or messaging boundary.
  • High-cardinality trace context is not safe as a metric dimension.
  • A successful exporter call does not guarantee durable storage or a usable query.

Decision checklist

  • Assign one instrumentation owner per boundary.
  • Prefer framework observations before adding custom spans.
  • Review low- and high-cardinality keys separately.
  • Set stable service, environment, and version identity.
  • Test HTTP, executor, reactive, and messaging propagation.
  • Verify application, Collector, exporter, and backend freshness.
  • Protect Actuator endpoints and redact before export.
  • Correlate telemetry with user and durable-order evidence.

Previous: Telemetry Quality and Cardinality. Next: Structured Logging and Correlation IDs. Follow the complete Production Observability & SRE course and topic.

For application operations, continue with Spring Boot Actuator, Health, and Metrics and Kubernetes Probes and Graceful Shutdown.

Official sources

Official sources accessed August 19, 2026. Community agent and starter versions must be checked independently from Spring Boot support.

Knowledge check

Check your understanding

Answer both questions correctly to mark this lesson as mastered. You can retry without penalty.

1. A custom order observation needs region for metrics and an internal operation reference for a protected trace; how should the keys differ?

2. Spring metrics arrive through Micrometer but traces disappear after enabling a second agent; what should operators verify?