Spring Boot Observability 2026: OpenTelemetry, Distributed Tracing und Interview-Fragen
Spring Boot Observability mit OpenTelemetry und Micrometer Tracing beherrschen. OTLP-Export konfigurieren, die Observation API nutzen und Interview-Fragen meistern.

Spring Boot Observability vereint Logging, Metriken und Distributed Tracing in einem einheitlichen System, das den Fluss von Anfragen durch Microservices sichtbar macht. Mit Spring Boot 3 hat das Framework Micrometer Tracing (als Ersatz für Spring Cloud Sleuth) eingeführt und die Observation API präsentiert, die einen einzigen Instrumentierungspunkt bietet, der sowohl Metriken als auch Traces erzeugt.
Spring Boot empfiehlt die Verwendung von Observation.observe() anstatt direkter OpenTelemetry-Aufrufe. Ein einzelner Instrumentierungsaufruf erzeugt Metriken über Micrometer und Traces über die OpenTelemetry-Bridge, was Code-Duplikation reduziert und konsistente Tag-Benennung über alle Signale hinweg gewährleistet.
Wie die Observation API Micrometer und OpenTelemetry verbindet
Die Observation API fungiert als Fassade über Metriken und Tracing. Wenn Code Observation.createNotStarted() aufruft, leitet Spring Boot die Observation an registrierte Handler weiter: MeterObservationHandler für Micrometer-Metriken und TracingObservationHandler für Distributed Traces. Diese Architektur bedeutet: einmal instrumentieren, überall exportieren.
Die Bridge-Abhängigkeit micrometer-tracing-bridge-otel verbindet Micrometer Tracing mit dem SDK von OpenTelemetry. Traces fließen durch den SdkTracerProvider von OpenTelemetry und werden via OTLP an Backends wie Jaeger, Tempo oder jeden OpenTelemetry-kompatiblen Collector exportiert.
@Configuration
public class ObservabilityConfig {
@Bean
public ObservationRegistryCustomizer<ObservationRegistry> addLowCardinalityTags() {
return registry -> registry.observationConfig()
.observationHandler(new ObservationTextPublisher()); // Logs observations to console
}
}Die obige Konfiguration registriert einen ObservationHandler, der jede Observation protokolliert. In Produktionsumgebungen senden die automatisch konfigurierten Handler Daten an Micrometer-Registries und OpenTelemetry-Exporter ohne zusätzlichen Code.
Erforderliche Abhängigkeiten für Spring Boot 3.4 Tracing
Spring Boot 3.4 benötigt explizite Abhängigkeiten für Distributed Tracing. Der spring-boot-starter-actuator stellt die Observation API bereit, aber Tracing erfordert die OpenTelemetry-Bridge und einen Exporter.
<!-- pom.xml -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>
</dependencies>Das micrometer-tracing-bridge-otel-Artefakt verbindet Micrometer Tracing mit der API von OpenTelemetry. Der opentelemetry-exporter-otlp sendet Spans an Collector über das OTLP-Protokoll via HTTP oder gRPC. Spring Boot verwaltet die Versionsabstimmung durch sein Dependency Management.
OTLP-Export nach Jaeger oder Tempo konfigurieren
Spring Boot konfiguriert automatisch einen OtlpHttpSpanExporter, wenn die OTLP-Abhängigkeit vorhanden ist. Der Exporter sendet Traces an den in application.yml angegebenen Endpunkt.
# application.yml
management:
tracing:
sampling:
probability: 1.0 # 100% sampling for dev, reduce in production
otlp:
tracing:
endpoint: http://localhost:4318/v1/traces
opentelemetry:
resource-attributes:
service.name: order-service
deployment.environment: stagingDie resource-attributes fügen jedem Span Metadaten hinzu. Backends wie Grafana Tempo und Jaeger nutzen diese Attribute, um Traces nach Service und Umgebung zu gruppieren. Das Setzen von sampling.probability auf 1.0 erfasst alle Anfragen während der Entwicklung, aber Produktionssysteme samplen typischerweise zwischen 1% und 10%, um Speicherkosten zu kontrollieren.
Benutzerdefinierte Observations mit Low- und High-Cardinality Tags erstellen
Observations unterstützen zwei Tag-Typen: Low Cardinality für Metriken (begrenzte Werte wie HTTP-Methoden oder Statuscodes) und High Cardinality für Traces (unbegrenzte Werte wie Benutzer-IDs oder Request-IDs).
@Service
public class PaymentService {
private final ObservationRegistry observationRegistry;
public PaymentService(ObservationRegistry observationRegistry) {
this.observationRegistry = observationRegistry;
}
public PaymentResult processPayment(PaymentRequest request) {
return Observation.createNotStarted("payment.process", observationRegistry)
.lowCardinalityKeyValue("payment.method", request.getMethod().name()) // enum: CARD, BANK_TRANSFER
.lowCardinalityKeyValue("currency", request.getCurrency()) // bounded: USD, EUR, GBP
.highCardinalityKeyValue("payment.id", request.getPaymentId()) // unique per request
.highCardinalityKeyValue("customer.id", request.getCustomerId()) // high cardinality
.observe(() -> executePayment(request));
}
private PaymentResult executePayment(PaymentRequest request) {
// Payment gateway call
return new PaymentResult(true, "TXN-" + UUID.randomUUID());
}
}Low-Cardinality-Tags erscheinen sowohl in Metriken als auch in Traces. High-Cardinality-Tags erscheinen nur in Traces, da Metriken mit unbegrenzten Dimensionen den Speicher sprengen. Diese Unterscheidung verhindert Prometheus-Kardinalitätsbomben, während Trace-Details reichhaltig bleiben.
Interviewer fragen oft, warum bestimmte Tags von Metriken ausgeschlossen werden sollten. Die Antwort bezieht sich auf Kardinalität: Ein Benutzer-ID-Tag auf einer Metrik erzeugt eine Zeitreihe pro Benutzer, potenziell Millionen von Zeitreihen. Monitoring-Backends haben mit hoher Kardinalität Probleme, was zu Speichererschöpfung und langsamen Abfragen führt. Traces handhaben hohe Kardinalität durch Sampling, was sie zum richtigen Ort für anfragespezifische Identifier macht.
Bereit für deine Spring Boot-Interviews?
Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.
Trace-Kontext über asynchrone Grenzen propagieren
Distributed Tracing erfordert Kontext-Propagation. HTTP-Header tragen Trace-IDs zwischen Services, aber asynchrone Operationen wie @Async-Methoden oder CompletableFuture-Ketten können den Kontext verlieren, wenn sie nicht konfiguriert sind.
Spring Boot 3.4 bietet automatische Propagation für Reactive Streams und @Async-Methoden, wenn konfiguriert:
# application.yml
spring:
reactor:
context-propagation: auto
task:
execution:
propagate-context: trueFür benutzerdefinierte TaskExecutor-Beans werden diese mit ContextPropagatingTaskDecorator umwickelt:
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(50);
executor.setTaskDecorator(new ContextPropagatingTaskDecorator());
executor.initialize();
return executor;
}
}Der Decorator kopiert die aktuelle Observation und den Trace-Kontext in den asynchronen Thread. Ohne ihn haben Spans, die in asynchronen Tasks gestartet werden, keinen Parent, was den Trace-Baum unterbricht.
Verwendung von @Observed und @NewSpan Annotationen
Spring Boot 3.4 unterstützt deklarative Observability durch Annotationen. Die Annotation-Verarbeitung wird durch Hinzufügen des AspectJ-Weavers aktiviert:
<!-- pom.xml -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency># application.yml
management:
observations:
annotations:
enabled: true@Service
public class InventoryService {
@Observed(name = "inventory.check", contextualName = "checkStock")
public StockLevel checkStock(String productId) {
// Database query
return new StockLevel(productId, 42);
}
@NewSpan("inventory.reserve") // Creates a child span under the current trace
public ReservationResult reserveStock(String productId, int quantity) {
// Update inventory
return new ReservationResult(true, "RES-" + System.currentTimeMillis());
}
}@Observed erstellt sowohl eine Metrik (Timer) als auch einen Span. @NewSpan erstellt nur einen Span, nützlich wenn die Operation bereits anderswo Metriken hat. Beide Annotationen handhaben automatisch Exception-Recording und Span-Status.
Auto-instrumentierte Komponenten in Spring Boot 3.4
Spring Boot 3.4 auto-instrumentiert mehrere Komponenten ohne Code-Änderungen:
| Komponente | Observation-Name | Was erfasst wird |
|---|---|---|
| Spring MVC | http.server.requests | Request-Pfad, Methode, Status, Exception |
| WebClient | http.client.requests | Ausgehende HTTP-Aufrufe |
| RestClient | http.client.requests | Ausgehende HTTP-Aufrufe (Spring 6.1+) |
| Spring Kafka | spring.kafka.listener | Consumer-Gruppe, Topic, Partition |
| Spring Data JPA | spring.data.repository | Repository-Methode, Abfragezeit |
| Scheduled Tasks | spring.scheduling | Task-Name, Ausführungszeit |
Die Spring Boot Actuator Dokumentation listet alle auto-instrumentierten Komponenten auf. Third-Party-Libraries wie Datasource Micrometer fügen JDBC-Query-Tracing hinzu.
Observations filtern zur Rauschreduzierung
Health-Checks, Readiness-Probes und statische Ressourcen erzeugen Rauschen in Traces. Diese werden mit Predicates herausgefiltert:
@Configuration
public class ObservationFilterConfig {
@Bean
public ObservationPredicate noHealthChecks() {
return (name, context) -> !name.equals("http.server.requests")
|| !isHealthEndpoint(context);
}
private boolean isHealthEndpoint(Observation.Context context) {
if (context instanceof ServerRequestObservationContext http) {
String path = http.getCarrier().getRequestURI();
return path.startsWith("/actuator/health") || path.startsWith("/actuator/ready");
}
return false;
}
}Alternativ können Observations nach Namen in der Konfiguration deaktiviert werden:
# application.yml
management:
observations:
enable:
spring.security: false # Disable Spring Security observations
http.server.requests.actuator: false # Custom predicate nameSampling reduziert den Prozentsatz der gesammelten Traces über alle Endpunkte hinweg. Filtering entfernt spezifische Endpunkte vollständig. Filtering wird für Endpunkte verwendet, die niemals diagnostischen Wert liefern (Health-Checks, Metrics-Scraping). Sampling wird zur Kostenkontrolle verwendet, während repräsentative Daten erhalten bleiben.
Logs mit Trace-IDs korrelieren
Spring Boot 3.4 fügt automatisch Trace- und Span-IDs zum MDC (Mapped Diagnostic Context) hinzu, wenn Micrometer Tracing aktiv ist. Logback und Log4j2 können diese IDs in die Log-Ausgabe einbeziehen:
<!-- logback-spring.xml -->
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - traceId=%X{traceId} spanId=%X{spanId} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</configuration>Mit diesem Pattern enthält jede Log-Zeile die Trace-ID. Die Suche nach Logs anhand der Trace-ID liefert alle Nachrichten einer einzelnen Anfrage über alle Services hinweg und korreliert Logs mit Spans in Jaeger oder Tempo.
Häufige Interview-Fragen zur Spring Boot Observability
Interviewer bewerten sowohl konzeptuelles Verständnis als auch praktische Erfahrung mit Observability. Diese Fragen erscheinen häufig in Senior-Backend-Positionen.
F: Was ist der Unterschied zwischen Micrometer Tracing und OpenTelemetry?
Micrometer Tracing ist eine herstellerneutrale API für Distributed Tracing, ähnlich wie Micrometer Metriken abstrahiert. OpenTelemetry ist eine spezifische Implementierung und ein Protokoll. Spring Boot verwendet Micrometer Tracing als API und verbindet sich über micrometer-tracing-bridge-otel mit OpenTelemetry für den Export. Diese Schichtung ermöglicht es Anwendungen, Backends ohne Code-Änderungen zu wechseln.
F: Warum empfiehlt Spring die Observation API anstelle direkter OpenTelemetry-Instrumentierung?
Die Observation API bietet einen einzigen Instrumentierungspunkt, der sowohl Metriken als auch Traces erzeugt. Direkte OpenTelemetry-Aufrufe erzeugen nur Traces. Die Verwendung von Observation.observe() generiert eine Timer-Metrik und einen Span aus demselben Code, was Duplikation reduziert und konsistente Benennung gewährleistet.
F: Wie debuggt man einen Trace, der eine Lücke zwischen Spans zeigt?
Lücken weisen auf fehlende Instrumentierung oder unterbrochene Kontext-Propagation hin. Es sollte geprüft werden, ob der Code asynchrone Operationen ohne ContextPropagatingTaskDecorator verwendet. Zu verifizieren ist, dass HTTP-Clients instrumentiert sind (WebClient, RestClient oder ein manuell gewrappter RestTemplate). Bei Message-Queues muss bestätigt werden, dass Trace-Header durch Message-Properties propagiert werden.
F: Was passiert, wenn ein High-Cardinality-Tag zu einer Metrik hinzugefügt wird?
Jeder eindeutige Tag-Wert erzeugt eine neue Zeitreihe. Ein Benutzer-ID-Tag mit Millionen von Benutzern erzeugt Millionen von Zeitreihen, was den Speicher in Prometheus oder anderen TSDB-Backends erschöpft. Die Lösung ist die Verwendung von highCardinalityKeyValue() anstelle von lowCardinalityKeyValue(), was das Tag nur zu Traces hinzufügt, wo hohe Kardinalität erwartet wird.
Eine Distributed-Tracing-Pipeline mit Docker Compose aufbauen
Ein lokaler Observability-Stack hilft bei der Validierung der Instrumentierung vor dem Deployment in Produktion. Dieses Beispiel verwendet den OpenTelemetry Collector und Jaeger:
# docker-compose.yml
services:
otel-collector:
image: otel/opentelemetry-collector-contrib:0.102.0
command: ["--config", "/etc/otel-collector-config.yml"]
volumes:
- ./otel-collector-config.yml:/etc/otel-collector-config.yml
ports:
- "4318:4318" # OTLP HTTP
- "4317:4317" # OTLP gRPC
jaeger:
image: jaegertracing/jaeger:2.3
ports:
- "16686:16686" # UI
environment:
- COLLECTOR_OTLP_ENABLED=true
app:
build: .
environment:
- MANAGEMENT_OTLP_TRACING_ENDPOINT=http://otel-collector:4318/v1/traces
depends_on:
- otel-collector# otel-collector-config.yml
receivers:
otlp:
protocols:
http:
endpoint: 0.0.0.0:4318
grpc:
endpoint: 0.0.0.0:4317
processors:
batch:
timeout: 1s
send_batch_size: 1024
exporters:
otlp/jaeger:
endpoint: jaeger:4317
tls:
insecure: true
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp/jaeger]Der Collector empfängt Spans von der Spring-Boot-Anwendung und leitet sie an Jaeger weiter. Diese Architektur ermöglicht das Hinzufügen von Exportern (Tempo, Zipkin, Cloud-Backends) ohne Änderung des Anwendungscodes.
Fang an zu üben!
Teste dein Wissen mit unseren Interview-Simulatoren und technischen Tests.
Wichtige Erkenntnisse zur Spring Boot Observability
- Die Observation API vereint Metriken und Tracing: Ein
Observation.observe()-Aufruf erzeugt sowohl eine Timer-Metrik als auch einen Span und eliminiert duale Instrumentierung. micrometer-tracing-bridge-otelundopentelemetry-exporter-otlphinzufügen, um OTLP-Export zu aktivieren. Spring Boot 3.4 konfiguriert automatisch den HTTP-Exporter mit dem Endpunkt ausmanagement.otlp.tracing.endpoint.lowCardinalityKeyValue()für Dimensionen verwenden, die in Metriken erscheinen (begrenzte Werte).highCardinalityKeyValue()für reine Trace-Daten verwenden (Benutzer-IDs, Request-IDs).- Kontext-Propagation für asynchronen Code mit
spring.task.execution.propagate-context=trueaktivieren und benutzerdefinierte Executors mitContextPropagatingTaskDecoratorumwickeln. - Laute Endpunkte wie
/actuator/healthmitObservationPredicate-Beans filtern, um Traces auf Geschäftsoperationen fokussiert zu halten. - Log-Patterns sollten
%X{traceId}enthalten, um Log-Zeilen mit Distributed Traces im Observability-Backend zu korrelieren. - Interview-Fragen zur Observability konzentrieren sich auf Kardinalität, Kontext-Propagation-Fehler und die Unterscheidung zwischen der Observation API und direkter OpenTelemetry-Nutzung.
Findest du den Bug in Spring Boot?
Ein echter Codeausschnitt, ein versteckter Bug, ein Versuch pro Tag. Zum Ausprobieren ohne Konto.

Geschrieben von
Anthony Fillion-MailletGründer von SharpSkill
Seit über 10 Jahren Fullstack-Entwickler. Er leitet SharpSkill und verantwortet alles, was hier erscheint.
Aktualisiert am 19. September 2026
Teilen
Verwandte Artikel

Spring Boot YAML vs Properties: Konfigurationsvergleich und Interview-Fragen 2026
Umfassender Vergleich zwischen YAML und Properties-Dateien in Spring Boot. Lernen Sie Syntax, Best Practices und häufige Interview-Fragen zur Externalisierung von Konfigurationen.

Strukturiertes Logging in Spring Boot 2026: JSON-Logs für Produktion mit Logback und OpenTelemetry
Vollständiger Leitfaden zu Spring Boot 4.x strukturiertem Logging. Native JSON-Unterstützung, OpenTelemetry Starter, MDC-Tracing und ELK-Stack-Integration für Produktions-Observability.

Spring Kafka: ereignisgesteuerte Architektur mit resilienten Consumern
Vollständiger Spring-Kafka-Leitfaden für ereignisgesteuerte Architekturen. Konfiguration, resiliente Consumer, Retry-Strategien, Dead Letter Queues und Produktionsmuster für verteilte Anwendungen.