Spring Boot(六):一招学会Log4j2

Log4j2简介

日志框架slf4j、j.u.l、log4j、logback、log4j2的比较 和 log4j2配置文件详解,请参考上篇文章《Log4j2使用详解

Log4j2实例

下面我们通过实例来看看Log4j2在Spring Boot中的应用

1、引入log4j2依赖

Spring Boot默认使用LogBack,如果我们要使用Log4j2,需要从spring-boot-starter-web中去掉spring-boot-starter-logging依赖,同时显式声明使用Log4j2的依赖jar包,具体如下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <!-- 去掉默认配置 -->
        <exclusion>
            <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
    </exclusions>
</dependency>

<!-- 引入log4j2依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

2、创建并配置log4j2-spring.xml

在src/main/resources文件夹下创建log4j2-spring.xml文件,并写入如下内容:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <properties>
        <property name="logBase">~/</property>
    </properties>

    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout charset="UTF-8" pattern="[%d] [%-5p] [%t] [%c] - %m%n"/>
        </Console>
        <RollingFile name="RollingFile" fileName="${logBase}/logs/access.log" filePattern="${logBase}/logs/access.%d{yyyy-MM-dd}.log">
            <PatternLayout pattern="[%d] [%-5p] [%t] [%c] - %m%n"/>
            <TimeBasedTriggeringPolicy/>
        </RollingFile>
        <RollingFile name="ErrorFile" fileName="${logBase}/logs/error.log" filePattern="${logBase}/logs/error.%d{yyyy-MM-dd}.log">
            <Filters>
                <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
            </Filters>
            <PatternLayout pattern="[%d] [error] [%t] [%c] - %m%n"/>
            <TimeBasedTriggeringPolicy/>
        </RollingFile>
    </Appenders>

    <Loggers>
        <Root level="trace">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="RollingFile"/>
            <AppenderRef ref="ErrorFile"/>
        </Root>
    </Loggers>
</configuration>

各节点的详细说明,详见《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文件中的<Root level="trace”>修改为<Root level="info”>,则日志从info级别开始打印,trace和debug日志不会打印。

多环境配置日志文件

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

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <properties>
        <property name="logBase">~/test/</property>
    </properties>

    <Appenders>
        <RollingFile name="RollingFile" fileName="${logBase}/logs/access.log" filePattern="${logBase}/logs/access.%d{yyyy-MM-dd}.log">
            <PatternLayout pattern="[%d] [%-5p] [%t] [%c] - %m%n"/>
            <TimeBasedTriggeringPolicy/>
        </RollingFile>
        <RollingFile name="ErrorFile" fileName="${logBase}/logs/error.log" filePattern="${logBase}/logs/error.%d{yyyy-MM-dd}.log">
            <Filters>
                <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
            </Filters>
            <PatternLayout pattern="[%d] [error] [%t] [%c] - %m%n"/>
            <TimeBasedTriggeringPolicy/>
        </RollingFile>
    </Appenders>

    <Loggers>
        <Root level="info">
            <AppenderRef ref="RollingFile"/>
            <AppenderRef ref="ErrorFile"/>
        </Root>
    </Loggers>
</configuration>

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环境,可以看到不同的环境打印出的日志

使用traceId跟踪请求全流程日志

线上我们一般采用多机部署,用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的读取:

<PatternLayout pattern="[%d] [%X{traceId}] [%-5p] [%t] [%c] - %m%n"/>

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上查看

更多内容,请关注公众号:图南随笔

猜你喜欢

转载自blog.csdn.net/tunan666/article/details/119703321
今日推荐