Obserwowalność w Spring Boot 2026: OpenTelemetry, Distributed Tracing i pytania rekrutacyjne
Kompleksowy przewodnik po obserwowalności Spring Boot z OpenTelemetry i Micrometer Tracing. Konfiguracja distributed tracing, Observation API, eksport OTLP oraz przygotowanie do rozmów kwalifikacyjnych.

Obserwowalność w Spring Boot łączy logowanie, metryki i distributed tracing w jeden spójny system, który pokazuje przepływ żądań przez mikroserwisy. Od wersji Spring Boot 3, framework przyjął Micrometer Tracing (zastępując Spring Cloud Sleuth) oraz wprowadził Observation API, dostarczając pojedynczy punkt instrumentacji emitujący zarówno metryki, jak i trace'y.
Spring Boot zaleca używanie Observation.observe() zamiast bezpośredniego wywoływania OpenTelemetry. Jedno wywołanie instrumentacji produkuje metryki przez Micrometer oraz trace'y przez most OpenTelemetry, redukując duplikację kodu i zapewniając spójne nazewnictwo tagów między sygnałami.
Jak Observation API łączy Micrometer z OpenTelemetry
Observation API działa jako fasada nad metrykami i tracingiem. Gdy kod wywołuje Observation.createNotStarted(), Spring Boot przekazuje obserwację do zarejestrowanych handlerów: MeterObservationHandler dla metryk Micrometer oraz TracingObservationHandler dla distributed tracing. Ta architektura oznacza, że instrumentacja raz wykonana eksportuje dane wszędzie.
Zależność mostkowa micrometer-tracing-bridge-otel łączy Micrometer Tracing z SDK OpenTelemetry. Trace'y przepływają przez SdkTracerProvider OpenTelemetry i są eksportowane przez OTLP do backendów takich jak Jaeger, Tempo lub dowolny kolektor kompatybilny z OpenTelemetry.
@Configuration
public class ObservabilityConfig {
@Bean
public ObservationRegistryCustomizer<ObservationRegistry> addLowCardinalityTags() {
return registry -> registry.observationConfig()
.observationHandler(new ObservationTextPublisher()); // Loguje obserwacje do konsoli
}
}Powyższa konfiguracja rejestruje ObservationHandler, który loguje każdą obserwację. W środowisku produkcyjnym automatycznie skonfigurowane handlery wysyłają dane do rejestrów Micrometer i eksporterów OpenTelemetry bez dodatkowego kodu.
Wymagane zależności dla Spring Boot 3.4 Tracing
Spring Boot 3.4 wymaga jawnych zależności dla distributed tracing. spring-boot-starter-actuator dostarcza Observation API, ale tracing wymaga mostu OpenTelemetry i eksportera.
<!-- 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>Artefakt micrometer-tracing-bridge-otel mostuje Micrometer Tracing do API OpenTelemetry. opentelemetry-exporter-otlp wysyła spany do kolektorów używając protokołu OTLP przez HTTP lub gRPC. Spring Boot zarządza wyrównaniem wersji przez swoje zarządzanie zależnościami.
Konfiguracja eksportu OTLP do Jaegera lub Tempo
Spring Boot automatycznie konfiguruje OtlpHttpSpanExporter, gdy zależność OTLP jest obecna. Eksporter wysyła trace'y do endpointu określonego w application.yml.
# application.yml
management:
tracing:
sampling:
probability: 1.0 # 100% samplowania dla dev, zmniejsz w produkcji
otlp:
tracing:
endpoint: http://localhost:4318/v1/traces
opentelemetry:
resource-attributes:
service.name: order-service
deployment.environment: stagingresource-attributes dołączają metadane do każdego spana. Backendy takie jak Grafana Tempo i Jaeger używają tych atrybutów do grupowania trace'ów według serwisu i środowiska. Ustawienie sampling.probability na 1.0 przechwytuje wszystkie żądania podczas developmentu, ale systemy produkcyjne zazwyczaj samplują między 1% a 10%, aby kontrolować koszty storage'u.
Tworzenie własnych obserwacji z tagami o niskiej i wysokiej kardynalności
Obserwacje wspierają dwa typy tagów: niskiej kardynalności dla metryk (ograniczone wartości jak metody HTTP lub kody statusu) oraz wysokiej kardynalności dla trace'ów (nieograniczone wartości jak ID użytkownika lub ID żądania).
@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()) // ograniczone: USD, EUR, GBP
.highCardinalityKeyValue("payment.id", request.getPaymentId()) // unikalne per żądanie
.highCardinalityKeyValue("customer.id", request.getCustomerId()) // wysoka kardynalność
.observe(() -> executePayment(request));
}
private PaymentResult executePayment(PaymentRequest request) {
// Wywołanie bramki płatności
return new PaymentResult(true, "TXN-" + UUID.randomUUID());
}
}Tagi niskiej kardynalności pojawiają się zarówno w metrykach, jak i trace'ach. Tagi wysokiej kardynalności pojawiają się tylko w trace'ach, ponieważ metryki z nieograniczonymi wymiarami eksplodują storage. Ta dystynkcja zapobiega bombom kardynalności w Prometheusie, jednocześnie zachowując bogate szczegóły trace'ów.
Rekruterzy często pytają, dlaczego niektóre tagi powinny być wykluczone z metryk. Odpowiedź dotyczy kardynalności: tag ID użytkownika na metryce tworzy jedną serię czasową na użytkownika, potencjalnie miliony serii. Backendy monitoringu mają problemy z wysoką kardynalnością, prowadząc do wyczerpania pamięci i wolnych zapytań. Trace'y obsługują wysoką kardynalność przez samplowanie, czyniąc je właściwym miejscem dla identyfikatorów specyficznych dla żądania.
Gotowy na rozmowy o Spring Boot?
Ćwicz z naszymi interaktywnymi symulatorami, flashcards i testami technicznymi.
Propagacja kontekstu trace'a przez granice asynchroniczne
Distributed tracing wymaga propagacji kontekstu. Nagłówki HTTP przenoszą ID trace'ów między serwisami, ale operacje asynchroniczne jak metody @Async lub łańcuchy CompletableFuture mogą utracić kontekst, jeśli nie są skonfigurowane.
Spring Boot 3.4 zapewnia automatyczną propagację dla strumieni reaktywnych i metod @Async przy odpowiedniej konfiguracji:
# application.yml
spring:
reactor:
context-propagation: auto
task:
execution:
propagate-context: trueDla własnych beanów TaskExecutor należy opakować je w ContextPropagatingTaskDecorator:
@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;
}
}Dekorator kopiuje bieżącą Observation i kontekst trace'a do wątku asynchronicznego. Bez niego spany rozpoczęte w zadaniach asynchronicznych nie mają rodzica, przerywając drzewo trace'ów.
Użycie adnotacji @Observed i @NewSpan
Spring Boot 3.4 wspiera deklaratywną obserwowalność przez adnotacje. Przetwarzanie adnotacji wymaga dodania AspectJ weaver:
<!-- 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) {
// Zapytanie do bazy danych
return new StockLevel(productId, 42);
}
@NewSpan("inventory.reserve") // Tworzy span potomny pod bieżącym trace'em
public ReservationResult reserveStock(String productId, int quantity) {
// Aktualizacja magazynu
return new ReservationResult(true, "RES-" + System.currentTimeMillis());
}
}@Observed tworzy zarówno metrykę (timer), jak i span. @NewSpan tworzy tylko span, przydatne gdy operacja ma już metryki gdzie indziej. Obie adnotacje automatycznie obsługują rejestrowanie wyjątków i status spana.
Automatycznie instrumentowane komponenty w Spring Boot 3.4
Spring Boot 3.4 automatycznie instrumentuje kilka komponentów bez zmian w kodzie:
| Komponent | Nazwa obserwacji | Co rejestruje |
|---|---|---|
| Spring MVC | http.server.requests | Ścieżka żądania, metoda, status, wyjątek |
| WebClient | http.client.requests | Wychodzące wywołania HTTP |
| RestClient | http.client.requests | Wychodzące wywołania HTTP (Spring 6.1+) |
| Spring Kafka | spring.kafka.listener | Grupa konsumentów, topic, partycja |
| Spring Data JPA | spring.data.repository | Metoda repozytorium, czas zapytania |
| Scheduled Tasks | spring.scheduling | Nazwa zadania, czas wykonania |
Dokumentacja Spring Boot Actuator wymienia wszystkie automatycznie instrumentowane komponenty. Biblioteki zewnętrzne jak Datasource Micrometer dodają tracing zapytań JDBC.
Filtrowanie obserwacji w celu redukcji szumu
Health checki, readiness probes i zasoby statyczne generują szum w trace'ach. Można je odfiltrować używając predykatów:
@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;
}
}Alternatywnie można wyłączyć obserwacje po nazwie w konfiguracji:
# application.yml
management:
observations:
enable:
spring.security: false # Wyłącz obserwacje Spring Security
http.server.requests.actuator: false # Własna nazwa predykatuSamplowanie redukuje procent trace'ów zbieranych ze wszystkich endpointów. Filtrowanie usuwa określone endpointy całkowicie. Filtrowania należy używać dla endpointów, które nigdy nie dostarczają wartości diagnostycznej (health checki, scraping metryk). Samplowania należy używać do kontrolowania kosztów przy zachowaniu reprezentatywnych danych.
Korelacja logów z ID trace'ów
Spring Boot 3.4 automatycznie dodaje ID trace'a i spana do MDC (Mapped Diagnostic Context), gdy Micrometer Tracing jest aktywny. Logback i Log4j2 mogą zawierać te ID w wyjściu logów:
<!-- 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>Z tym wzorcem każda linia logu zawiera ID trace'a. Wyszukiwanie logów po ID trace'a zwraca wszystkie wiadomości z pojedynczego żądania ze wszystkich serwisów, korelując logi ze spanami w Jaegerze lub Tempo.
Częste pytania rekrutacyjne dotyczące obserwowalności Spring Boot
Rekruterzy oceniają zarówno rozumienie koncepcyjne, jak i praktyczne doświadczenie z obserwowalnością. Te pytania pojawiają się często na stanowiskach senior backend.
P: Jaka jest różnica między Micrometer Tracing a OpenTelemetry?
Micrometer Tracing to vendor-neutral API dla distributed tracing, podobnie jak Micrometer abstrahuje metryki. OpenTelemetry to konkretna implementacja i protokół. Spring Boot używa Micrometer Tracing jako API i mostuje do OpenTelemetry w celu eksportu przez micrometer-tracing-bridge-otel. Ta warstwa pozwala aplikacjom zmieniać backendy bez zmian w kodzie.
P: Dlaczego Spring zaleca Observation API zamiast bezpośredniej instrumentacji OpenTelemetry?
Observation API zapewnia pojedynczy punkt instrumentacji emitujący zarówno metryki, jak i trace'y. Bezpośrednie wywołania OpenTelemetry produkują tylko trace'y. Użycie Observation.observe() generuje metrykę timer i span z tego samego kodu, redukując duplikację i zapewniając spójne nazewnictwo.
P: Jak debugować trace, który pokazuje lukę między spanami?
Luki wskazują na brakującą instrumentację lub przerwanie propagacji kontekstu. Należy sprawdzić, czy kod używa operacji asynchronicznych bez ContextPropagatingTaskDecorator. Zweryfikować, czy klienty HTTP są instrumentowane (WebClient, RestClient lub ręcznie opakowany RestTemplate). Dla kolejek wiadomości potwierdzić, że nagłówki trace'ów propagują przez właściwości wiadomości.
P: Co się dzieje, gdy dodasz tag o wysokiej kardynalności do metryki?
Każda unikalna wartość tagu tworzy nową serię czasową. Tag ID użytkownika z milionami użytkowników tworzy miliony serii, wyczerpując pamięć w Prometheusie lub innych backendach TSDB. Rozwiązaniem jest użycie highCardinalityKeyValue() zamiast lowCardinalityKeyValue(), które dodaje tag tylko do trace'ów, gdzie wysoka kardynalność jest oczekiwana.
Budowanie pipeline'u distributed tracing z Docker Compose
Lokalny stack obserwowalności pomaga zwalidować instrumentację przed wdrożeniem do produkcji. Ten przykład używa OpenTelemetry Collector i Jaegera:
# 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]Kolektor odbiera spany z aplikacji Spring Boot i przekazuje je do Jaegera. Ta architektura pozwala dodawać eksportery (Tempo, Zipkin, backendy chmurowe) bez zmiany kodu aplikacji.
Zacznij ćwiczyć!
Sprawdź swoją wiedzę z naszymi symulatorami rozmów i testami technicznymi.
Kluczowe wnioski dotyczące obserwowalności Spring Boot
- Observation API unifikuje metryki i tracing: jedno wywołanie
Observation.observe()produkuje zarówno metrykę timer, jak i span, eliminując podwójną instrumentację. - Dodanie
micrometer-tracing-bridge-oteliopentelemetry-exporter-otlpwłącza eksport OTLP. Spring Boot 3.4 automatycznie konfiguruje eksporter HTTP z endpointem zmanagement.otlp.tracing.endpoint. lowCardinalityKeyValue()należy używać dla wymiarów pojawiających się w metrykach (ograniczone wartości).highCardinalityKeyValue()należy używać dla danych tylko w trace'ach (ID użytkowników, ID żądań).- Propagację kontekstu dla kodu asynchronicznego włącza
spring.task.execution.propagate-context=trueoraz opakowywanie własnych executorów wContextPropagatingTaskDecorator. - Filtrowanie hałaśliwych endpointów jak
/actuator/healthprzy użyciu beanówObservationPredicateutrzymuje trace'y skoncentrowane na operacjach biznesowych. - Wzorce logów powinny zawierać
%X{traceId}, aby korelować linie logów z distributed trace'ami w backendzie obserwowalności. - Pytania rekrutacyjne o obserwowalność skupiają się na kardynalności, błędach propagacji kontekstu oraz różnicy między Observation API a bezpośrednim użyciem OpenTelemetry.
Znajdziesz błąd w Spring Boot?
Prawdziwy fragment kodu, ukryty błąd, jedna próba dziennie. Bez konta, żeby spróbować.

Autor:
Anthony Fillion-MailletZałożyciel SharpSkill
Programista fullstack od ponad 10 lat. Prowadzi SharpSkill i odpowiada za wszystko, co się tu ukazuje.
Zaktualizowano 19 września 2026
Tagi
Udostępnij
Powiązane artykuły

Spring Boot Actuator: Monitorowanie Produkcyjne z Micrometer i Prometheus
Kompletny przewodnik po Spring Boot Actuator do monitorowania produkcji. Konfiguracja Micrometer, metryki Prometheus, własne endpointy i alerty.

Spring Boot YAML vs Properties: Porównanie Konfiguracji i Pytania Rekrutacyjne 2026
Dogłębne porównanie formatów konfiguracji YAML i Properties w Spring Boot. Omówienie składni, zarządzania profilami, struktur danych oraz najczęstszych pytań rekrutacyjnych.

Strukturalne logowanie Spring Boot 2026: logi JSON produkcyjne z Logback i OpenTelemetry
Kompletny przewodnik po strukturalnym logowaniu Spring Boot 4.x. Natywne wsparcie JSON, starter OpenTelemetry, MDC tracing i integracja z ELK Stack dla obserwowalności produkcyjnej.