编程 一种高效的日志打印工具,通过使用SpringAOP和MDC,将用户ID和订单ID自动填充到日志中,简化了日志记录的过程

2024-11-19 03:30:24 +0800 CST views 570

一种高效的日志打印工具,通过使用SpringAOP和MDC,将用户ID和订单ID自动填充到日志中,简化了日志记录的过程

1. 目标

在电商交易系统的日志中,为了更方便地记录信息,每次都需要手动设置 userIdorderId,这显得非常繁琐。因此,目标是通过优化,实现日志打印时自动填充这些常用字段,而无需每次手动指定。

2. 实现思路

  • 在日志模板中声明占位符 userIdorderId
  • 在业务入口处将 userId 放入到线程的 ThreadLocal 本地变量中。
  • 通过 Spring AOP + 注解,自动将用户信息放入到线程上下文中,进而填充日志。

3. 配置日志变量,读取上下文变量

使用 %X{} 占位符来自定义日志格式。例如:

<?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>
        <AsyncRoot level="info" includeLocation="true">
            <appender-ref ref="consoleAppender"/>
        </AsyncRoot>
    </Loggers>
</Configuration>

4. 基于 MDC 将订单和用户信息放到线程的上下文 Map

MDC(Mapped Diagnostic Context)允许将信息放入线程上下文中,日志框架会自动将这些信息应用到日志格式中。

使用 MDC 类的 put() 方法可以将 userIdorderId 注入到日志中,例如:

MDC.put("userId", userId);
MDC.put("orderId", orderId);
log.warn("订单履约完成");

效果如下:

2024-08-17 21:35:38,284 [main] WARN  - userId:32894934895 orderId:8497587947594859232 订单履约完成

5. 注解 + SpringAop,自动将 UserId 放到 MDC

通过注解和切面的方式,自动将 UserId 注入到 MDC 中。在方法执行前,注解会自动获取入参中的 userIdorderId

5.1 定义注解

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLog {
    String userId() default "";
    String orderId() default "";
}

使用方法:

@UserLog(userId = "userId", orderId = "orderId")
public void orderPerform(UserOrder order) {
   log.warn("订单履约完成");
}

5.2 定义切面

@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 关键代码解读

  • 获取 UserLog 注解

    UserLog userLogAnnotation = method.getAnnotation(UserLog.class);
    
  • 使用 PropertyUtils.getProperty 获取 userId

    PropertyUtils.getProperty(args[0], userLogAnnotation.userId());
    
  • 使用 MDC.put() 设置和清除变量

    MDC.put("userId", userId);
    MDC.clear();
    

6. 验证使用效果

6.1 声明业务 Service

@Service
public class OrderService {
   public 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
public void testUserLog() {
   OrderService.UserOrder order = new OrderService.UserOrder();
   order.setUserId("32894934895");
   order.setOrderId("8497587947594859232");
   orderService.orderPerform(order);
}

6.3 日志效果

打印的日志会自动包含 userIdorderId

2024-08-17 21:35:38,284 [main] WARN  - userId:32894934895 orderId:8497587947594859232 订单履约完成

7. 总结

使用 UserLog 注解和 AOP,可以自动将 userIdorderId 等默认参数放入日志中,简化了业务日志的打印,大幅提升了生产力。通过进一步扩展,可以自动打印出入参日志或自动上报监控打点等功能。

复制全文 生成海报 日志 电商 开发工具 Spring框架 AOP

推荐文章

Mysql允许外网访问详细流程
2024-11-17 05:03:26 +0800 CST
为什么大厂也无法避免写出Bug?
2024-11-19 10:03:23 +0800 CST
CSS 中的 `scrollbar-width` 属性
2024-11-19 01:32:55 +0800 CST
PHP中获取某个月份的天数
2024-11-18 11:28:47 +0800 CST
js函数常见的写法以及调用方法
2024-11-19 08:55:17 +0800 CST
Rust 与 sqlx:数据库迁移实战指南
2024-11-19 02:38:49 +0800 CST
windon安装beego框架记录
2024-11-19 09:55:33 +0800 CST
使用Vue 3和Axios进行API数据交互
2024-11-18 22:31:21 +0800 CST
Golang 中你应该知道的 noCopy 策略
2024-11-19 05:40:53 +0800 CST
Node.js中接入微信支付
2024-11-19 06:28:31 +0800 CST
js一键生成随机颜色:randomColor
2024-11-18 10:13:44 +0800 CST
一个有趣的进度条
2024-11-19 09:56:04 +0800 CST
Vue3中的虚拟滚动有哪些改进?
2024-11-18 23:58:18 +0800 CST
Go 开发中的热加载指南
2024-11-18 23:01:27 +0800 CST
JavaScript数组 splice
2024-11-18 20:46:19 +0800 CST
16.6k+ 开源精准 IP 地址库
2024-11-17 23:14:40 +0800 CST
CSS 特效与资源推荐
2024-11-19 00:43:31 +0800 CST
如何在 Linux 系统上安装字体
2025-02-27 09:23:03 +0800 CST
Gin 框架的中间件 代码压缩
2024-11-19 08:23:48 +0800 CST
25个实用的JavaScript单行代码片段
2024-11-18 04:59:49 +0800 CST
Plyr.js 播放器介绍
2024-11-18 12:39:35 +0800 CST
程序员茄子在线接单