log4j2异步日志输出方式有几种

log4j2异步日志输出方式有几种

小编给大家分享一下log4j2异步日志输出方式有几种,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

log4j2的异步日志输出方式

使用log4j2的同步日志进行日志输出,日志输出语句与程序的业务逻辑语句将在同一个线程运行。

log4j2异步日志输出方式有几种

而使用异步日志进行输出时,日志输出语句与业务逻辑语句并不是在同一个线程中运行,而是有专门的线程用于进行日志输出操作,处理业务逻辑的主线程不用等待即可执行后续业务逻辑。

Log4j2中的异步日志实现方式有AsyncAppender和AsyncLogger两种。

其中:

  • AsyncAppender采用了ArrayBlockingQueue来保存需要异步输出的日志事件;

  • AsyncLogger则使用了Disruptor框架来实现高吞吐。

第一种实现异步方式AsyncAppender

AsyncAppender直接在log4j2的xml的配置文件中配置,注意下面代码的注释位置

<?xmlversion="1.0"encoding="UTF-8"?><Configurationstatus="warn"><Appenders><!--正常的Appender配置,此处配置的RollingFile会在下面AsyncAppender被通过name引用--><RollingFilename="RollingFileError"fileName="${Log_Home}/error.${date:yyyy-MM-dd}.log"immediateFlush="true"filePattern="${Log_Home}/$${date:yyyy-MM}/error-%d{MM-dd-yyyy}-%i.log.gz"><PatternLayoutpattern="%d{yyyy-MM-dd'at'HH:mm:ssz}%-5level%logger{36}:%msg%xEx%n"/><ThresholdFilterlevel="error"onMatch="ACCEPT"onMismatch="DENY"/><Policies><TimeBasedTriggeringPolicymodulate="true"interval="1"/><SizeBasedTriggeringPolicysize="10MB"/></Policies></RollingFile><!--一个Appender配置完毕--><!--异步AsyncAppender进行配置直接引用上面的RollingFile的name--><Asyncname="Async"><AppenderRefref="MyFile"/></Async><!--异步AsyncAppender配置完毕,需要几个配置几个--></Appenders><Loggers><Rootlevel="error"><!--此处如果引用异步AsyncAppender的name就是异步输出日志--><!--此处如果引用Appenders标签中RollingFile的name就是同步输出日志--><AppenderRefref="Async"/></Root></Loggers></Configuration>

重点内容全在上面代码的注释中,AsyncAppender的配置就在xml文件中实现,无需单独引用包来支持.配置AsyncAppender后,日志事件写入文件的操作将在单独的线程中执行。

AsyncAppender的常用参数

参数名类型说明
nameStringAsync Appender的名字
AppenderRefString异步调用的Appender的名字,可以配置多个
blockingboolean默认为true。如果为true,appender将一直等待直到queue中有空闲;如果为false,当队列满的时候,日志事件将被丢弃。(如果配置了error appender,要丢弃的日志事件将由error appender处理)
bufferSizeinteger队列中可存储的日志事件的最大数量,默认为128

第二种实现异步方式AsyncLogger

Log4j2中的AsyncLogger的内部使用了Disruptor框架。

Disruptor简介

Disruptor是英国外汇交易公司LMAX开发的一个高性能队列,基于Disruptor开发的系统单线程能支撑每秒600万订单。

目前,包括Apache Strom、Log4j2在内的很多知名项目都应用了Disruptor来获取高性能。

Disruptor框架内部核心数据结构为RingBuffer,其为无锁环形队列。

Disruptor为什么这么快?

  • lock-free-使用了CAS来实现线程安全

  • 使用缓存行填充解决伪共享问题

首先在pom单中应用相关的包

<dependency><groupId>com.lmax</groupId><artifactId>disruptor</artifactId><version>3.4.2</version></dependency>

第二步在log4j2的xml文件中配置AsyncLogger

log4j2.xml配置如下:

