前言:在服务端排查日志时,想查看一次接口请求的完整日志,而不受其他其他日志干扰,可以在log4j中添加request维度的logId来实现过滤。
目录
1、如何添加logId
2、子线程如何获取logId
log4j提供了很多常用的API功能接口,其中包括ThreadContext。顾名思义这是一个日志上下文,那我们猜想在日志入口加入的数据下文可以使用,也即在请求入口加入的数据,请求处理过程中,日志线程可以使用。ThreadContext本质是一个map或stack。官网这样说:
The Stack and the Map are managed per thread and are based on ThreadLocal by default.
其实就是基于ThreadLoacl实现,感兴趣的同学可以自行看源码拓展学习。大家可以思考一下又了这个“日志线程上下文”我们可以做些什么以实现每次请求的日志识别?很简单当然是加标识!
@Component
public class LogInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 日志id
ThreadContext.put("logId", UuidUtil.getTimeBasedUuid().toString());
return true;
}
}
配置spring的拦截器,在ThreadContext中加入logId。然后呢再在log4j2的配置的pattern中加入%X{logId}
%d{yyyy-MM-dd HH:mm:ss,SSS} %X{logId} %5p %c{1}:%L - %m%n
添加测试接口
@GetMapping("testLogId")
public String testLogId() {
log.info("test");
return "ok";
}
输出结果,标黄为logId:
2022-10-19 15:47:50,959 550b4c61-4f82-11ed-b02a-5ec48148ecef INFO HealthController:16 - test
好像大功告成,可是等等上面提到ThreadContext实现基于ThreadLocal,当前输出没问题,那子线程呢?测试试一下!
@GetMapping("testLogId")
public String testLogId() {
log.info("test");
new Thread(() -> {
log.info("sub thead!");
}).start();
return "ok";
}
结果应该在意料之中:
2022-10-19 15:53:56,969 2f3361c1-4f83-11ed-9d3d-5ec48148ecef INFO HealthController:16 - test
2022-10-19 15:53:56,970 INFO HealthController:18 - sub thead!
查资料得知log4j提供了很多系统参数
其中包括 log4j2.isThreadContextMapInheritable
log4j2.isThreadContextMapInheritable
(isThreadContextMapInheritable)LOG4J_IS_THREAD_CONTEXT_MAP_INHERITABLE false
isThreadContextMapInheritable顾名思义ThreadContext是否可“遗传”。配置为true即可,有四种配置的方式:
Source | Priority | Description |
---|---|---|
Spring Boot Properties | -100 | This property source is enabled only if the Java application uses Spring Boot and the log4j-spring module is present. It resolves properties using a Spring Environment. |
System Properties | 0 | All properties can be set using normal system property patterns. |
Environment Variables | 100 | Environment variables are all prefixed with LOG4J_ , are in all caps, and words are all separated by underscores. |
log4j2.component.properties file |
200 | Including this file on the classpath can be used as an alternative to providing properties as system properties. |
我测试了其中的两种System Properties,Environment Variables。
//system 加在JAVA_OPTS 系统变量里
-Dlog4j2.isThreadContextMapInheritable=true
//environment 加在代码里
static {
System.setProperty("LOG4J_IS_THREAD_CONTEXT_MAP_INHERITABLE", "true");
}
结果如下:
2022-10-19 16:13:17,490 e2edbfb1-4f85-11ed-b003-5ec48148ecef INFO HealthController:16 - test
2022-10-19 16:13:17,490 e2edbfb1-4f85-11ed-b003-5ec48148ecef INFO HealthController:18 - sub thead!
总结一下如果添加一次请求维度的logId:
参考:
Log4j – Configuring Log4j 2
Log4j – Log4j 2 API
转载注明来源❤️
个人网站:www.sanjie.site
个人微信公众号:叁戒
网站ai、游戏、摸鱼等板块,欢迎学习ai和玩游戏,有任何问题网站或公众号留言,欢迎交流沟通