Spring Boot cookbook · Beginner
Add correlation IDs to Spring Boot logs
Trace every log line of a request (and its outbound calls) with one ID returned to clients.
Approach
If you use Micrometer Tracing, trace IDs are already in the MDC — return them in a response header. Otherwise add a filter that reads/creates X-Request-ID, puts it in the MDC, adds it to the response and clears it afterwards; propagate it on outbound calls with a RestClient interceptor.
Solution
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
class CorrelationIdFilter extends OncePerRequestFilter {
static final String HEADER = "X-Request-ID";
@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
throws ServletException, IOException {
String id = Optional.ofNullable(req.getHeader(HEADER)).filter(v -> v.matches("[A-Za-z0-9-]{8,64}"))
.orElseGet(() -> UUID.randomUUID().toString());
MDC.put("requestId", id);
res.setHeader(HEADER, id);
try {
chain.doFilter(req, res);
} finally {
MDC.remove("requestId");
}
}
}
@Bean
RestClientCustomizer propagateRequestId() {
return builder -> builder.requestInterceptor((request, body, execution) -> {
String id = MDC.get("requestId");
if (id != null) request.getHeaders().set(CorrelationIdFilter.HEADER, id);
return execution.execute(request, body);
});
}
logging:
pattern:
correlation: "[${spring.application.name:},%X{requestId:-}] "
structured:
format:
console: ecs # JSON logs include MDC values
Pitfalls
- Not clearing MDC (IDs leak into other requests on pooled threads).
- Losing MDC in
@Asynctasks — use aTaskDecoratorto copy it. - Accepting arbitrary incoming IDs without validation.
Variations
- Micrometer Tracing + OpenTelemetry gives trace/span IDs and cross-service propagation automatically.
Further reading: Spring Boot: Logging
Reference: https://docs.spring.io/spring-boot/reference/features/logging.html
More Spring Boot recipes
- Add retries and a circuit breaker with Resilience4j
- Authenticate machine clients with API keys in Spring Security
- Cache service results in Redis with @Cacheable
- Consume Kafka messages with retries and a dead-letter topic
- Handle concurrent updates with optimistic locking
- Implement soft delete with Hibernate
- Make POST endpoints idempotent in Spring Boot
- Map entities to DTOs with MapStruct