In this post, I’ll show you how to implement correlation ids in a Spring Boot application, how to propagate them to downstream services (optionally, with FeignClient), and how to log them using Logback.

What Are Correlation IDs?#

In modern microservices architectures, a single user request often traverses multiple services before a response is returned. When something goes wrong, or when you want to trace the flow of a request, it can be challenging to follow its journey across service boundaries. This is where correlation IDs come in.

A correlation ID is a unique identifier attached to each incoming request. As the request flows through your system—across services, threads, and logs—the correlation id is passed along, making it easy to trace the entire lifecycle of a request. This is invaluable for debugging, monitoring, and understanding the behavior of distributed systems.

Implementing Correlation IDs in Spring Boot#

The core idea is to generate or extract a correlation ID for each incoming HTTP request and make it available throughout the request’s lifecycle. This is typically done using a servlet filter.

Key points from the code:

public class CorrelationIdFilter extends OncePerRequestFilter {

    public static final String CORRELATION_ID = "correlationId";
    public static final String X_CORRELATION_ID = "X-Correlation-Id";

    @Override
    protected void doFilterInternal(@NonNull HttpServletRequest request,
                                    @NonNull HttpServletResponse response,
                                    @NonNull FilterChain filterChain) 
                                    throws ServletException, IOException {
        String correlationId = request.getHeader(X_CORRELATION_ID);

        if (correlationId == null || correlationId.isEmpty()) {
            correlationId = UUID.randomUUID().toString();
        }

        MDC.put(CORRELATION_ID, correlationId);
        try {
            filterChain.doFilter(request, response);
        } finally {
            MDC.clear();
        }
    }
}
  • The filter checks for an incoming X-Correlation-Id header.
  • If it’s missing, it generates a new UUID.
  • The correlation ID is stored in the Mapped Diagnostic Context (MDC), which makes it available to the logging framework and any downstream code during the request.
  • The correlation ID is removed from the MDC after the request is processed to avoid leaking it between requests.

Logging Correlation IDs with Logback#

To make correlation IDs visible in your logs, you need to update your logging configuration to include the MDC value.

Logback configuration:

<pattern> ... | %blue(%12(correlationId: %8mdc{correlationId})) ... </pattern>
  • The pattern includes mdc{correlationId} in every log line, so the correlation ID is always visible.
  • This makes it easy to filter and trace logs for a specific request.

Example log output:

2025-07-17 | 20:00:00.275 | http-nio-8080-exec-1 | DEBUG | c.f.c.c.TodoApiClient     | correlationId: 60a08789-0a99-47bb-9465-45fac275e198 | [TodoApiClient#getTodos] <--- END HTTP (24311-byte body)
2025-07-17 | 20:00:00.309 | http-nio-8080-exec-1 | INFO  | c.f.c.service.TodoService | correlationId: 60a08789-0a99-47bb-9465-45fac275e198 | Todos fetched successfully!

Notice how the correlation ID appears in the log lines, making it easy to trace the request.

Propagating Correlation IDs with Feign#

If your service calls other services (e.g., via FeignClient), you should propagate the correlation ID in the outgoing HTTP headers. This ensures the correlation ID follows the request across service boundaries.

Feign client configuration:

@Bean
RequestInterceptor requestInterceptor() {
    return template -> {
        String correlationId = MDC.get(CORRELATION_ID);
        template.header(X_CORRELATION_ID, correlationId);
    };
}
  • The RequestInterceptor retrieves the correlation ID from the MDC.
  • It adds the correlation ID to the X-Correlation-Id header of every outgoing Feign request.

Tracing a Request#

Let’s see how a request is traced through the system:

  1. A request arrives at your application.
  2. The CorrelationIdFilter extracts or generates a correlation ID and puts it in the MDC.
  3. All logs for this request include the correlation ID.
  4. If the service calls another service via Feign, the correlation ID is added to the outgoing request header.
  5. Downstream services can extract the correlation ID and continue the trace.

Sample log flow from application:

2025-07-17 | 20:16:01.562 | http-nio-8080-exec-1 | DEBUG | c.f.c.c.TodoApiClient     | correlationId: ead1b850-3330-4653-9109-c223f752e449 | [TodoApiClient#getTodos] ---> GET https://jsonplaceholder.typicode.com/todos HTTP/1.1
2025-07-17 | 20:16:01.562 | http-nio-8080-exec-1 | DEBUG | c.f.c.c.TodoApiClient     | correlationId: ead1b850-3330-4653-9109-c223f752e449 | [TodoApiClient#getTodos] X-Correlation-Id: ead1b850-3330-4653-9109-c223f752e449
...
...
...
2025-07-17 | 20:16:01.769 | http-nio-8080-exec-1 | DEBUG | c.f.c.c.TodoApiClient     | correlationId: ead1b850-3330-4653-9109-c223f752e449 | [TodoApiClient#getTodos] x-ratelimit-remaining: 999
2025-07-17 | 20:16:01.769 | http-nio-8080-exec-1 | DEBUG | c.f.c.c.TodoApiClient     | correlationId: ead1b850-3330-4653-9109-c223f752e449 | [TodoApiClient#getTodos] x-ratelimit-reset: 1752563994
2025-07-17 | 20:16:01.788 | http-nio-8080-exec-1 | DEBUG | c.f.c.c.TodoApiClient     | correlationId: ead1b850-3330-4653-9109-c223f752e449 | [TodoApiClient#getTodos] <--- END HTTP (24311-byte body)
2025-07-17 | 20:16:01.797 | http-nio-8080-exec-1 | INFO  | c.f.c.service.TodoService | correlationId: ead1b850-3330-4653-9109-c223f752e449 | Todos fetched successfully!

Conclusion#

Correlation IDs are a simple but powerful tool for tracing requests in distributed systems. By implementing a filter to manage correlation IDs, updating your logging configuration, and (optionally) propagating the ID with Feign, you can make your Spring Boot applications much easier to debug and monitor.

Key takeaways:

  • Always include a correlation ID in your logs.
  • Propagate the correlation ID to downstream services.
  • Use MDC to manage correlation IDs in a thread-safe way.

With these practices, you’ll be well-equipped to trace and debug requests across your microservices landscape!

The source code for this post is available in my GitHub repository. Feel free to explore and contribute.

Thank you for reading! I hope this post helps you effectively implement and log correlation IDs in your applications. If you have any questions or suggestions, feel free to share them in the comments. 🚀