log4j2异步日志的使用

前言:

之前三篇文章我们介绍过log4j、logback以及log4j2的springboot使用方式。

那么在实际的工作中,我们应该使用哪种日志框架呢?

做选择之前,我们肯定要有所比对,究竟哪种日志框架性能最好,使用最方便?从下图中(来自log4j2官网测试)

可以看出,log4j2(有三种模式[全异步、混合异步、同步])的性能吊打log4j1和logback。

尤其在多线程的测试下,log4j2的性能更是火力全开。

所以,为了实现更好的日志打印,我们就选择log4j2即可。

之前的文章中已经了解到了springboot与log4j2的结合使用方式,当时log4j2.xml中的配置采用的是同步日志打印方式,本文就来说下另外两种日志打印方式:完全异步、混合异步。

1.完全异步

完全异步日志打印方式是性能最高的方式,也是官方推荐的方式。

1.1 maven依赖(引入disruptor)

	<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

	<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <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.2</version>
        </dependency>
    </dependencies>

注意Log4j-2.9及更高版本在类路径上需要disruptor-3.3.4.jar或更高版本。在Log4j-2.9之前,需要disruptor-3.0.0.jar或更高版本。无需将系统属性“Log4jContextSelector”设置为任何值

1.2 log4j2.xml配置

在完全异步的方式下,log4j2.xml的配置与完全同步的配置文件相同,笔者直接从之前的文章中拷贝过来

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <!--<Configuration status="WARN" monitorInterval="30"> -->
    <properties>
        <property name="LOG_HOME">D:/</property>
        <Property name="LOG_PATTERN" value="%d [%t] %-5level %logger{0} - %msg%n"/>
    </properties>
    <Appenders>
        <!--*********************控制台日志***********************-->
        <Console name="consoleAppender" target="SYSTEM_OUT">
            <!--设置日志格式及颜色-->
            <PatternLayout
                    pattern="%style{%d{UTF-8}}{bright,green} %highlight{%-5level} [%style{%t}{bright,blue}] %style{%C{}}{bright,yellow}: %msg%n%style{%throwable}{red}"
                     noConsoleNoAnsi="false"/>
        </Console>

        <!--*********************文件日志***********************-->
        <!--all级别日志-->
        <RollingFile name="allFileAppender"
                     fileName="${LOG_HOME}/all.log"
                     filePattern="${LOG_HOME}/$${date:yyyy-MM}/all-%d{yyyy-MM-dd}-%i.log.gz">
            <!--设置日志格式-->
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
                <!-- 设置日志文件切分参数 -->
                <!--<OnStartupTriggeringPolicy/>-->
                <!--设置日志基础文件大小,超过该大小就触发日志文件滚动更新-->
                <SizeBasedTriggeringPolicy size="100 MB"/>
                <!--设置日志文件滚动更新的时间,依赖于文件命名filePattern的设置-->
                <TimeBasedTriggeringPolicy/>
            </Policies>
            <!--设置日志的文件个数上限,不设置默认为7个,超过大小后会被覆盖;依赖于filePattern中的%i-->
            <DefaultRolloverStrategy max="100"/>
        </RollingFile>

        <!--debug级别日志-->
        <RollingFile name="debugFileAppender"
                     fileName="${LOG_HOME}/debug.log"
                     filePattern="${LOG_HOME}/$${date:yyyy-MM}/debug-%d{yyyy-MM-dd}-%i.log.gz">
            <Filters>
                <!--过滤掉info及更高级别日志-->
                <ThresholdFilter level="info" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <!--设置日志格式-->
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
                <!-- 设置日志文件切分参数 -->
                <!--<OnStartupTriggeringPolicy/>-->
                <!--设置日志基础文件大小,超过该大小就触发日志文件滚动更新-->
                <SizeBasedTriggeringPolicy size="100 MB"/>
                <!--设置日志文件滚动更新的时间,依赖于文件命名filePattern的设置-->
                <TimeBasedTriggeringPolicy/>
            </Policies>
            <!--设置日志的文件个数上限,不设置默认为7个,超过大小后会被覆盖;依赖于filePattern中的%i-->
            <DefaultRolloverStrategy max="100"/>
        </RollingFile>

        <!--info级别日志-->
        <RollingFile name="infoFileAppender"
                     fileName="${LOG_HOME}/info.log"
                     filePattern="${LOG_HOME}/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log.gz">
            <Filters>
                <!--过滤掉warn及更高级别日志-->
                <ThresholdFilter level="warn" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <!--设置日志格式-->
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
            <!-- 设置日志文件切分参数 -->
            <!--<OnStartupTriggeringPolicy/>-->
            <!--设置日志基础文件大小,超过该大小就触发日志文件滚动更新-->
            <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
            <!--设置日志的文件个数上限,不设置默认为7个,超过大小后会被覆盖;依赖于filePattern中的%i-->
            <!--<DefaultRolloverStrategy max="100"/>-->
        </RollingFile>

        <!--warn级别日志-->
        <RollingFile name="warnFileAppender"
                     fileName="${LOG_HOME}/warn.log"
                     filePattern="${LOG_HOME}/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log.gz">
            <Filters>
                <!--过滤掉error及更高级别日志-->
                <ThresholdFilter level="error" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <!--设置日志格式-->
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
                <!-- 设置日志文件切分参数 -->
                <!--<OnStartupTriggeringPolicy/>-->
                <!--设置日志基础文件大小,超过该大小就触发日志文件滚动更新-->
                <SizeBasedTriggeringPolicy size="100 MB"/>
                <!--设置日志文件滚动更新的时间,依赖于文件命名filePattern的设置-->
                <TimeBasedTriggeringPolicy/>
            </Policies>
            <!--设置日志的文件个数上限,不设置默认为7个,超过大小后会被覆盖;依赖于filePattern中的%i-->
            <DefaultRolloverStrategy max="100"/>
        </RollingFile>

        <!--error及更高级别日志-->
        <RollingFile name="errorFileAppender"
                     fileName="${LOG_HOME}/error.log"
                     filePattern="${LOG_HOME}/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log.gz">
            <!--设置日志格式-->
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
                <!-- 设置日志文件切分参数 -->
                <!--<OnStartupTriggeringPolicy/>-->
                <!--设置日志基础文件大小,超过该大小就触发日志文件滚动更新-->
                <SizeBasedTriggeringPolicy size="100 MB"/>
                <!--设置日志文件滚动更新的时间,依赖于文件命名filePattern的设置-->
                <TimeBasedTriggeringPolicy/>
            </Policies>
            <!--设置日志的文件个数上限,不设置默认为7个,超过大小后会被覆盖;依赖于filePattern中的%i-->
            <DefaultRolloverStrategy max="100"/>
        </RollingFile>

    </Appenders>

    <Loggers>
        <!--spring日志-->
        <Logger name="org.springframework" level="debug"/>

        <!-- 根日志设置 -->
        <Root level="debug">
            <AppenderRef ref="allFileAppender" level="all"/>
            <AppenderRef ref="consoleAppender" level="debug"/>
            <AppenderRef ref="debugFileAppender" level="debug"/>
            <AppenderRef ref="infoFileAppender" level="info"/>
            <AppenderRef ref="warnFileAppender" level="warn"/>
            <AppenderRef ref="errorFileAppender" level="error"/>
        </Root>
    </Loggers>
