Automate User and Order IDs in Spring Boot Logs with MDC and AOP
This guide shows how to automatically inject userId and orderId into Spring Boot log messages by defining log placeholders, using ThreadLocal, creating a custom @UserLog annotation, and applying a Spring AOP aspect that populates MDC, dramatically simplifying logging in e‑commerce systems.
1. Goal
Automatically fill userId and orderId in log statements without manually passing them each time.
2. Implementation Idea
Declare placeholders userId:%X{userId} orderId:%X{orderId} in the log pattern.
Store userId and orderId in a ThreadLocal variable at the entry point of each request.
Use a custom annotation together with Spring AOP to copy the ThreadLocal values into MDC before the method executes.
3. Configure Log Variables
Use %X{} to define custom placeholders in the logging configuration, for example:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info">
<Appenders>
<Console name="consoleAppender" target="SYSTEM_OUT">
<PatternLayout pattern="%d{DEFAULT} [%t] %-5p - userId:%X{userId} orderId:%X{orderId} %m%n%ex" charset="UTF-8"/>
</Console>
</Appenders>
<Loggers>
<!-- Root Logger -->
<AsyncRoot level="info" includeLocation="true">
<appender-ref ref="consoleAppender"/>
</AsyncRoot>
</Loggers>
</Configuration>4. Use MDC to Store Context
Put values into MDC so the logging framework can substitute them automatically:
MDC.put("userId", userId);
MDC.put("orderId", orderId);
log.warn("订单履约完成");Resulting log line:
2024-08-17 21:35:38,284 [main] WARN - userId:32894934895 orderId:8497587947594859232 订单履约完成Next, declare an annotation and an aspect to automate the MDC population.
5. Annotation + Spring AOP
5.1 Define Annotation
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLog {
String userId() default "";
String orderId() default "";
}5.2 Define Aspect
@Aspect
@Component
public class UserLogAspect {
@Pointcut("@annotation(UserLog) && execution(public * *(..))")
public void pointcut() {}
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
Object[] args = joinPoint.getArgs();
UserLog userLogAnnotation = method.getAnnotation(UserLog.class);
if (userLogAnnotation != null && args != null && args.length > 0) {
String userId = String.valueOf(PropertyUtils.getProperty(args[0], userLogAnnotation.userId()));
String orderId = String.valueOf(PropertyUtils.getProperty(args[0], userLogAnnotation.orderId()));
MDC.put("userId", userId);
MDC.put("orderId", orderId);
}
try {
return joinPoint.proceed();
} finally {
MDC.clear();
}
}
}5.3 Key Points
Retrieve the @UserLog annotation at runtime.
Use PropertyUtils.getProperty (from commons‑beanutils) to extract nested properties, e.g., info.userId.
Store extracted values in MDC and clear them after method execution.
6. Verify the Effect
6.1 Service Declaration
@Service
public class OrderService {
private static final Logger log = LoggerFactory.getLogger(OrderService.class);
@UserLog(userId = "userId", orderId = "orderId")
public void orderPerform(UserOrder order) {
log.warn("订单履约完成");
}
@Data
public static class UserOrder {
String userId;
String orderId;
}
}6.2 Test Case
@Test
public void testUserLog() {
OrderService.UserOrder order = new OrderService.UserOrder();
order.setUserId("32894934895");
order.setOrderId("8497587947594859232");
orderService.orderPerform(order);
}6.3 Log Output
7. Summary
Different business scenarios require different log details; for troubleshooting it is often useful to attach a unique identifier to each request. Using a custom @UserLog annotation together with AOP automatically injects these common parameters into the log, greatly improving productivity.
You can further extend this approach to automatically log method arguments, report metrics, and more.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
