log4j2用asyncRoot配置异步日志是如何使用disruptor
用asyncRoot配置对应的对接disruptor类是AsyncLoggerConfigDisruptor,用Log4jContextSelector启动参数配置全局异步的对应的对接disruptor类是AsyncLoggerDisruptor。下面分析的是AsyncLoggerConfigDisruptor
disruptor的创建与启动需要的部件实现
AsyncLoggerConfigDisruptor.start方法用来创建并启动disruptor实例
创建disruptor需要EventFactory,ringBuffer的大小,ThreadFactory,ProducerType,等待策略waitStrategy
创建后需要设置ExceptionHandler,设置EventHandler。
发布(生产)事件的translator。
EventFactory
分是否可变(mutable字段)场景对应两个不同的EventFactory。
不可变的factory的逻辑是:
@Override
public Log4jEventWrapper newInstance() {
return new Log4jEventWrapper();
}
可变的factory逻辑是:
public Log4jEventWrapper newInstance() {
return new Log4jEventWrapper(new MutableLogEvent());
}
会在 Log4jEventWrapper的构造函数中传入MutableLogEvent实例。
ringBuffer的大小
是根据AsyncLoggerConfig.RingBufferSize配置值算出来的。
这个配置项的值最小不能小于128,默认值分两种情况进行设定:如果启用了ENABLE_THREADLOCALS(优化GC的一个配置项),那么默认值是4 * 1024,否则是256 * 1024。
这个配置是通过System properties指定,同样存在不同版本,配置项名称不一致的情况,log4j2.asyncLoggerRingBufferSize (AsyncLogger.RingBufferSize)。详细可以参见这里
ThreadFactory
主要是定制线程名:
线程名格式是:"AsyncLoggerConfig-" + FACTORY_NUMBER(自增) + "-" + threadFactoryName + "-" + THREAD_NUMBER(自增)
默认的实际示例是: Log4j2-TF-1-AsyncLoggerConfig--1,跟上面的有些差异,上面的分析错了吗??
ProducerType
多生产者
等待策略waitStrategy
默认是10ms的TimeoutBlockingWaitStrategy。 支持可配置SleepingWaitStrategy、YieldingWaitStrategy、BlockingWaitStrategy、BusySpinWaitStrategy、TimeoutBlockingWaitStrategy。
这个配置是通过System properties指定,同样存在不同版本,配置项名称不一致的情况,log4j2.asyncLoggerWaitStrategy (AsyncLogger.WaitStrategy)。
ExceptionHandler
可以配置,配置项名称是AsyncLoggerConfig.ExceptionHandler,默认是用AsyncLoggerConfigDefaultExceptionHandler,打印: AsyncLogger error handling event seq=..., value=...,并打出异常栈。
EventHandler
此处使用了 Log4jEventWrapperHandler RingBufferLogEventHandler,是disruptor的SequenceReportingEventHandler实现。
/**
* EventHandler performs the work in a separate thread.
*/
private static class Log4jEventWrapperHandler implements SequenceReportingEventHandler<Log4jEventWrapper> {
private static final int NOTIFY_PROGRESS_THRESHOLD = 50;
private Sequence sequenceCallback;
private int counter;
@Override
public void setSequenceCallback(final Sequence sequenceCallback) {
this.sequenceCallback = sequenceCallback;
}
@Override
public void onEvent(final Log4jEventWrapper event, final long sequence, final boolean endOfBatch)
throws Exception {
event.event.setEndOfBatch(endOfBatch);
event.loggerConfig.asyncCallAppenders(event.event);
event.clear();
notifyIntermediateProgress(sequence);
}
/**
* Notify the BatchEventProcessor that the sequence has progressed. Without this callback the sequence would not
* be progressed until the batch has completely finished.
*/
private void notifyIntermediateProgress(final long sequence) {
if (++counter > NOTIFY_PROGRESS_THRESHOLD) {
sequenceCallback.set(sequence);
counter = 0;
}
}
}
event.loggerConfig.asyncCallAppenders(event.event); 这个会触发日志的输出
translator
跟EventFactory一样分mutable是否可变的两种情况。
不可变:
private static final EventTranslatorTwoArg<Log4jEventWrapper, LogEvent, AsyncLoggerConfig> TRANSLATOR =
new EventTranslatorTwoArg<Log4jEventWrapper, LogEvent, AsyncLoggerConfig>() {
@Override
public void translateTo(final Log4jEventWrapper ringBufferElement, final long sequence,
final LogEvent logEvent, final AsyncLoggerConfig loggerConfig) {
ringBufferElement.event = logEvent;
ringBufferElement.loggerConfig = loggerConfig;
}
};
可变:
/**
* Object responsible for passing on data to a RingBuffer event with a MutableLogEvent.
*/
private static final EventTranslatorTwoArg<Log4jEventWrapper, LogEvent, AsyncLoggerConfig> MUTABLE_TRANSLATOR =
new EventTranslatorTwoArg<Log4jEventWrapper, LogEvent, AsyncLoggerConfig>() {
@Override
public void translateTo(final Log4jEventWrapper ringBufferElement, final long sequence,
final LogEvent logEvent, final AsyncLoggerConfig loggerConfig) {
((MutableLogEvent) ringBufferElement.event).initFrom(logEvent);
ringBufferElement.loggerConfig = loggerConfig;
}
};
都是完成一个事情给ringBufferElement元素的event赋值或者初始化。
事件进队列的tryEnqueue方法逻辑分析
- prepareEvent
- ensureImmutable:创建LogEvent的快照,传递进来的原LogEvent在应用线程还会被继续修改,所以此处要创建快照
- Log4jLogEvent.makeMessageImmutable:格式化消息。因为是异步日志,针对需要format的消息在此处进行格式化,否则会因为引用对象值的改变导致日志不准确
- tryPublishEvent
- 发布事件对象到disruptor队列
事件出队列的处理
先看按下调用栈:
Daemon Thread [Log4j2-TF-1-AsyncLoggerConfig--1] (Suspended (breakpoint at line 37 in PatternFormatter))
PatternFormatter.format(LogEvent, StringBuilder) line: 37
PatternLayout$PatternSerializer.toSerializable(LogEvent, StringBuilder) line: 334
PatternLayout.toText(AbstractStringLayout$Serializer2, LogEvent, StringBuilder) line: 233
PatternLayout.encode(LogEvent, ByteBufferDestination) line: 218
PatternLayout.encode(Object, ByteBufferDestination) line: 58
ConsoleAppender(AbstractOutputStreamAppender<M>).directEncodeEvent(LogEvent) line: 177
ConsoleAppender(AbstractOutputStreamAppender<M>).tryAppend(LogEvent) line: 170
ConsoleAppender(AbstractOutputStreamAppender<M>).append(LogEvent) line: 161
AppenderControl.tryCallAppender(LogEvent) line: 156
AppenderControl.callAppender0(LogEvent) line: 129
AppenderControl.callAppenderPreventRecursion(LogEvent) line: 120
AppenderControl.callAppender(LogEvent) line: 84
AsyncLoggerConfig(LoggerConfig).callAppenders(LogEvent) line: 448
AsyncLoggerConfig.asyncCallAppenders(LogEvent) line: 129
AsyncLoggerConfigDisruptor$Log4jEventWrapperHandler.onEvent(AsyncLoggerConfigDisruptor$Log4jEventWrapper, long, boolean) line: 111
AsyncLoggerConfigDisruptor$Log4jEventWrapperHandler.onEvent(Object, long, boolean) line: 97
BatchEventProcessor<T>.run() line: 129
Log4jThread(Thread).run() line: 748
Log4jEventWrapperHandler.onEvent 111行是event.loggerConfig.asyncCallAppenders(event.event),参见上面EventHandler,此处完成日志真正写出。
log4j2用asyncRoot配置异步日志是如何使用disruptor的更多相关文章
- log4j2用Log4jContextSelector启动参数配置全局异步日志是如何使用disruptor
与 log4j2用asyncRoot配置异步日志是如何使用disruptor差异有几个: 给disruptor实例的EventFactory不同 此处EventFactory采用的是RingBuffe ...
- log4j2笔记 #02# 启用异步日志
索引 参考 Making All Loggers Asynchronous 第一步,添加相应的disruptor库 第二步,设置系统属性log4j2.contextSelector 第三步,检验! 参 ...
- logback配置异步日志
<appender name="FILE" class= "ch.qos.logback.core.rolling.RollingFileAppender" ...
- spring boot:使用log4j2做异步日志打印(spring boot 2.3.1)
一,为什么要使用log4j2? log4j2是log4j的升级版, 升级后更有优势: 性能更强/吞吐量大/支持异步 功能扩展/支持插件/支持自定义级别等 这些优 ...
- 一次鞭辟入里的 Log4j2 异步日志输出阻塞问题的定位
一次鞭辟入里的 Log4j2 日志输出阻塞问题的定位 问题现象 线上某个应用的某个实例突然出现某些次请求服务响应极慢的情况,有几次请求超过 60s 才返回,并且通过日志发现,服务线程并没有做什么很重的 ...
- 近期业务大量突增微服务性能优化总结-3.针对 x86 云环境改进异步日志等待策略
最近,业务增长的很迅猛,对于我们后台这块也是一个不小的挑战,这次遇到的核心业务接口的性能瓶颈,并不是单独的一个问题导致的,而是几个问题揉在一起:我们解决一个之后,发上线,之后发现还有另一个的性能瓶颈问 ...
- log4j2异步日志配置及官方文档的问题澄清
配置及demo 方法一全部打开 加启动参数 -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextS ...
- spring boot:配置druid数据库连接池(开启sql防火墙/使用log4j2做异步日志/spring boot 2.3.2)
一,druid数据库连接池的功能? 1,Druid是阿里巴巴开发的号称为监控而生的数据库连接池 它的优点包括: 可以监控数据库访问性能 SQL执行日志 SQL防火墙 2,druid的官方站: http ...
- Log4j2中的同步日志与异步日志
1.背景 Log4j 2中记录日志的方式有同步日志和异步日志两种方式,其中异步日志又可分为使用AsyncAppender和使用AsyncLogger两种方式. 2.Log4j2中的同步日志 所谓同步日 ...
随机推荐
- .gitignore梳理
参考来源: https://www.cnblogs.com/kevingrace/p/5690241.html 对于经常使用Git的朋友来说,.gitignore配置一定不会陌生.废话不说多了,接下来 ...
- 巧用netsh命令实现端口转发(端口映射)不求人
好处:即时生效,随意修改删除,不影响其他ip映射 记事本保存为bat格式批量添加后,并查看映射: netsh interface portproxy add v4tov4 listenport=701 ...
- LeetCode Reverse Words in a String 将串中的字翻转
class Solution { public: void reverseWords(string &s) { string end="",tem="" ...
- 常用宏OC
#ifndef MacroDefinition_h #define MacroDefinition_h //-------------------获取设备大小--------------------- ...
- java Vamei快速教程17 多线程
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 多线程 多线程(multiple thread)是计算机实现多任务并行处理的一种方 ...
- linux 命令——30 chown (转)
chown将指定文件的拥有者改为指定的用户或组,用户可以是用户名或者用户ID:组可以是组名或者组ID:文件是以空格分开的要改变权限的文件列表,支持通配符.系统管理员经常使用chown命令,在将文件拷贝 ...
- JPA将查询结果转换为DTO对象
前言 JPA支持使用@Query自定义查询,查询的结果需要字节用DTO对象接收,如果使用HQL的查询语句,可以将直接将DTO对象的构造方法传入hql中,直接转为DTO对象:而如果使用native sq ...
- POJ 2010 Moo University - Financial Aid(堆维护滑窗kth,二分)
按照score排序,贪心,从左到右用堆维护并且记录前面的最小N/2个花费之和. 然后从右向左枚举中位数,维护N/2个数之和加上并判断是否满足条件.(stl的队列没有clear(),只能一个一个pop. ...
- Linux---cp命令学习
cp命令 cp source_file target_file 能够复制文件,如果target_file所指定的文件不存在,cp就创建这个文件,如果已经存在,就把文件内容清空并把source_fil ...
- 小波变换(wavelet transform)的通俗解释(一)
小波变换 小波,一个神奇的波,可长可短可胖可瘦(伸缩平移),当去学习小波的时候,第一个首先要做的就是回顾傅立叶变换(又回来了,唉),因为他们都是频率变换的方法,而傅立叶变换是最入门的,也是最先了解的, ...