日志框架slf4j、j.u.l、log4j、logback、log4j2的比较 和 log4j2配置文件详解,请参考上篇文章《Log4j2使用详解》
下面我们通过实例来看看Log4j2在Spring Boot中的应用
1、引入log4j2依赖
Spring Boot默认使用LogBack,如果我们要使用Log4j2,需要从spring-boot-starter-web中去掉spring-boot-starter-logging依赖,同时显式声明使用Log4j2的依赖jar包,具体如下:
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-logging
org.springframework.boot
spring-boot-starter-log4j2
2、创建并配置log4j2-spring.xml
在src/main/resources文件夹下创建log4j2-spring.xml文件,并写入如下内容:
~/
各节点的详细说明,详见《Log4j2使用详解》
logBase请根据项目的实际日志目录修改
3、打印日志
一般情况下,我们使用LoggerFactory去获取Logger对象,在BlogController中我们加入如下内容:
private final static Logger logger = LoggerFactory.getLogger(BlogController.class);
@GetMapping(value = "log")
public String printLog() {
logger.trace("trace log");
logger.debug("debug log");
logger.info("info log");
logger.warn("warn log");
logger.error("error log");
return "print log ok";
}
调用接口,可以看到控制台和日志目录下的logs/access.log文件中从trace log到error log都依次打印出来,而error.log中打印出了error log。
如果把log4j2-spring.xml文件中的
Spring Boot默认加载log4j2-spring.xml文件,如果我们想像application.yml配置文件一样,不同的环境配置不同的log4j2文件,比如本地环境需要在控制台打印出来,测试环境和线上的日志目录不同等,这时候我们也可以根据环境的不同配置不同的日志文件。
1、创建log4j2-dev.xml、log4j2-test.xml和log4j2-prod.xml
log4j2-dev.xml:把log4j2-spring.xml文件内容copy到log4j2-dev.xml中
log4j2-test.xml:去掉控制台打印、修改logBase变量、修改root的日志level
~/test/
log4j2-prod.xml:修改logBase变量为~/prod/,其他同log4j2-test.xml
2、删除log4j2-spring.xml
3、多环境配置日志文件
application-dev.yml增加配置节点:
logging:
config: classpath:log4j2-dev.xml
application-test.yml增加配置节点:
logging:
config: classpath:log4j2-test.xml
application-prod.yml增加配置节点:
logging:
config: classpath:log4j2-prod.xml
4、修改环境变量,查看日志打印结果
IDEA中通过修改Active profiles来切换dev、test和prod环境,可以看到不同的环境打印出的日志
线上我们一般采用多机部署,用kibana收集日志,但是在并发大的时候,使用日志定位问题比较麻烦,很难筛选出指定请求的全部相关日志。因此我们可以对日志打印做一个改造,使用traceId跟踪请求的全部路径。
1、MDC简介
MDC:Mapped Diagnostic Context,映射调试上下文,它是 log4j 和 logback 提供的一种方便在多线程条件下记录日志的功能。MDC 中包含的内容可以被同一线程中执行的代码所访问。当前线程的子线程会继承其父线程中的 MDC 的内容。当需要记录日志时,只需要从 MDC 中获取所需的信息即可。
2、创建AccessInterceptor
在com.tn666.demo目录下创建interceptor文件夹,在此文件夹下创建AccessInterceptor类文件:
public class AccessInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
String traceId = UUID.randomUUID().toString();
MDC.put("traceId", traceId);
return true;
}
}
preHandle方法会在Controller处理之前进行调用,我们在请求开始时,向MDC中写入了一个traceId,这里主要说一下traceId的记录,更多拦截器的内容,后续的文章中会详细介绍
3、创建MvcConfiguration
在com.tn666.demo.configuration文件夹下创建MvcConfiguration类文件:
@Configuration
public class MvcConfiguration implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AccessInterceptor());
}
}
4、读取traceId
在 log4j 和 logback 的取值方式为:
%X{traceId}
在日志文件的PatternLayout中加入traceId的读取:
5、日志打印
访问接口,可以看到traceId的打印
从打印出的日志可以看出,这是两次http请求,有两个traceId
6、下游服务使用相同traceId
查找问题时,有时候我们希望把一次请求串起来,包括调用第三方服务,这时候我们可以采用如下方法:
1)改造http调用工具
在发送http请求时,自动将traceId添加到header中
2)下游服务的拦截器修改
下游服务的拦截器,首先从header中获取traceId,写入MDC中,若header中没有traceId,再使用UUID
文章中的示例代码,可以在https://github.com/tunan66666/spring-boot-demo上查看
更多内容,请关注公众号:图南随笔