springboot中如何将logback切换为log4j2
作者:明月一壶酒
前言
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万订单的高性能队列。
下图是官方给出的性能对比:
到此这篇关于springboot中将logback切换为log4j2的文章就介绍到这了,更多相关springboot logback切换log4j2内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!