springboot中将logback切换为log4j2

news2024/9/21 18:08:38

前言
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>


        &lt;!&ndash; 根日志设置 &ndash;&gt;
        <Root level="debug" additivity="false">
            <AppenderRef ref="Async"/>
        </Root>




    </Loggers>-->


</configuration>

总结

log4j2使用了两种方式记录日志:AsyncAppender和AsyncLogger,上面我们的配置采用了AsyncLogger,性能最佳。
1、AsyncAppender使用队列异步记录日志,但是一旦队列已满,appender线程需要等待。
2、AsyncLogger是采用Disruptor,通过环形队列无阻塞队列作为缓冲,多生产者多线程的竞争是通过CAS实现,无锁化实现,可以降低极端大的日志量时候的延迟尖峰,Disruptor 可是号称一个线程里每秒处理600万订单的高性能队列。


下图是官方给出的性能对比:

在这里插入图片描述

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/594019.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java 实现在顺序表末尾插入一个元素

一、思路 1.因为我们是用数组实现的顺序表&#xff0c;因此首先要保证数组有足够的空间来进行插入元素. 2.如果数组满了就需要将数组扩容&#xff0c;没满就开始插入. 3.当前数组中的元素个数就是每一次要插入的末尾位置的下标. 4.定义一个 usedSize 来表示当前的元素个数. 5.插…

Pandas+ChatGPT强强结合诞生PandasAI,数据分析师行业要变天了?

大家好&#xff0c;我是千与千寻&#xff0c;可以叫我千寻&#xff0c;我自己主要的编程语言是Python和Java。 说到Python编程语言&#xff0c;使用Python语言主要使用的是数据科学领域的从业者。 Python编程语言之所以在数据科学领域十分火热&#xff0c;源于Python语言的三…

9.Ansible Conditions介绍

Ansible条件语句 1)上面的例子在不同的机器上安装nginx&#xff0c;不同的操作系统风格使用不同的软件包管理器&#xff61;debian使用APT, Red Hat使用Yum, 但这是两个独立的Playbook,您必须为各自的服务器使用正确的剧本&#xff61; 可以使用条件语句&#xff0c;将这两个P…

Mongodb在Linux下载安装及部署

前言 一、下载安装包 Mongodb官网&#xff1a;Download MongoDB Community Server | MongoDB 二、安装及配置 博主下载的安装包是&#xff1a;mongodb-linux-x86_64-rhel70-6.0.6.tgz 新建目录 # 进入 usr 文件夹 cd /usr# 新建 mongodb 文件夹 mkdir mongodb# 进入 mongodb …

如何自学成为黑客

学习路线 不BB&#xff0c;直接上干货。 学完下面的内容&#xff0c;绝对可以进入黑客圈。 文末有福利噢&#xff01; 第一步&#xff1a;计算机基础 了解计算机基本常识&#xff0c;常用软件使用。需要学会基本使用的软件或技术有&#xff1a;Word、VMware、VPN、Visual St…

快速实现工程化部署,亚马逊云科技为AIGC产品化提供可靠基础

本文将以Stable Diffusion Quick Kit在亚马逊云科技Amazon SageMaker上的部署来介绍Stable Diffusion模型基础知识&#xff0c;HuggingFace Diffusers接口&#xff0c;以及如何使用Quick Kit在SageMaker Endpoint上快速部署推理服务。 Stable Diffusion模型 2022年由Stability…

自己拍摄的视频剪辑时如何消音?

由于录制环境的影响&#xff0c;有时制作出来的视频原始声音可能无法达到令人满意的效果&#xff0c;可能有噪声存在。这个时候&#xff0c;就应该先消除视频原始声音&#xff0c;然后后期再去给视频添加配音。有哪些适合给自己拍摄的视频调为静音的方法&#xff0c;来看看有哪…

详解 Windows 10 安装 CUDA 和 CUDNN

目录 查看本机 Window 10 系统已经安装 NIVIDIA 的驱动版本说在前面查看驱动版本 CUDA下载直接下载最新的 CUDA下载历史版本的 CUDA 安装测试 CUDNN下载 下载最新版本的 cuDNN下载历史版本的 cuDNN, 如: cuDNN 12.0安装 关于添加系统环境变量的问题 ⭐️⭐️说在前面!!! 建议 先…

平均年薪20W,自动化测试工程师这么吃香?