</Configuration>

1.3 完全异步开启

1.3.1 通过JVM启动参数设置

-DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector

1.3.2 通过System属性设置

System.setProperty("Log4jContextSelector",
                "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector");

1.4 验证异步是否开启

按照上述方式设置完成之后,我们如何验证是否开启了全异步日志呢?

可以通过log4j2提供的一个方法AsyncLoggerContextSelector.isSelected(),如果返回true,则说明开启了。

Assert.isTrue(AsyncLoggerContextSelector.isSelected(), "log4j2 的异步 disruptor启动失败");

1.5 那些不正确的全异步开启方式

网上找到一篇文章,博主列举了常用的几个开启异步问题,有兴趣大家可以参考下: 高性能 log4j 2 疑难杂症 - 怎样正确开启全局异步 怎么验证是否真正开启了_w1047667241的博客-CSDN博客_log4j2开启异步   

2.混合异步日志

混合异步,理解下来就是当前项目的日志打印有两种方式:异步、同步

那么究竟哪些是异步的,哪些是同步的呢? 该如何设置呢?

我们可以通过Appender和Logger两个方面来设置(不要同时设置)

2.1 maven依赖

这里的maven依赖同1.1

2.2 log4j2.xml配置

2.2.1 设置Appender异步

同样,针对1.2中的log4j2.xml文件中的errorFileAppender来作为参考,设置一个异步Appender

		<!--error及更高级别日志  同步Appender-->
        <RollingFile name="errorFileAppender"
                     fileName="${LOG_HOME}/error.log"
                     filePattern="${LOG_HOME}/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log.gz">
            <!--设置日志格式-->
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
                <!-- 设置日志文件切分参数 -->
                <!--<OnStartupTriggeringPolicy/>-->
                <!--设置日志基础文件大小,超过该大小就触发日志文件滚动更新-->
                <SizeBasedTriggeringPolicy size="100 MB"/>
                <!--设置日志文件滚动更新的时间,依赖于文件命名filePattern的设置-->
                <TimeBasedTriggeringPolicy/>
            </Policies>
            <!--设置日志的文件个数上限,不设置默认为7个,超过大小后会被覆盖;依赖于filePattern中的%i-->
            <DefaultRolloverStrategy max="100"/>
        </RollingFile>

		<!-- 异步Appender -->
        <Async name="async_appender">
            <AppenderRef ref="errorFileAppender"/>
        </Async>

设置异步Appender之后,在下面的Loggers中来使用该Appender

	<Loggers>
        <!-- 对自定义个Logger使用asyncAppender -->
        <Logger name="com.example.log4j2springboot.log" level="debug">
            <AppenderRef ref="async_appender" level="debug"/>
        </Logger>
    </Loggers>

2.2.2 设置Logger异步

这里介绍下设置Logger为异步的方式

        <!-- 设置异步Logger -->
        <AsyncLogger name="com.example.log4j2springboot.log" level="debug">
            <AppenderRef ref="debugFileAppender" level="debug"/>
        </AsyncLogger>

		<!-- 设置同步Logger -->
		<Logger name="org.springframework" level="debug">
            <AppenderRef ref="allFileAppender" level="debug"/>
        </Logger>

2.3 验证异步开启

这种混合异步的方式其实不是太方便验证,我们可以简单通过下面两个方面来验证:

开启项目DEBUG模式,Get thread dump后,可以看到异步线程的信息

总结:

log4j2日志性能比较:全异步>混合异步>同步。

所以建议大家在使用的时候使用全异步的方式,火力全开,性能为王。

参考:

Log4j2的异步性能_milo.qu的博客-CSDN博客

SpringBoot - 日志框架Log4j2的整合教程3(异步输出日志)

Log4j2中的同步日志与异步日志 - Ye_yang - 博客园 原理介绍

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

恐龙弟旺仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值