1. 概述
官方参考文档:Log4j
Apache Log4j2 是对原先的 Log4j 项目的升级版本,参考了 logback 的一些优秀的设计,并且修复了一些问题,因此带来了一些重大的提升。
- 异常处理,在 logback 中,Appender 中的异常不会被应用感知到,但是在 log4j2 中,提供了一些异常处理机制;
- 性能提升,log4j2 相较于 log4j 和 logback 都具有明显的性能提升,有18倍性能提升;
- 自动装载配置,参考了 logback 的设计,当然会提供自动刷新参数配置,最实用的就是我们在生产上可以动态的修改日志级别而不需要重启应用;
- 无垃圾机制,log4j2 在大部分情况下,都可以使用其设计的一套无垃圾机制(对象重用、内存缓冲),避免频繁的日志收集导致的 JVM gc。
参考:https://logging.apache.org/log4j/2.x/
2. 案例与解析
2.1 引入依赖
SpringBoot 的 starter 自带的是 logback 日志,若要使用 log4j2 日志,需要引入对应依赖。
logback 日志和 log4j2 日志都是对 slf4j 门面的实现,只能存在一个,且必须存在一个,不存在或者存在多个都会出错。如果两者都存在就会出现以下的问题:
因此,在使用 log4j2 日志时,必须要在依赖中把 logback 给 exclude 掉。 并且,使用 log4j2 日志还需要适配器 **log4j-slf4j-impl**,它跟 SpringBoot 的 starter 自带的 **log4j-to-slf4j** 是相互冲突的,因此还需要将 **log4j-to-slf4j** 也 exclude 掉。
因为 SpringBoot 的 starter 中已经带有 slf4j 门面了,因此无需再引入 slf4j 依赖。
<!-- 使用 log4j2 的适配器进行绑定 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.19.0</version>
</dependency>
<!-- log4j2 日志门面 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.19.0</version>
</dependency>
<!-- log4j2 日志实面 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.19.0</version>
</dependency>
2.2 定义日志文件 log4j2.xml
<?xml version="1.0" encoding="UTF-8" ?>
<configuration status="warn" monitorInterval="5">
<properties>
<property name="LOG_HOME" value="logs"/>
</properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] [%-5level] %c{36}:%L --- %m%n"/>
</Console>
<File name="File" fileName="${LOG_HOME}/file-log4j2.log">
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss}] [%-5level] %l %c{36} - %m%n"/>
</File>
<RandomAccessFile name="AccessFile" fileName="${LOG_HOME}/myAcclog.log" immediateFlush="true">
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss}] [%-5level] %l %c{36} - %m%n"/>
</RandomAccessFile>
<RollingFile name="RollingFile" fileName="${LOG_HOME}/log4j2.log"
filePattern="logs/log4j2.%d{yyyy-MM-dd-HH-mm}.%i.log">
<ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss}] [%-5level] %l %c{36} - %msg%n"/>
<Policies>
<OnStartupTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="10 KB"/>
<TimeBasedTriggeringPolicy/>
</Policies>
<DefaultRolloverStrategy max="30"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
<AppenderRef ref="AccessFile"/>
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</configuration>
2.3 在 SpringBoot 项目的配置文件中配置
在 SpringBoot 的 application.properties (或者ymal格式的application.yaml) 中指明日志配置文件
# log4j2
logging.config=classpath:log4j2.xml
2.4 日志配置解析
Appenders
在 Appenders
中定义了 4 个 Appender,分别对应了 Console
、File
、 RandomAccessFile
和 RollingFile
4种类型。
- Console:控制台输出日志;
- File: 日志全部输出到一个文件中;
- RandomAccessFile:参考 RandomAccessFile,RandomAccessFile 总是将日志写入到缓存中,然后再写入到磁盘,并且写入缓存的过程是不能被关掉的,而 FileAppender 中写入缓存的过程是可以被关闭的。若将
immediateFlush
属性设置为 true,那么每写完一条日志到缓存后都会写入到磁盘中; - RollingFile:滚动日志,根据日期和日志文件大小滚动;参考 RollingFile;
Loggers
- Root:是根 logger,所有根据类的全路径名定位不到的 logger 都使用 Root 中定义的 Appender 来打印日志;
- Logger:定义一个具有具体名字的 logger,如
com.foo.Bar
,那么在要使用这个 logger 的地方LogManager.getLogger("com.foo.Bar")
即可得到这个 logger,就可以用这个 logger 下定义的 Appender 来打印日志了; - 如果定位不到 logger,则使用 Root 作为默认的 logger。因此,我们可以在 Root 中定义默认的日志配置,如果需要定义某个特定的 logger,采用不同的日志级别,那么就可以单独定义一个logger,在需要的地方用这个 logger 就可以了,十分方便;
3. 测试
3.1 控制台输出的日志
3.2 日志文件中输出的日志
参考文献
[1] https://logging.apache.org/log4j/2.x/index.html
[2] https://tanzhang.blog.csdn.net/article/details/110723441
[3] https://blog.csdn.net/cxy1991xm/article/details/90549806