Skip to content

Log4j2

Log4j2优点

  1. 在多线程场景下,Log4j2的吞吐量比Logback高出了10倍,延迟降低了几个数量级。这话听起来像吹牛,反正是Log4j2官方自己吹的。
  2. Log4j2的异步Logger使用的是无锁数据结构,而Logback和Log4j的异步Logger使用的是ArrayBlockingQueue。对于阻塞队列,多线程应用程序在尝试使日志事件入队时通常会遇到锁争用。
  3. Log4j2可以减少垃圾收集器的压力。
  4. 支持Lambda表达式。
  5. 支持自动重载配置。

快速开始

maven中引入log4j2包

xml
        <!-- log4j2日志门面 -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.18.0</version>
        </dependency>

        <!-- log4j2日志框架 -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.18.0</version>
        </dependency>

配置文件

Log4j2会去寻找 4 种类型的配置⽂件,前缀是 log4j2-test 或者 log4j2。后缀分别是 propertiesyamljsonxml

Log4j2的配置文件格式和Logback有点相似,基本的结构为<Configuration>元素,包含0或多个<Appenders>元素,其后跟0或多个<Loggers>元素,里面再跟最多只能存在一个的<Root>元素。

xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Root level="DEBUG">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

配置appender,也就是配置日志的输出目的地。

有Console,典型的控制台配置信息上面你也看到了,我来简单解释一下里面pattern的格式:

  • %d{HH:mm:ss.SSS}:表示输出到毫秒的时间
  • %t:输出当前线程名称
  • %-5level:输出日志级别,-5表示左对齐并且固定输出5个字符,如果不足在右边补空格
  • %logger:输出logger名称,最多36个字符
  • %msg:日志文本
  • %n:换行

顺带补充一下其他常用的占位符:

  • %F:输出所在的类文件名,如Main.java
  • %L:输出行号
  • %M:输出所在方法名
  • %l:输出语句所在的行数,包括类名、方法名、文件名、行数
  • %p:输出日志级别
  • %c:输出包名,如果后面跟有{length.}参数,比如说c{1.},它将输出报名的第一个字符,如com.itwanger的实际报名将只输出c.i

配置Loggers,指定Root的日志级别,并且指定具体启用哪一个Appenders。

自动重载配置

Logback支持自动重载配置,Log4j2也支持,那想要启用这个功能也非常简单,只需要在Configuration元素上添加monitorInterval属性即可。

xml
<Configuration monitorInterval="30">
...
</Configuration>

值要设置成非零,上例中的意思是至少30秒后检查配置文件中的更改。最小间隔为5秒。

Async示例

除了Console,还有Async,可以配合文件的方式来异步写入,典型的配置信息如下所示:

xml
<Configuration>
    <Appenders>
        <File name="DebugFile" fileName="debug.log">
            <PatternLayout>
                <Pattern>%d %p %c [%t] %m%n</Pattern>
            </PatternLayout>
        </File>
        <Async name="Async">
            <AppenderRef ref="DebugFile"/>
        </Async>
    </Appenders>
    <Loggers>
        <Root level="debug">
            <AppenderRef ref="Async"/>
        </Root>
    </Loggers>
</Configuration>

RollingFile示例

RollingFile会根据Triggering(触发)策略和Rollover(过渡)策略来进行日志文件滚动。如果没有配置Rollover,则使用DefaultRolloverStrategy来作为RollingFile的默认配置。

触发策略包含有:

  • 基于cron表达式(源于希腊语,时间的意思,用来配置定期执行任务的时间格式)的CronTriggeringPolicy
  • 基于文件大小的SizeBasedTriggeringPolicy
  • 基于时间的Time BasedTriggeringPolicy

过渡策略包含有:

  • 默认的过渡策略DefaultRolloverStrategy
  • 直接写入的DirectWriteRolloverStrategy

一般情况下,采用默认的过渡策略即可,它已经足够强大。

以下是基于SizeBasedTriggeringPolicyTimeBasedTriggeringPolicy策略,以及缺省DefaultRolloverStrategy策略的配置示例:

xml
<Configuration>
    <Appenders>
        <RollingFile name="RollingFile" fileName="rolling.log"
                     filePattern="rolling-%d{yyyy-MM-dd}-%i.log">
            <PatternLayout>
                <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
            </PatternLayout>
            <Policies>
                <SizeBasedTriggeringPolicy size="1 KB"/>
            </Policies>
        </RollingFile>
    </Appenders>
    <Loggers>
        <Root level="debug">
            <AppenderRef ref="RollingFile"/>
        </Root>
    </Loggers>
</Configuration>

RollingFile的配置

  • fileName:指定文件名。
  • filePattern:指定文件名的模式,它取决于过渡策略。

由于配置文件中没有显式指定过渡策略,因此RollingFile会启用默认的DefaultRolloverStrategy

先来看一下DefaultRolloverStrategy的属性:

属性值值类型描述
fileIndexString默认值为max,索引值较高的比较小的更新;如果是min,则相反。
minint计数器的最小值,默认值为1。
maxint计数器的最大值,默认值为7;达到这个值后,旧的日志文件被删除。
compressionLevelint压缩级别,从0-9,0为无,1为最佳速度,9为最佳压缩。仅针对zip文件。
tempCompressionFilePattenString日志文件压缩时的文件名模式。

再来看filePattern的值rolling-%d{yyyy-MM-dd}-%i.log,其中d{yyyy-MM-dd)很好理解,就是年月日;其中%i是什么意思呢?

第一个日志文件名为rolling.log(最近的日志放在这个里面),第二个文件名除去日期为rolling-1.1og,第二个文件名除去日期为rolling-2.log

其实和DefaultRolloverStrategy中的max属性有关,目前使用的默认值,也就是7,那就当rolling-8.log要生成的时候,删除rolling-1.log。可以调整Demo中的日志输出量来进行验证。

SizeBasedTriggeringPolicy,基于日志文件大小的时间策略,大小以字节为单位,后缀可以是KBMBGB,例如20MB

xml
<RollingFile name="RollingFileGZ" fileName="gz/rolling.log"
             filePattern="gz/%d{yyyy-MM-dd-HH}-%i.rolling.gz">
    <PatternLayout>
        <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
    </PatternLayout>
    <Policies>
        <SizeBasedTriggeringPolicy size="1 KB"/>
    </Policies>
</RollingFile>
  • fileName的属性值中包含了一个目录gz,也就是说日志文件都将放在这个目录下。
  • filePattern的属性值中增加了一个gz的后缀,这就表明日志文件要进行压缩了,还可以是Zip格式。

整合Springboot

xml
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <!-- 排除springboot默认的日志框架 -->
                <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>

快速使用

java
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Main {

    private static final Logger logger = LogManager.getLogger(Main.class);

    public static void main(String[] args) {
        logger.debug("log4j2");
    }
}

// 输出
2023-09-25 14:58:07,073 DEBUG taketo.Main [main] log4j2