前言
springboot默认使用logback作为日志记录框架,常见的日志记录框架有log4j、logback、log4j2。这篇文章我们来学习怎样将logbak替换为log4j2。
一、为什么使用log4j2?
我们在项目中经常使用一个叫SLF4J的依赖,它是做什么的呢?
slf4j是对所有日志框架制定的一种规范、标准、接口,并不是一个框架的具体的实现,它的接口并不能独立使用,需要和具体的日志框架实现配合使用(如log4j、logback、log4j2)。
log4j是apache实现的一个开源日志组件。
logback同样是由log4j的作者设计完成的,拥有更好的特性,用来取代log4j的一个日志框架,是slf4j的原生实现。
Log4j2是log4j 1.x和logback的改进版,性能最高。
log4j2异步记录日志使用了disruptor框架,性能得到了提高,记录日志的流程如下:
几种日志框架的性能测试对比如下:
二、使用步骤
1.引入库
gradle:
//引入log4j2
api 'org.springframework.boot:spring-boot-starter-log4j2'
api "com.lmax:disruptor:3.4.4"
//删除logback依赖
configurations {
api.exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
api.exclude group: 'ch.qos.logback', module: 'logback-access'
api.exclude group: 'ch.qos.logback', module: 'logback-classic'
api.exclude group: 'ch.qos.logback', module: 'logback-core'
}
maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!-- 排除掉logging,不使用logback,改用log4j2 -->
<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>
<!-- disruptor -->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.4.4</version>
</dependency>
2.编写log4j2配置文件
在application.properties中引入配置文件
logging.config=classpath:log4j2-spring.xml
在resources下添加log4j2-spring.xml配置文件
以下是我在项目中的配置,注意的是使用AsyncLogger才会使用disruptor提高性能。如果使用的AsyncAppender,则使用的是类似logback一样的队列的方式做异步记录。
<?xml version="1.0" encoding="UTF-8"?>
<!--Configuration 后面的 status,这个用于设置 log4j2 自身内部的信息输出级别,可以不设置,当设置成 trace 时,你会看到 log4j2 内部各种详细输出-->
<!--monitorInterval:Log4j2 能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
<configuration status="error" monitorInterval="30">
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--变量配置-->
<properties>
<!-- 格式化输出:%date 表示日期,%thread 表示线程名,%-5level:级别从左显示 5 个字符宽度 %msg:日志消息,%n 是换行符-->
<!-- %logger{36} 表示 Logger 名字最长 36 个字符 -->
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level [%logger{50}:%L] - %msg%n"/>
<property name="LOG_CONSOLE_PATTERN" value="%style{%d{ISO8601}}{bright,green} %highlight{%-5level} [%style{%t}{bright,blue}] %style{%C{}}{bright,yellow}: %msg%n%style{%throwable}{red}"/>
<!-- 定义日志存储的路径 -->
<property name="FILE_PATH" value="logs"/>
<property name="FILE_NAME" value="newframe"/>
</properties>
<Appenders>
<!--*********************控制台日志***********************-->
<Console name="consoleAppender" target="SYSTEM_OUT">
<!--设置日志格式及颜色-->
<PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/>
</Console>
<!--info级别日志-->
<!-- 这个会打印出所有的info及以上级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
<RollingFile name="infoFileAppender"
fileName="${FILE_PATH}/${FILE_NAME}/log_info.log"
filePattern="${FILE_PATH}/${FILE_NAME}/log-info-%d{yyyy-MM-dd}_%i.log.gz"
append="true">
<!--设置日志格式-->
<PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/>
<Filters>
<!--过滤掉warn及更高级别日志-->
<ThresholdFilter level="warn" onMatch="DENY" onMismatch="NEUTRAL" />
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<Policies>
<!-- 基于时间的触发策略。该策略主要是完成周期性的log文件封存工作。有两个参数:
interval,integer型,指定两次封存动作之间的时间间隔。单位:以日志的命名精度来确定单位,
比如yyyy-MM-dd-HH 单位为小时,yyyy-MM-dd-HH-mm 单位为分钟
modulate,boolean型,说明是否对封存时间进行调制。若modulate=true,
则封存时间将以0点为边界进行偏移计算。比如,modulate=true,interval=4hours,
那么假设上次封存日志的时间为00:00,则下次封存日志的时间为04:00,
之后的封存时间依次为08:00,12:00,16:00-->
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<!-- DefaultRolloverStrategy 属性如不设置,则默认为最多同一文件夹下当天 7 个文件后开始覆盖-->
<DefaultRolloverStrategy max="30">
<!-- 删除处理策略,在配置的路径中搜索,maxDepth 表示往下搜索的最大深度 -->
<Delete basePath="${FILE_PATH}/${FILE_NAME}/" maxDepth="2">
<!-- 文件名搜索匹配,支持正则 -->
<IfFileName glob="*.log.gz"/>
<!--!Note: 这里的 age 必须和 filePattern 协调, 后者是精确到 dd, 这里就要写成 xd, xD 就不起作用
另外, 数字最好 >2, 否则可能造成删除的时候, 最近的文件还处于被占用状态,导致删除不成功!-->
<!--7天-->
<IfLastModified age="7d"/>
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
<!--warn级别日志-->
<!-- 这个会打印出所有的warn及以上级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
<RollingFile name="warnFileAppender"
fileName="${FILE_PATH}/${FILE_NAME}/log_warn.log"
filePattern="${FILE_PATH}/${FILE_NAME}/log-warn-%d{yyyy-MM-dd}_%i.log.gz"
append="true">
<!--设置日志格式-->
<PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/>
<Filters>
<!--过滤掉error及更高级别日志-->
<ThresholdFilter level="error" onMatch="DENY" onMismatch="NEUTRAL" />
<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<Policies>
<!-- 基于时间的触发策略。该策略主要是完成周期性的log文件封存工作。有两个参数:
interval,integer型,指定两次封存动作之间的时间间隔。单位:以日志的命名精度来确定单位,
比如yyyy-MM-dd-HH 单位为小时,yyyy-MM-dd-HH-mm 单位为分钟
modulate,boolean型,说明是否对封存时间进行调制。若modulate=true,
则封存时间将以0点为边界进行偏移计算。比如,modulate=true,interval=4hours,
那么假设上次封存日志的时间为00:00,则下次封存日志的时间为04:00,
之后的封存时间依次为08:00,12:00,16:00-->
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<!-- DefaultRolloverStrategy 属性如不设置,则默认为最多同一文件夹下当天 7 个文件后开始覆盖-->
<DefaultRolloverStrategy max="30">
<!-- 删除处理策略,在配置的路径中搜索,maxDepth 表示往下搜索的最大深度 -->
<Delete basePath="${FILE_PATH}/${FILE_NAME}/" maxDepth="2">
<!-- 文件名搜索匹配,支持正则 -->
<IfFileName glob="*.log.gz"/>
<!--!Note: 这里的 age 必须和 filePattern 协调, 后者是精确到 dd, 这里就要写成 xd, xD 就不起作用
另外, 数字最好 >2, 否则可能造成删除的时候, 最近的文件还处于被占用状态,导致删除不成功!-->
<!--7天-->
<IfLastModified age="7d"/>
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
<!--error级别日志-->
<!-- 这个会打印出所有的error及以上级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
<RollingFile name="errorFileAppender"
fileName="${FILE_PATH}/${FILE_NAME}/log_error.log"
filePattern="${FILE_PATH}/${FILE_NAME}/log-error-%d{yyyy-MM-dd}_%i.log.gz"
append="true">
<!--设置日志格式-->
<PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/>
<Filters>
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<Policies>
<!-- 基于时间的触发策略。该策略主要是完成周期性的log文件封存工作。有两个参数:
interval,integer型,指定两次封存动作之间的时间间隔。单位:以日志的命名精度来确定单位,
比如yyyy-MM-dd-HH 单位为小时,yyyy-MM-dd-HH-mm 单位为分钟
modulate,boolean型,说明是否对封存时间进行调制。若modulate=true,
则封存时间将以0点为边界进行偏移计算。比如,modulate=true,interval=4hours,
那么假设上次封存日志的时间为00:00,则下次封存日志的时间为04:00,
之后的封存时间依次为08:00,12:00,16:00-->
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<!-- DefaultRolloverStrategy 属性如不设置,则默认为最多同一文件夹下当天 7 个文件后开始覆盖-->
<DefaultRolloverStrategy max="30">
<!-- 删除处理策略,在配置的路径中搜索,maxDepth 表示往下搜索的最大深度 -->
<Delete basePath="${FILE_PATH}/${FILE_NAME}/" maxDepth="2">
<!-- 文件名搜索匹配,支持正则 -->
<IfFileName glob="*.log.gz"/>
<!--!Note: 这里的 age 必须和 filePattern 协调, 后者是精确到 dd, 这里就要写成 xd, xD 就不起作用
另外, 数字最好 >2, 否则可能造成删除的时候, 最近的文件还处于被占用状态,导致删除不成功!-->
<!--7天-->
<IfLastModified age="7d"/>
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
<!--<Async name="Async" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</Async>-->
</Appenders>
<Loggers>
<AsyncLogger name="org.apache.http" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="io.lettuce" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="io.netty" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="org.quartz" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="org.springframework" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="org.springdoc" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="druid.sql" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="io.undertow" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="sun.rmi" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="com.sun.mail" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="javax.management" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="de.codecentric" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="org.hibernate.validator" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="org.mybatis.spring.mapper" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="org.xnio" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="springfox" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="com.baomidou" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="io.micrometer.core" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="Validator" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="org.neo4j" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="org.apache.zookeeper" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="org.apache.curator" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="oshi.util" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="net.javacrumbs" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncLogger name="com.atomikos" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncLogger>
<AsyncRoot level="debug" includeLocation="true" additivity="false">
<AppenderRef ref="infoFileAppender"/>
<AppenderRef ref="warnFileAppender"/>
<AppenderRef ref="errorFileAppender"/>
<AppenderRef ref="consoleAppender"/>
</AsyncRoot>
</Loggers>
<!--Logger 节点用来单独指定日志的形式,比如要为指定包下的 class 指定不同的日志级别等。-->
<!--然后定义 loggers,只有定义了 logger 并引入的 appender,appender 才会生效-->
<!--<Loggers>
<Logger name="java.sql" level="debug" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="com.sxd.swapping.dao.mybatis" level="debug" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="org.apache.ibatis" level="debug" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="sun.rmi.transport.tcp" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="org.apache.http" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="com.sun.mail.smtp" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="javax.management" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="sun.rmi" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="de.codecentric" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="druid.sql.Connection" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="druid.sql.Statement" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="druid.sql.ResultSet" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="org.hibernate.validator" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="org.mybatis.spring.mapper" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="org.xnio.nio" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="springfox.documentation" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="springfox.bean" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="com.baomidou.mybatisplus.core" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="io.undertow" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="io.micrometer.core" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="com.baomidou.mybatisplus.extension.spring" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="Validator" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="io.lettuce" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="io.netty" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="org.springframework.boot.actuate.redis.RedisReactiveHealthIndicator" level="error" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="org.neo4j.driver" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="org.apache.zookeeper" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="org.apache.curator.framework.recipes.cache" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="oshi.util.platform.windows" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="org.quartz.core" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="org.quartz.simpl" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="net.javacrumbs.shedlock.core.DefaultLockingTaskExecutor" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="com.atomikos.jdbc.AbstractDataSourceBean" level="warn" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="com.atomikos.jdbc.AtomikosConnectionProxy" level="error" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="org.springframework.boot.actuate.mail" level="error" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="org.springframework.web" level="info" additivity="false" >
<AppenderRef ref="Async"/>
</Logger>
<Logger name="org.springframework.context" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="org.springframework.data" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="org.springframework.beans" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="org.springframework.core" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="org.springframework.jdbc" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<Logger name="org.springframework.messaging" level="info" additivity="false">
<AppenderRef ref="Async"/>
</Logger>
<!– 根日志设置 –>
<Root level="debug" additivity="false">
<AppenderRef ref="Async"/>
</Root>
</Loggers>-->
</configuration>
总结
log4j2使用了两种方式记录日志:AsyncAppender和AsyncLogger,上面我们的配置采用了AsyncLogger,性能最佳。
1、AsyncAppender使用队列异步记录日志,但是一旦队列已满,appender线程需要等待。
2、AsyncLogger是采用Disruptor,通过环形队列无阻塞队列作为缓冲,多生产者多线程的竞争是通过CAS实现,无锁化实现,可以降低极端大的日志量时候的延迟尖峰,Disruptor 可是号称一个线程里每秒处理600万订单的高性能队列。
下图是官方给出的性能对比: