Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To add a request or operation ID to selected Spring Boot log lines, use a Spring AOP advice to put the value in the logging framework’s MDC before the advised method runs, then restore or remove it in a finally block. Configure the active logging pattern separately to print the MDC key. If the value must cross executor threads or reactive operators, configure context propagation as well: MDC alone does not carry arbitrary values across those boundaries.

How AOP, MDC, and log formatting fit together

These are separate jobs. Spring AOP intercepts a method call that passes through a Spring proxy. Your advice can establish an MDC value around that call. The logging backend then decides whether to include that value in each log line. Adding a value to MDC does not, by itself, change the output format.

Spring Boot auto-configures Spring AOP when its requirements are present. Its default proxy type is CGLIB; set spring.aop.proxy-target-class=false to use JDK proxies instead. With AspectJ on the classpath, Boot enables AspectJ auto-proxying, so adding @EnableAspectJAutoProxy is unnecessary in that setup. See Spring Boot’s AOP reference and the Spring Framework AOP reference.

The example below is an implementation pattern, not a Spring-provided MDC aspect. It assumes a service method receives a request ID as an argument. If the ID originates at an HTTP boundary, obtain or create it there and pass it to the service, or use an appropriate request-level integration; a service-method pointcut does not automatically identify every incoming request.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Implement an aspect that owns the MDC value lifecycle

Mark the methods that should carry the context

A narrow pointcut is easier to reason about than advising every method. For example, define a runtime annotation for service operations whose first argument is the request ID:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface WithRequestId {
}

Set the value, proceed, and restore prior state

This aspect is illustrative Java code. It expects the annotated method’s first argument to be a non-null request ID string; adapt the lookup if your identifier comes from a request object or another source.

@Aspect
@Component
public class RequestIdMdcAspect {
    private static final String MDC_KEY = "requestId";

    @Around("@annotation(WithRequestId)")
    public Object addRequestId(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();
        String requestId = args.length > 0 ? (String) args[0] : null;
        if (requestId == null || requestId.isBlank()) {
            return joinPoint.proceed();
        }

        String previous = MDC.get(MDC_KEY);
        MDC.put(MDC_KEY, requestId);
        try {
            return joinPoint.proceed();
        } finally {
            if (previous == null) {
                MDC.remove(MDC_KEY);
            } else {
                MDC.put(MDC_KEY, previous);
            }
        }
    }
}

Use the MDC class supplied by the logging facade configured in your application, commonly SLF4J’s org.slf4j.MDC. The finally block runs whether the method returns normally or throws. Restoring the previous value, rather than always removing the key, preserves an outer context when advised calls are nested and reuse the same key. This cleanup also prevents a pooled thread from retaining one operation’s value for unrelated later work.

In proxy-based Spring AOP, an internal self-invocation—one method on an object calling another method on that same object—does not pass through the Spring proxy. The advice therefore will not run for that internal call. Put the advised operation behind a Spring bean boundary or arrange calls to pass through the proxy. Pointcut, proxy type, and bean arrangement determine which calls are intercepted.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Keep MDC values suitable for logs: avoid secrets, credentials, and large or high-cardinality payloads. Use a stable identifier that helps correlate events without exposing sensitive data.

Print the MDC key in the active logging pattern

For Logback, include the key with %X{requestId} in the pattern. Spring Boot documents the related example logging.pattern.level=user:%X{user} %5p; configure the corresponding pattern property supported by your Boot version and logging setup. If the active pattern omits the key, the aspect can populate MDC correctly while the log output still shows no request ID. See Spring Boot’s logging reference for its logging and pattern guidance.

Choose between a custom request ID and tracing correlation

A custom MDC key and tracing correlation solve overlapping but different problems. Choose based on where the identifier comes from and what needs correlating.

Approach Identifier and scope Propagation and output
Custom AOP-managed key Application-defined value; limited to selected advised method calls. Your advice owns MDC setup and cleanup. The active logging pattern must print the key.
Micrometer Tracing correlation Trace and span identifiers associated with instrumented request or trace execution. Spring Boot adds a correlation ID based on traceId and spanId to logging by default when Micrometer Tracing is configured. Boot documents logging.pattern.correlation for customizing its output format.

When tracing is already configured, check whether its trace/span correlation meets the requirement before adding a second request identifier. The identifiers can serve distinct purposes, but avoid implying they are interchangeable or creating duplicate-looking fields without a clear reason. Spring Boot states: “Correlation IDs rely on context propagation.” See the tracing reference.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Propagate context across async and reactive boundaries

Common MDC implementations keep values in thread-local state. An aspect setting a custom value on one thread does not guarantee that an executor thread or a reactive operator sees it. Spring Boot’s observability propagation settings concern observation and tracing context; they do not automatically guarantee propagation of arbitrary MDC keys unless the application’s context propagation configuration captures those values.

Auto-configured @Async execution

For Boot’s auto-configured task execution used with @Async, Boot documents opting in to context propagation with spring.task.execution.propagate-context. Verify that the property is available and behaves as expected in the Spring Boot release used by the application. This is an observability-context option, not a blanket promise that any manually populated MDC entry is copied.

Custom task executors

For a custom AsyncTaskExecutor, register a ContextPropagatingTaskDecorator to wrap task execution and help restore logging or observation context on another thread. The decorator propagates context that is available through the configured context-propagation mechanisms; do not assume it captures a custom MDC key without the relevant accessor or configuration. Spring Framework also cautions that the decorator adds overhead and is not recommended for workloads made up of many very small tasks. See the ContextPropagatingTaskDecorator API documentation.

Reactor pipelines

For reactive applications, Boot documents the spring.reactor.context-propagation setting; auto enables automatic propagation of the current observation across reactive operators. Reactive context is distinct from simply setting MDC in a method that may run on a different thread. Check the property and behavior against the Boot version in use, and ensure that custom values are part of the context that is actually propagated. Boot’s observability reference describes these async and reactive options.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Practical checks when the ID is missing or wrong

  • No ID in any log line: confirm the active backend pattern includes the exact MDC key, and confirm the advised call passes through a Spring proxy.
  • ID disappears inside a method: check whether the work moved to another executor thread or reactive operator; configure the relevant propagation mechanism rather than relying on thread-local MDC.
  • A later request shows an earlier ID: ensure every path exits through cleanup, including exceptions, and restore or remove the key in finally.
  • Advice is skipped for an internal call: proxy-based AOP does not intercept self-invocation; route the call through a proxied bean boundary.
  • Trace IDs appear but the custom ID does not: tracing-managed correlation and a custom MDC key have separate sources and propagation requirements.

Because Boot properties and logging behavior can vary by release and backend, verify each setting against the version and logging implementation deployed by the application.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.