<?xmlversion="1.0"encoding="UTF-8"?><Configurationstatus="debug"name="MyApp"packages=""><Appenders><Consolename="Console"target="SYSTEM_OUT"><PatternLayoutpattern="%d{HH:mm:ss.SSS}[%t]%-5level%logger{36}-%msg%n"/></Console><RollingFilename="RollingFile"fileName="logs/app.log"filePattern="logs/app-%d{yyyy-MM-ddHH}.log"><PatternLayout><Pattern>%d%p%c{1.}[%t]%m%n</Pattern></PatternLayout><Policies><SizeBasedTriggeringPolicysize="500MB"/></Policies></RollingFile><RollingFilename="RollingFile2"fileName="logs/app2.log"filePattern="logs/app2-%d{yyyy-MM-ddHH}.log"><PatternLayout><Pattern>%d%p%c{1.}[%t]%m%n</Pattern></PatternLayout><Policies><SizeBasedTriggeringPolicysize="500MB"/></Policies></RollingFile></Appenders><Loggers><!--上面的配置都和原配置一样,就是在下方这直接定义AsyncLogger,他的name在java类中被引用即可--><AsyncLoggername="com.meituan.Main"level="trace"additivity="false"><appender-refref="RollingFile"/></AsyncLogger><AsyncLoggername="RollingFile2"level="trace"additivity="false"><appender-refref="RollingFile2"/></AsyncLogger><Rootlevel="debug"><AppenderRefref="Console"/><AppenderRefref="RollingFile"/></Root></Loggers></Configuration>

java代码如下:

publicclassMain{publicstaticvoidmain(Stringargs[]){//引用com.meituan.Main日志输出器Loggerlogger=LogManager.getLogger(Main.class);//引用的名为RollingFile2的异步AsyncLoggerLoggerlogger2=LogManager.getLogger("RollingFile2");Personperson=newPerson("Li","lei");logger.info("hello,{}",person);logger2.info("goodbye,{}",person);}

上述log4j2.xml中配置了两个AsyncLogger,名字分别为com.meituan.Main和RollingFile2。

并且,在main方法中分别使用两个logger来输出两条日志。

在加载log4j2.xml的启动阶段,如果检测到配置了AsyncRoot或AsyncLogger,将启动一个disruptor实例。

log4j2异步注意事项

log4j2异步类型

1) 使用<Async>标签

示例:

<Asyncname="asyncKafkaLog"><AppenderRefref="Failover"/></Async>

注意事项: 此类异步队列是BockingQueue,队列默认大小是128

2) 使用<AsyncLogger>标签

示例:

<AsyncLoggername="kafkaLogger"level="trace"includeLocation="false"><AppenderRefref="Failover"/></AsyncLogger>

注意事项: 此类异步队列是Disruptor队列默认大小是4096

3) 使用 JVM参数

示例:

#启动参数方式-DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector#代码方式System.setProperty("Log4jContextSelector","org.apache.logging.log4j.core.async.AsyncLoggerContextSelector");

注意事项: 此类异步是全量异步,log4j配置文件里所有logger都自动异步,使用异步队列为Disruptor,队列默认大小4096

小提示

① Disruptor队列性能远胜于BlockingQueue,这也是log4j2性能提升的重要原因之一

② 如果启用了全量异步,又使用了<AsyncLogger>会如何?

  • log4j2会新建两个Disruptor队列,<AsyncLogger>之流使用一个,其他的使用另外一个,所以建议将可能发生阻塞的logger归类使用一个Disruptor,毕竟是队列,一个阻塞了其他的得乖乖等着

③ 如果默认队列长度不足咋办?

#第一步:加大两个Disruptor队列的长度-DAsyncLogger.RingBufferSize=262144-DAsyncLoggerConfig.RingBufferSize=262144#第二步:设置队列满了时的处理策略:丢弃,否则默认blocking,异步就与同步无异了-Dlog4j2.AsyncQueueFullPolicy=Discard

以上是“log4j2异步日志输出方式有几种”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注恰卡编程网行业资讯频道!

发布于 2021-12-22 21:56:22
收藏
分享
海报
0 条评论
35
上一篇:基于Log4j2阻塞业务线程引发的问题有哪些 下一篇:log4j2的高并发死锁问题配置如何优化
目录

    0 条评论

    本站已关闭游客评论,请登录或者注册后再评论吧~

    忘记密码?

    图形验证码