Observabilidade no Spring Boot em 2026: OpenTelemetry, Tracing Distribuído e Perguntas de Entrevista
Guia completo sobre observabilidade no Spring Boot com OpenTelemetry e tracing distribuído. Configuração OTLP, Observation API, propagação de contexto e perguntas técnicas para entrevistas backend.

A observabilidade no Spring Boot combina logging, métricas e tracing distribuído em um sistema unificado que revela como as requisições fluem através dos microsserviços. Desde o Spring Boot 3, o framework adotou o Micrometer Tracing (substituindo o Spring Cloud Sleuth) e introduziu a Observation API, que fornece um único ponto de instrumentação que emite tanto métricas quanto traces.
O Spring Boot recomenda usar Observation.observe() em vez de chamar o OpenTelemetry diretamente. Uma única chamada de instrumentação produz métricas via Micrometer e traces via bridge OpenTelemetry, reduzindo duplicação de código e garantindo nomenclatura consistente de tags entre os sinais.
Como a Observation API Conecta Micrometer e OpenTelemetry
A Observation API atua como uma fachada sobre métricas e tracing. Quando o código chama Observation.createNotStarted(), o Spring Boot roteia a observação para os handlers registrados: MeterObservationHandler para métricas do Micrometer e TracingObservationHandler para traces distribuídos. Essa arquitetura significa que instrumentar uma vez exporta para todos os lugares.
A dependência bridge micrometer-tracing-bridge-otel conecta o Micrometer Tracing ao SDK do OpenTelemetry. Os traces fluem através do SdkTracerProvider do OpenTelemetry e exportam via OTLP para backends como Jaeger, Tempo, ou qualquer coletor compatível com OpenTelemetry.
@Configuration
public class ObservabilityConfig {
@Bean
public ObservationRegistryCustomizer<ObservationRegistry> addLowCardinalityTags() {
return registry -> registry.observationConfig()
.observationHandler(new ObservationTextPublisher()); // Logs observations to console
}
}A configuração acima registra um ObservationHandler que registra cada observação em logs. Em produção, os handlers auto-configurados enviam dados para os registros do Micrometer e exportadores do OpenTelemetry sem código adicional.
Dependências Necessárias para Tracing no Spring Boot 3.4
O Spring Boot 3.4 requer dependências explícitas para tracing distribuído. O spring-boot-starter-actuator fornece a Observation API, mas o tracing precisa do bridge OpenTelemetry e um exportador.
<!-- 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>O artefato micrometer-tracing-bridge-otel faz a ponte entre o Micrometer Tracing e a API do OpenTelemetry. O opentelemetry-exporter-otlp envia spans para os coletores usando o protocolo OTLP sobre HTTP ou gRPC. O Spring Boot gerencia o alinhamento de versões através de sua gestão de dependências.
Configuração da Exportação OTLP para Jaeger ou Tempo
O Spring Boot auto-configura um OtlpHttpSpanExporter quando a dependência OTLP está presente. O exportador envia traces para o endpoint especificado no 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: stagingOs resource-attributes anexam metadados a cada span. Backends como Grafana Tempo e Jaeger usam esses atributos para agrupar traces por serviço e ambiente. Definir sampling.probability como 1.0 captura todas as requisições durante desenvolvimento, mas sistemas de produção tipicamente amostram entre 1% e 10% para controlar custos de armazenamento.
Criar Observations Personalizadas com Tags de Cardinalidade Baixa e Alta
As observations suportam dois tipos de tags: cardinalidade baixa para métricas (valores limitados como métodos HTTP ou códigos de status) e cardinalidade alta para traces (valores ilimitados como IDs de usuário ou IDs de requisição).
@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());
}
}Tags de cardinalidade baixa aparecem tanto em métricas quanto em traces. Tags de cardinalidade alta aparecem apenas em traces porque métricas com dimensões ilimitadas explodem o armazenamento. Essa distinção previne as bombas de cardinalidade do Prometheus enquanto mantém os traces ricos em detalhes.
Entrevistadores frequentemente perguntam por que algumas tags devem ser excluídas das métricas. A resposta envolve cardinalidade: uma tag de ID de usuário em uma métrica cria uma série temporal por usuário, potencialmente milhões de séries. Backends de monitoramento têm dificuldade com alta cardinalidade, levando ao esgotamento de memória e consultas lentas. Traces lidam com alta cardinalidade através de amostragem, tornando-os o lugar correto para identificadores específicos de requisição.
Pronto para mandar bem nas entrevistas de Spring Boot?
Pratique com nossos simuladores interativos, flashcards e testes tecnicos.
Propagação do Contexto de Trace Através de Fronteiras Assíncronas
O tracing distribuído requer propagação de contexto. Headers HTTP carregam IDs de trace entre serviços, mas operações assíncronas como métodos @Async ou cadeias de CompletableFuture podem perder contexto se não configuradas corretamente.
O Spring Boot 3.4 fornece propagação automática para streams reativos e métodos @Async quando configurado:
# application.yml
spring:
reactor:
context-propagation: auto
task:
execution:
propagate-context: truePara beans TaskExecutor personalizados, envolvê-los com 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;
}
}O decorator copia a Observation atual e o contexto de trace para a thread assíncrona. Sem ele, spans iniciados em tarefas async não têm pai, quebrando a árvore de traces.
Uso das Anotações @Observed e @NewSpan
O Spring Boot 3.4 suporta observabilidade declarativa através de anotações. Habilitar o processamento de anotações adicionando o weaver do 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 cria tanto uma métrica (timer) quanto um span. @NewSpan cria apenas um span, útil quando a operação já tem métricas em outro lugar. Ambas as anotações lidam automaticamente com o registro de exceções e o status do span.
Componentes Auto-Instrumentados no Spring Boot 3.4
O Spring Boot 3.4 auto-instrumenta vários componentes sem mudanças de código:
| Componente | Nome da Observation | O Que Captura |
|---|---|---|
| Spring MVC | http.server.requests | Caminho da requisição, método, status, exceção |
| WebClient | http.client.requests | Chamadas HTTP de saída |
| RestClient | http.client.requests | Chamadas HTTP de saída (Spring 6.1+) |
| Spring Kafka | spring.kafka.listener | Grupo de consumidores, tópico, partição |
| Spring Data JPA | spring.data.repository | Método do repositório, tempo de consulta |
| Tarefas Agendadas | spring.scheduling | Nome da tarefa, tempo de execução |
A documentação do Spring Boot Actuator lista todos os componentes auto-instrumentados. Bibliotecas de terceiros como Datasource Micrometer adicionam tracing de consultas JDBC.
Filtrar Observations para Reduzir Ruído
Health checks, probes de disponibilidade e recursos estáticos geram ruído nos traces. Filtrá-los usando predicados:
@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;
}
}Alternativamente, desabilitar observations por nome na configuração:
# application.yml
management:
observations:
enable:
spring.security: false # Disable Spring Security observations
http.server.requests.actuator: false # Custom predicate nameA amostragem reduz a porcentagem de traces coletados em todos os endpoints. A filtragem remove endpoints específicos completamente. Usar filtragem para endpoints que nunca fornecem valor diagnóstico (health checks, scraping de métricas). Usar amostragem para controlar custos enquanto preserva dados representativos.
Correlação de Logs com IDs de Trace
O Spring Boot 3.4 automaticamente adiciona IDs de trace e span ao MDC (Mapped Diagnostic Context) quando o Micrometer Tracing está ativo. Logback e Log4j2 podem incluir esses IDs na saída dos logs:
<!-- 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>Com esse padrão, cada linha de log inclui o ID de trace. Buscar logs por ID de trace retorna todas as mensagens de uma única requisição através de todos os serviços, correlacionando logs com spans no Jaeger ou Tempo.
Perguntas de Entrevista Comuns sobre Observabilidade no Spring Boot
Entrevistadores avaliam tanto a compreensão conceitual quanto a experiência prática com observabilidade. Essas perguntas aparecem frequentemente para cargos backend sênior.
P: Qual é a diferença entre Micrometer Tracing e OpenTelemetry?
Micrometer Tracing é uma API agnóstica de fornecedor para tracing distribuído, similar a como o Micrometer abstrai métricas. OpenTelemetry é uma implementação e protocolo específicos. O Spring Boot usa Micrometer Tracing como API e faz bridge para OpenTelemetry para exportação via micrometer-tracing-bridge-otel. Essa camada permite que aplicações troquem de backend sem mudanças de código.
P: Por que o Spring recomenda a Observation API em vez da instrumentação direta do OpenTelemetry?
A Observation API fornece um único ponto de instrumentação que emite tanto métricas quanto traces. Chamadas diretas ao OpenTelemetry produzem apenas traces. Usar Observation.observe() gera uma métrica timer e um span a partir do mesmo código, reduzindo duplicação e garantindo nomenclatura consistente.
P: Como depurar um trace que mostra uma lacuna entre spans?
Lacunas indicam instrumentação ausente ou propagação de contexto quebrada. Verificar se o código usa operações async sem ContextPropagatingTaskDecorator. Verificar se os clientes HTTP estão instrumentados (WebClient, RestClient, ou um RestTemplate envolvido manualmente). Para filas de mensagens, confirmar que os headers de trace se propagam através das propriedades da mensagem.
P: O que acontece se adicionar uma tag de alta cardinalidade a uma métrica?
Cada valor único de tag cria uma nova série temporal. Uma tag de ID de usuário com milhões de usuários cria milhões de séries, esgotando a memória no Prometheus ou outros backends TSDB. A solução é usar highCardinalityKeyValue() em vez de lowCardinalityKeyValue(), o que adiciona a tag apenas aos traces onde alta cardinalidade é esperada.
Construir um Pipeline de Tracing Distribuído com Docker Compose
Uma stack de observabilidade local ajuda a validar a instrumentação antes de implantar em produção. Este exemplo usa o 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]O coletor recebe spans da aplicação Spring Boot e os encaminha para o Jaeger. Essa arquitetura permite adicionar exportadores (Tempo, Zipkin, backends cloud) sem alterar o código da aplicação.
Comece a praticar!
Teste seus conhecimentos com nossos simuladores de entrevista e testes tecnicos.
Pontos-Chave para Observabilidade no Spring Boot
- A Observation API unifica métricas e tracing: uma única chamada
Observation.observe()produz tanto uma métrica timer quanto um span, eliminando instrumentação dupla. - Adicionar
micrometer-tracing-bridge-oteleopentelemetry-exporter-otlppara habilitar exportação OTLP. O Spring Boot 3.4 auto-configura o exportador HTTP com o endpoint demanagement.otlp.tracing.endpoint. - Usar
lowCardinalityKeyValue()para dimensões que aparecem em métricas (valores limitados). UsarhighCardinalityKeyValue()para dados apenas em traces (IDs de usuário, IDs de requisição). - Habilitar propagação de contexto para código async com
spring.task.execution.propagate-context=truee envolver executors personalizados comContextPropagatingTaskDecorator. - Filtrar endpoints ruidosos como
/actuator/healthusando beansObservationPredicatepara manter os traces focados em operações de negócio. - Os padrões de log devem incluir
%X{traceId}para correlacionar linhas de log com traces distribuídos no backend de observabilidade. - As perguntas de entrevista sobre observabilidade focam em cardinalidade, falhas de propagação de contexto e a distinção entre a Observation API e o uso direto do OpenTelemetry.
Você saberia encontrar o bug em Spring Boot?
Um trecho real, um bug escondido, uma tentativa por dia. Sem conta para testar.

Escrito por
Anthony Fillion-MailletFundador da SharpSkill
Desenvolvedor fullstack há mais de 10 anos. Dirige a SharpSkill e responde por tudo o que é publicado aqui.
Atualizado em 19 de setembro de 2026
Tags
Compartilhar
Artigos relacionados

Spring Boot Actuator: Monitoramento em Produção com Micrometer e Prometheus
Guia completo do Spring Boot Actuator para monitoramento em produção. Configuração Micrometer, métricas Prometheus, endpoints customizados e alertas.

Logs estruturados no Spring Boot em 2026: JSON para produção com Logback e OpenTelemetry
Guia completo de logs estruturados no Spring Boot 4.x. Suporte JSON nativo, starter OpenTelemetry, tracing MDC e integração ELK Stack para observabilidade em produção.

Spring Boot YAML vs Properties: Comparacao de Configuracao e Perguntas de Entrevista 2026
Comparacao detalhada entre YAML e Properties no Spring Boot. Sintaxe, gerenciamento de perfis, estruturas de dados e perguntas de entrevista tecnica.