log4j2用asyncRoot配置异步日志是如何使用disruptor

asyncRoot配置对应的对接disruptor类是AsyncLoggerConfigDisruptor,用Log4jContextSelector启动参数配置全局异步的对应的对接disruptor类是AsyncLoggerDisruptor。下面分析的是AsyncLoggerConfigDisruptor

disruptor的创建与启动需要的部件实现

AsyncLoggerConfigDisruptor.start方法用来创建并启动disruptor实例
创建disruptor需要EventFactoryringBuffer的大小ThreadFactoryProducerType等待策略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。 支持可配置SleepingWaitStrategyYieldingWaitStrategyBlockingWaitStrategyBusySpinWaitStrategyTimeoutBlockingWaitStrategy
这个配置是通过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
  1. ensureImmutable:创建LogEvent的快照,传递进来的原LogEvent在应用线程还会被继续修改,所以此处要创建快照
  2. Log4jLogEvent.makeMessageImmutable:格式化消息。因为是异步日志,针对需要format的消息在此处进行格式化,否则会因为引用对象值的改变导致日志不准确
  • tryPublishEvent
  1. 发布事件对象到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,此处完成日志真正写出。

原文地址:https://www.cnblogs.com/simoncook/p/10990208.html

时间: 2024-08-13 20:54:05

log4j2用asyncRoot配置异步日志是如何使用disruptor的相关文章

log4j2用Log4jContextSelector启动参数配置全局异步日志是如何使用disruptor

与 log4j2用asyncRoot配置异步日志是如何使用disruptor差异有几个: 给disruptor实例的EventFactory不同 此处EventFactory采用的是RingBufferLogEvent.FACTORY,newInstance逻辑大致是: public RingBufferLogEvent newInstance() { final RingBufferLogEvent result = new RingBufferLogEvent(); if (Constant

Log4j2使用总结(异步日志)

TimeBased Triggering Policy 基于时间的触发策略.该策略主要是完成周期性的log文件封存工作.有两个参数: interval,integer型,指定两次封存动作之间的时间间隔.单位:以日志的命名精度来确定单位,比如yyyy-MM-dd-HH 单位为小时,yyyy-MM-dd-HH-mm 单位为分钟 modulate,boolean型,说明是否对封存时间进行调制.若modulate=true,则封存时间将以0点为边界进行偏移计算.比如,modulate=true,inte

Log4j2中的同步日志与异步日志

1.背景 Log4j 2中记录日志的方式有同步日志和异步日志两种方式,其中异步日志又可分为使用AsyncAppender和使用AsyncLogger两种方式. 2.Log4j2中的同步日志 所谓同步日志,即当输出日志时,必须等待日志输出语句执行完毕后,才能执行后面的业务逻辑语句. 下面通过一个例子来了解Log4j2中的同步日志,并借此来探究整个日志输出过程. log4j2.xml配置如下: <?xml version="1.0" encoding="UTF-8"

异步日志

[z]https://www.jianshu.com/p/9f0c67facbe2 简介 Apache Log4j 2 is an upgrade to Log4j that provides significant improvements over its predecessor, Log4j 1.x, and provides many of the improvements available in Logback while fixing some inherent problems

log4j 异步日志问题分析

1. 常用的DailyRollingFileAppender与RollingFileAppender是否同步? 1.1 代码分析 2. log4j 1.2.x提供了异步appender是什么?AsyncAppender 2.1 AsyncAppender配置 2.2 AsyncAppender分析 3. log4j 2.x 异步日志问题的解决方案及分析 3.1 log4j 2.x 异步日志问题的解决方案 3.2 log4j 2.x 异步日志性能高的关键 1. 常用的DailyRollingFil

java log4j基本配置及日志级别配置详解

java log4j日志级别配置详解 1.1 前言 说出来真是丢脸,最近被公司派到客户公司面试外包开发岗位,本来准备了什么redis.rabbitMQ.SSM框架的相关面试题以及自己做过的一些项目回顾,信心满满地去面试,结果别人一上来就问到了最近项目使用的日志系统是什么?日志级别是怎么配置的?当时我都蒙X了,平时都是项目经理搭的,我自己也是随便上网一搜往配置文件一黏贴就OK了.我就这么说完后面试官深深定了我一眼,当时我的内心羞愧到...... 1.2 闲话少说,讲讲日志的发展故事(如果已经了解的

log4j2.xml完美配置

配置文件 <?xml version="1.0" encoding="UTF-8"?> <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --> <!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部

logback异步日志

一.为什么使用异步日志Why 为提高程序性能,尽量默认都使用异步日志,如果不使用,可能日志在打包的时候,会占用大量磁盘IO和CPU,导致程序性能下降 二.依赖 <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.20</version> </dependency> <depend

springboot配置logback日志

springboot配置logback日志 java web 下有好几种日志框架,比如:logback,log4j,log4j2(slj4f 并不是一种日志框架,它相当于定义了规范,实现了这个规范的日志框架就能够用 slj4f 调用).本篇主要说明spring boot配置logback springboot配置日志框架之前,要先取消springboot默认的日志框架 一.在pom.xml中加入取消默认日志框架 <dependency> <groupId>org.jxls</