每日技术干货,第一时间送达!
log.warn("user:{}, orderId:{} 订单提单成功",userId, orderId);
log.warn("user:{}, orderId:{} 订单支付成功",userId, orderId);
log.warn("user:{}, orderId:{} 订单收到履约请求",userId, orderId);
log.warn("user:{}, orderId:{} 订单履约成功",userId, orderId);
-
日志模板中声明占位符 userId,orderId -
在业务入口将userId放入到线程ThreadLocal本地变量中。 -
使用SpringAop+ 注解 自动将第二步的用户信息放到线程上下文
userId:%X{userId} orderId:%X{orderId},定义了userId和orderId两个占位符。
<?xml version="1.0" encoding="UTF-8"?>
<Configurationstatus="info">
<Appenders>
<Consolename="consoleAppender"target="SYSTEM_OUT">
<PatternLayoutpattern="%d{DEFAULT} [%t] %-5p - userId:%X{userId} orderId:%X{orderId} %m%n%ex"charset="UTF-8"/>
</Console>
</Appenders>
<Loggers>
<!-- Root Logger -->
<AsyncRootlevel="info"includeLocation="true">
<appender-refref="consoleAppender"/>
</AsyncRoot>
</Loggers>
</Configuration>
MDC.put("userId", userId);
MDC.put("orderId", orderId);
log.warn("订单履约完成");
当使用log.warn("订单履约完成") 方式打印日志时,代码中会自动包含userId和 订单Id。
2024-08-17 21:35:38,284 [main] WARN - userId:32894934895 orderId:8497587947594859232 订单履约完成
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public@interface UserLog {
String userId()default "";
String orderId()default "";
}
@UserLog(userId = "userId", orderId = "orderId")
publicvoidorderPerform(UserOrder order){
log.warn("订单履约完成");
}
@Data
publicstaticclassUserOrder{
String userId;
String orderId;
}
@Aspect
@Component
publicclassUserLogAspect{
@Pointcut("@annotation(UserLog) && execution(public * *(..))")
publicvoidpointcut(){
}
@Around(value = "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) {
//使用工具类获取userId。
String userId = String.valueOf(PropertyUtils.getProperty(args[0], userLogAnnotation.userId()));
String orderId = String.valueOf(PropertyUtils.getProperty(args[0], userLogAnnotation.orderId()));
// 放到MDC中
MDC.put("userId", userId);
MDC.put("orderId", orderId);
}
try {
Object response = joinPoint.proceed();
return response;
} catch (Exception e) {
throw e;
} finally {
//清理MDC
MDC.clear();
}
}
}
UserLog userLogAnnotation = method.getAnnotation(UserLog.class);
PropertyUtils.getProperty(args[0], userLogAnnotation.userId())
要注意 PropertyUtils 是commons-beanutils提供的工具类,可以指定属性的路径,自动提取属性值。如果存在多层关系,可以使用,级联取属性值。例如 info.userId,则从对象的info属性中取userId属性。
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>
MDC.put("userId", userId);
MDC.clear();
@Service
publicclassOrderService{
publicstaticfinal Logger log = LoggerFactory.getLogger(OrderService.class);
@UserLog(userId = "userId", orderId = "orderId")
publicvoidorderPerform(UserOrder order){
log.warn("订单履约完成");
}
@Data
publicstaticclassUserOrder{
String userId;
String orderId;
}
}
@Test
publicvoidtestUserLog(){
OrderService.UserOrder order = new OrderService.UserOrder();
order.setUserId("32894934895");
order.setOrderId("8497587947594859232");
orderService.orderPerform(order);
}
往期推荐
Redis与本地缓存组合使用...
老司机总结的12条SQL优化方案(非常实用)
中毒太深!离开Spring我居然连最基本的接口都不会写了。。。
开源项目|Java开发身份证号码识别系统
SpringBoot + minio实现分片上传、秒传、续传
开源项目 | 一个注解让你的项目减少30%SQL代码量

