middle
Как настроить distributed tracing в Spring Boot?
Начиная с Spring Boot 3.x, для distributed tracing используется Micrometer Tracing (замена Spring Cloud Sleuth). Micrometer Tracing предоставляет фасад, а конкретная реализация (OTel или Brave/Zipkin) подключается как bridge.
Подключение зависимостей (pom.xml)
<dependencies>
<!-- Actuator (обязательно) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Micrometer Tracing — фасад -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing</artifactId>
</dependency>
<!-- Bridge к OpenTelemetry -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
<!-- OTLP exporter для отправки трейсов -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>
<!-- Для Prometheus метрик с exemplars -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
</dependencies>
Конфигурация application.yml
Пример
spring:
application:
name: order-service
management:
tracing:
sampling:
probability: 1.0 # 1.0 = 100% для dev, 0.1 = 10% для prod
propagation:
type: w3c # W3C Trace Context (по умолчанию)
otlp:
tracing:
endpoint: http://otel-collector:4318/v1/traces
metrics:
distribution:
percentiles-histogram:
http.server.requests: true
tags:
application: ${spring.application.name}
logging:
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] [%X{traceId}/%X{spanId}] %-5level %logger{36} - %msg%n"
Автоматическое распространение контекста
Spring Boot автоматически передаёт trace context через:
- RestTemplate / WebClient — HTTP-заголовки
traceparent - Spring Kafka — Kafka Record Headers
- Spring AMQP — RabbitMQ message headers
- Spring gRPC — gRPC metadata
Пример
@Service
public class OrderService {
private final RestClient restClient;
public OrderService(RestClient.Builder builder) {
this.restClient = builder
.baseUrl("http://inventory-service:8080")
.build();
}
public InventoryResponse checkStock(String productId) {
// traceId/spanId автоматически передаются в заголовках
return restClient.get()
.uri("/api/inventory/{id}", productId)
.retrieve()
.body(InventoryResponse.class);
}
}
Кастомные спаны с Observation API
Пример
@Service
public class OrderService {
private final ObservationRegistry observationRegistry;
public OrderService(ObservationRegistry observationRegistry) {
this.observationRegistry = observationRegistry;
}
public Order processOrder(OrderRequest request) {
return Observation.createNotStarted("order.processing", observationRegistry)
.lowCardinalityKeyValue("order.type", request.getType())
.highCardinalityKeyValue("order.id", request.getId())
.observe(() -> {
// Автоматически создаёт:
// 1. Span с именем "order.processing"
// 2. Timer-метрику "order.processing"
Order order = createOrder(request);
validateOrder(order);
return order;
});
}
}
Аннотация @Observed
Пример
@Configuration
public class ObservationConfig {
@Bean
public ObservedAspect observedAspect(ObservationRegistry registry) {
return new ObservedAspect(registry);
}
}
@Service
public class PaymentService {
@Observed(name = "payment.process",
contextualName = "processing-payment",
lowCardinalityKeyValues = {"payment.provider", "stripe"})
public PaymentResult processPayment(PaymentRequest request) {
// Автоматически создаётся span + метрика
return callPaymentProvider(request);
}
}
Логирование с traceId
Micrometer Tracing автоматически добавляет traceId и spanId в MDC (Mapped Diagnostic Context):
Пример
@Service
public class OrderService {
private static final Logger log = LoggerFactory.getLogger(OrderService.class);
public Order processOrder(OrderRequest request) {
// traceId/spanId автоматически добавляются через MDC
log.info("Processing order for customer: {}", request.getCustomerId());
// Лог: 2026-04-22 10:30:00 [main] [abc123/def456] INFO OrderService - Processing order...
return doProcess(request);
}
}
Конфигурация logback для JSON-формата
<!-- logback-spring.xml -->
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<includeMdcKeyName>traceId</includeMdcKeyName>
<includeMdcKeyName>spanId</includeMdcKeyName>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</configuration>
Результат:
{
"@timestamp": "2026-04-22T10:30:00.123Z",
"level": "INFO",
"logger_name": "com.example.OrderService",
"message": "Processing order for customer: 42",
"traceId": "abc123def456789",
"spanId": "def456789abc",
"service": "order-service"
}
Важное
- Micrometer Tracing — фасад, аналогичный SLF4J. Нужен bridge (
micrometer-tracing-bridge-otel) для конкретной реализации. - Observation API — единый механизм, создающий одновременно метрику и span. Используйте
@Observedвместо отдельных@Timed+ ручных спанов. - sampling.probability = 1.0 в dev/staging, 0.01-0.1 в production. В production используйте tail-based sampling на стороне OTel Collector.
- Spring Boot 3.x автоматически пропагирует контекст через стандартные HTTP-клиенты, Kafka, RabbitMQ.
Частые ошибки
- Забыть подключить bridge: без
micrometer-tracing-bridge-otelтрейсы не генерируются. - sampling.probability = 1.0 в production: 100% семплирование на высоконагруженном сервисе создаёт огромный overhead.
- Потеря контекста в
@Async: стандартныйTaskExecutorне передаёт trace context. ИспользуйтеContextPropagatingTaskDecorator. - Не добавить traceId в логи: без
%X{traceId}в log pattern невозможно связать логи с трейсами. - Путать Spring Cloud Sleuth и Micrometer Tracing: Sleuth устарел и не поддерживается в Spring Boot 3.x.
Правильная передача контекста в @Async
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
private final ObservationRegistry observationRegistry;
public AsyncConfig(ObservationRegistry observationRegistry) {
this.observationRegistry = observationRegistry;
}
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setTaskDecorator(new ContextPropagatingTaskDecorator());
executor.initialize();
return executor;
}
}
Как используется в 2026
- Micrometer Observation API — стандартный способ инструментирования в Spring-экосистеме.
- OTLP экспорт — нативная поддержка в Spring Boot через
management.otlp.tracingиmanagement.otlp.metrics. - Виртуальные потоки (Project Loom) — Micrometer Context Propagation корректно работает с virtual threads.
- Spring Boot 3.4+ — улучшенная поддержка OTel Logs, автоматическая корреляция логов с трейсами через OTLP.
- Testcontainers + OTel — интеграционные тесты с реальным OTel Collector для проверки трейсинга.
На собеседовании: обязательно упомяните переход от Spring Cloud Sleuth к Micrometer Tracing в Spring Boot 3.x. Покажите знание Observation API как единого механизма для метрик и трейсов. Ключевая ошибка на собеседовании — не знать про необходимость bridge и
ContextPropagatingTaskDecoratorдля@Async.