自动化测试工程师&#xff0c;平均年薪20w绝对不是空穴来凤&#xff0c;甚至我还说少了&#xff0c;加上年终奖和奖金等等年薪可能还不止20w这个水平&#xff0c;让我们看看下方截图&#xff0c;【来自于职友集】 本篇文章将由以下4个部分来展开&#xff1a; 1. 什么是自动化测…

PaddleClas初体验

PaddleClas初体验 该包是由百度PaddlePaddle组织下开源的项目&#xff0c;主要用于图像分类&#xff0c;图像搜索等相关任务。 项目地址&#xff1a; https://github.com/PaddlePaddle/PaddleClashttps://pypi.org/project/paddleclas 主要构件&#xff1a; PP-ShiTu&…

企业的数据信息值钱吗?如何提升数据信息的价值?

越来越多的企业也将数据视为转型发展、重塑竞争优势和提升组织治理能力的重要战略资产&#xff0c;并对这一重要资产进行系统性、体系化的管理&#xff0c;以便充分挖掘数据的战略、战术价值。鉴于此&#xff0c;对数据资产进行体全面盘点、构建企业级的数据资产目录成为了数据…

aigc分享

AIGC技术分享 AIGC概述 AIGC的概念、应用场景和发展历程 机器学习基础 机器学习的基本概念、分类和常用算法&#xff0c;如线性回归、决策树、支持向量机、神经网络等。 深度学习基础 深度学习的基本概念、分类和常用算法&#xff0c;如卷积神经网络、循环神经网络、自编…

面试专题:java多线程(2)-- 线程池

1.为什么要用线程池&#xff1f; 线程池提供了一种限制和管理资源&#xff08;包括执行一个任务&#xff09;。 每个线程池还维护一些基本统计信息&#xff0c;例如已完成任务的数量。 这里借用《Java并发编程的艺术》提到的来说一下使用线程池的好处&#xff1a; 降低资源消…

【嵌入式烧录/刷写文件】-1.6-剪切/保留Motorola S-record(S19/SREC/mot/SX)文件中指定地址范围内的数据

案例背景&#xff1a; 有如下一段S19文件&#xff0c;保留地址范围0x9140-0x91BF内的数据&#xff0c;删除地址范围0x9140-0x91BF外的数据。 S0110000486578766965772056312E30352EA6 S123910058595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F70717273747576775B S12391207…

如何判断一个点是否在凸多边形内 - golang

判断一个点是否在凸多边形内的方法很多&#xff0c;此处仅给出使用向量叉积法判断点是否在凸多边形内的方法。 以下图为例说明问题&#xff1a; 原理&#xff1a; 1. 将多边形的第 i 条边的第一个顶点指向点 P 得到向量 v1&#xff0c;然后将从第一个顶点指向第二个顶点得到向…

Java 多线程实现1到1千万的求和操作

一、使用多线程的背景 提高程序速度和响应性&#xff1a;许多应用程序需要同时执行多个任务&#xff0c;例如网络服务器&#xff0c;图形图像处理&#xff0c;模拟程序等。使用多线程可以让程序同时执行多个部分&#xff0c;从而显著提高程序的执行速度、响应速度。 充分利用 …

CompletableFuture 线程编排

一、前言 Java8 新特性之一&#xff0c;其实现了Future<T>, CompletionStage<T>两接口&#xff0c;后者是对前者的一个扩展&#xff0c;增加了异步回调、流式处理、多个Future组合处理的能力&#xff0c;使 Java 在处理多任务的协同工作时更加顺畅便利。 二、Compl…

POST请求与GET请求的区别

POST请求 &#xff08;提交数据&#xff0c;一般用于将数据发给服务器&#xff0c;用于修改和写入数据&#xff09; 1、传参方式&#xff1a;相对安全&#xff0c;入参在request body中&#xff0c;可通过各种抓包工具获取 2、缓存&#xff1a;不会被缓存&#xff0c;保存在服…

基于Qt的嵌入式GUI开发指南(一)

Qt 是一个跨平台的应用程序开发框架&#xff0c;用于创建高性能、可扩展和用户友好的图形用户界面&#xff08;GUI&#xff09;应用程序。它提供了丰富的工具、库和功能&#xff0c;使开发者能够轻松地构建各种类型的应用程序&#xff0c;包括桌面应用程序、移动应用程序和嵌入…