log4j2配置一次请求的logId,子线程获取父线程数据

前言:在服务端排查日志时,想查看一次接口请求的完整日志,而不受其他其他日志干扰,可以在log4j中添加request维度的logId来实现过滤。

目录

1、如何添加logId

2、子线程如何获取logId


1、如何添加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

2、子线程如何获取logId

好像大功告成,可是等等上面提到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: 

  1. 添加接口拦截器。
  2. 拦截器里ThreadContext加入logId。
  3. log4j2.xml中pattern加入%X{logId}
  4. 配置系统参数log4j2.isThreadContextMapInheritable为true。

参考:

Log4j – Configuring Log4j 2

Log4j – Log4j 2 API

转载注明来源❤️

个人网站:www.sanjie.site

个人微信公众号:叁戒

log4j2配置一次请求的logId,子线程获取父线程数据_第1张图片

网站ai、游戏、摸鱼等板块,欢迎学习ai和玩游戏,有任何问题网站或公众号留言,欢迎交流沟通

 

你可能感兴趣的:(日常实践经验,java,spring,boot,经验分享)