Spring Boot Observability nel 2026: OpenTelemetry, Distributed Tracing e Domande per Colloqui
Padroneggiare l'observability di Spring Boot con OpenTelemetry e Micrometer Tracing. Configurare l'export OTLP, utilizzare la Observation API e prepararsi ai colloqui.

L'observability di Spring Boot combina logging, metriche e distributed tracing in un sistema unificato che rivela come le richieste fluiscono attraverso i microservizi. A partire da Spring Boot 3, il framework ha adottato Micrometer Tracing (sostituendo Spring Cloud Sleuth) e ha introdotto la Observation API, che fornisce un singolo punto di strumentazione che emette sia metriche che trace.
Spring Boot raccomanda l'utilizzo di Observation.observe() piuttosto che chiamare OpenTelemetry direttamente. Una singola chiamata di strumentazione produce metriche via Micrometer e trace via il bridge OpenTelemetry, riducendo la duplicazione del codice e garantendo una nomenclatura dei tag consistente tra tutti i segnali.
Come la Observation API Collega Micrometer e OpenTelemetry
La Observation API agisce come una facciata su metriche e tracing. Quando il codice chiama Observation.createNotStarted(), Spring Boot instrada l'observation agli handler registrati: MeterObservationHandler per le metriche Micrometer e TracingObservationHandler per i distributed trace. Questa architettura significa strumentare una volta, esportare ovunque.
La dipendenza bridge micrometer-tracing-bridge-otel connette Micrometer Tracing all'SDK di OpenTelemetry. I trace fluiscono attraverso SdkTracerProvider di OpenTelemetry ed esportano via OTLP verso backend come Jaeger, Tempo o qualsiasi collector compatibile con OpenTelemetry.
@Configuration
public class ObservabilityConfig {
@Bean
public ObservationRegistryCustomizer<ObservationRegistry> addLowCardinalityTags() {
return registry -> registry.observationConfig()
.observationHandler(new ObservationTextPublisher()); // Logs observations to console
}
}La configurazione sopra registra un ObservationHandler che logga ogni observation. In produzione, gli handler configurati automaticamente inviano i dati ai registry Micrometer e agli esportatori OpenTelemetry senza codice aggiuntivo.
Dipendenze Richieste per Spring Boot 3.4 Tracing
Spring Boot 3.4 richiede dipendenze esplicite per il distributed tracing. Lo spring-boot-starter-actuator fornisce la Observation API, ma il tracing necessita del bridge OpenTelemetry e di un esportatore.
<!-- 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>L'artefatto micrometer-tracing-bridge-otel collega Micrometer Tracing all'API di OpenTelemetry. L'opentelemetry-exporter-otlp invia gli span ai collector usando il protocollo OTLP via HTTP o gRPC. Spring Boot gestisce l'allineamento delle versioni attraverso il suo dependency management.
Configurare l'Export OTLP verso Jaeger o Tempo
Spring Boot configura automaticamente un OtlpHttpSpanExporter quando la dipendenza OTLP è presente. L'esportatore invia i trace all'endpoint specificato in application.yml.
# 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: stagingI resource-attributes allegano metadati a ogni span. Backend come Grafana Tempo e Jaeger usano questi attributi per raggruppare i trace per servizio e ambiente. Impostare sampling.probability a 1.0 cattura tutte le richieste durante lo sviluppo, ma i sistemi di produzione tipicamente campionano tra l'1% e il 10% per controllare i costi di storage.
Creare Observation Personalizzate con Tag Low e High Cardinality
Le observation supportano due tipi di tag: low cardinality per le metriche (valori limitati come metodi HTTP o codici di stato) e high cardinality per i trace (valori illimitati come ID utente o ID richiesta).
@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());
}
}I tag low cardinality appaiono sia nelle metriche che nei trace. I tag high cardinality appaiono solo nei trace perché le metriche con dimensioni illimitate fanno esplodere lo storage. Questa distinzione previene le bombe di cardinalità in Prometheus mantenendo ricchi i dettagli dei trace.
Gli intervistatori spesso chiedono perché alcuni tag dovrebbero essere esclusi dalle metriche. La risposta riguarda la cardinalità: un tag ID utente su una metrica crea una time series per utente, potenzialmente milioni di series. I backend di monitoring faticano con l'alta cardinalità, portando a esaurimento della memoria e query lente. I trace gestiscono l'alta cardinalità attraverso il sampling, rendendoli il posto corretto per identificatori specifici della richiesta.
Pronto a superare i tuoi colloqui su Spring Boot?
Pratica con i nostri simulatori interattivi, flashcards e test tecnici.
Propagare il Contesto Trace Attraverso Confini Asincroni
Il distributed tracing richiede la propagazione del contesto. Gli header HTTP trasportano gli ID trace tra i servizi, ma le operazioni asincrone come i metodi @Async o le catene di CompletableFuture possono perdere il contesto se non configurate.
Spring Boot 3.4 fornisce propagazione automatica per i reactive stream e i metodi @Async quando configurato:
# application.yml
spring:
reactor:
context-propagation: auto
task:
execution:
propagate-context: truePer i bean TaskExecutor personalizzati, vanno wrappati con 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;
}
}Il decorator copia l'Observation corrente e il contesto trace nel thread asincrono. Senza di esso, gli span avviati in task asincroni non hanno parent, rompendo l'albero dei trace.
Usare le Annotazioni @Observed e @NewSpan
Spring Boot 3.4 supporta l'observability dichiarativa attraverso le annotazioni. L'elaborazione delle annotazioni viene abilitata aggiungendo il weaver AspectJ:
<!-- 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 crea sia una metrica (timer) che uno span. @NewSpan crea solo uno span, utile quando l'operazione ha già metriche altrove. Entrambe le annotazioni gestiscono automaticamente la registrazione delle eccezioni e lo stato dello span.
Componenti Auto-Strumentati in Spring Boot 3.4
Spring Boot 3.4 auto-strumenta diversi componenti senza modifiche al codice:
| Componente | Nome Observation | Cosa Cattura |
|---|---|---|
| Spring MVC | http.server.requests | Percorso richiesta, metodo, stato, eccezione |
| WebClient | http.client.requests | Chiamate HTTP in uscita |
| RestClient | http.client.requests | Chiamate HTTP in uscita (Spring 6.1+) |
| Spring Kafka | spring.kafka.listener | Gruppo consumer, topic, partizione |
| Spring Data JPA | spring.data.repository | Metodo repository, tempo query |
| Scheduled Tasks | spring.scheduling | Nome task, tempo di esecuzione |
La documentazione di Spring Boot Actuator elenca tutti i componenti auto-strumentati. Librerie di terze parti come Datasource Micrometer aggiungono il tracing delle query JDBC.
Filtrare le Observation per Ridurre il Rumore
Gli health check, le readiness probe e le risorse statiche generano rumore nei trace. Vanno filtrati usando dei predicate:
@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;
}
}In alternativa, le observation possono essere disabilitate per nome nella configurazione:
# application.yml
management:
observations:
enable:
spring.security: false # Disable Spring Security observations
http.server.requests.actuator: false # Custom predicate nameIl sampling riduce la percentuale di trace raccolti su tutti gli endpoint. Il filtering rimuove endpoint specifici completamente. Il filtering viene usato per endpoint che non forniscono mai valore diagnostico (health check, scraping delle metriche). Il sampling viene usato per controllare i costi preservando dati rappresentativi.
Correlare i Log con gli ID Trace
Spring Boot 3.4 aggiunge automaticamente trace e span ID all'MDC (Mapped Diagnostic Context) quando Micrometer Tracing è attivo. Logback e Log4j2 possono includere questi ID nell'output dei log:
<!-- 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>Con questo pattern, ogni riga di log include il trace ID. Cercare i log per trace ID restituisce tutti i messaggi di una singola richiesta attraverso tutti i servizi, correlando i log con gli span in Jaeger o Tempo.
Domande Comuni da Colloquio sulla Spring Boot Observability
Gli intervistatori valutano sia la comprensione concettuale che l'esperienza pratica con l'observability. Queste domande appaiono frequentemente nei ruoli backend senior.
D: Qual è la differenza tra Micrometer Tracing e OpenTelemetry?
Micrometer Tracing è un'API vendor-neutral per il distributed tracing, simile a come Micrometer astrae le metriche. OpenTelemetry è un'implementazione specifica e un protocollo. Spring Boot usa Micrometer Tracing come API e si collega a OpenTelemetry per l'export via micrometer-tracing-bridge-otel. Questa stratificazione permette alle applicazioni di cambiare backend senza modifiche al codice.
D: Perché Spring raccomanda la Observation API rispetto alla strumentazione diretta di OpenTelemetry?
La Observation API fornisce un singolo punto di strumentazione che emette sia metriche che trace. Le chiamate dirette a OpenTelemetry producono solo trace. Usare Observation.observe() genera una metrica timer e uno span dallo stesso codice, riducendo la duplicazione e garantendo una nomenclatura consistente.
D: Come si fa il debug di un trace che mostra un gap tra gli span?
I gap indicano strumentazione mancante o propagazione del contesto interrotta. Bisogna verificare se il codice usa operazioni asincrone senza ContextPropagatingTaskDecorator. Verificare che i client HTTP siano strumentati (WebClient, RestClient, o un RestTemplate wrappato manualmente). Per le code di messaggi, confermare che gli header trace si propaghino attraverso le proprietà dei messaggi.
D: Cosa succede se si aggiunge un tag high cardinality a una metrica?
Ogni valore tag unico crea una nuova time series. Un tag ID utente con milioni di utenti crea milioni di series, esaurendo la memoria in Prometheus o altri backend TSDB. La soluzione è usare highCardinalityKeyValue() invece di lowCardinalityKeyValue(), che aggiunge il tag solo ai trace dove l'alta cardinalità è prevista.
Costruire una Pipeline di Distributed Tracing con Docker Compose
Uno stack di observability locale aiuta a validare la strumentazione prima del deploy in produzione. Questo esempio usa l'OpenTelemetry Collector e 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]Il collector riceve gli span dall'applicazione Spring Boot e li inoltra a Jaeger. Questa architettura permette di aggiungere esportatori (Tempo, Zipkin, backend cloud) senza modificare il codice dell'applicazione.
Inizia a praticare!
Metti alla prova le tue conoscenze con i nostri simulatori di colloquio e test tecnici.
Punti Chiave per la Spring Boot Observability
- La Observation API unifica metriche e tracing: una chiamata
Observation.observe()produce sia una metrica timer che uno span, eliminando la doppia strumentazione. - Aggiungere
micrometer-tracing-bridge-oteleopentelemetry-exporter-otlpper abilitare l'export OTLP. Spring Boot 3.4 configura automaticamente l'esportatore HTTP con l'endpoint damanagement.otlp.tracing.endpoint. - Usare
lowCardinalityKeyValue()per le dimensioni che appaiono nelle metriche (valori limitati). UsarehighCardinalityKeyValue()per i dati solo dei trace (ID utente, ID richiesta). - Abilitare la propagazione del contesto per il codice asincrono con
spring.task.execution.propagate-context=truee wrappare gli executor personalizzati conContextPropagatingTaskDecorator. - Filtrare gli endpoint rumorosi come
/actuator/healthusando beanObservationPredicateper mantenere i trace focalizzati sulle operazioni di business. - I pattern dei log dovrebbero includere
%X{traceId}per correlare le righe di log con i distributed trace nel backend di observability. - Le domande da colloquio sull'observability si concentrano sulla cardinalità, i fallimenti della propagazione del contesto e la distinzione tra la Observation API e l'uso diretto di OpenTelemetry.
Sapresti trovare il bug in Spring Boot?
Uno snippet reale, un bug nascosto, un tentativo al giorno. Senza account per provare.

Scritto da
Anthony Fillion-MailletFondatore di SharpSkill
Sviluppatore fullstack da oltre 10 anni. Guida SharpSkill e risponde di tutto ciò che vi viene pubblicato.
Aggiornato il 19 settembre 2026
Condividi
Articoli correlati

Spring Boot YAML vs Properties: Confronto Configurazioni e Domande da Colloquio 2026
Confronto completo tra YAML e Properties in Spring Boot. Sintassi, best practice, gestione profili e domande frequenti nei colloqui tecnici sulla configurazione esternalizzata.

Logging strutturato in Spring Boot 2026: log JSON per la produzione con Logback e OpenTelemetry
Guida completa al logging strutturato in Spring Boot 4.x. Supporto JSON nativo, OpenTelemetry starter, MDC tracing e integrazione ELK Stack per observability in produzione.

Spring Kafka: architettura event-driven con consumer resilienti
Guida completa a Spring Kafka per architetture event-driven. Configurazione, consumer resilienti, politiche di retry, dead letter queue e pattern di produzione per applicazioni distribuite.