原文地址:https://dzone.com/articles/asynchronous-logging-with-log4j-2

Log4J 2 is a logging framework designed to address the logging requirements of enterprise applications. If you are new to Log4J2, I suggest going through my introductory post on Log4J 2, Introducing Log4J 2 – Enterprise Class Logging.

Log4J 2 introduces configuration support via JSON and YAML in addition to properties file and XML. I’ve written about the different Log4J 2 configuration options in the following posts:

  • Log4J 2 Configuration: Using Properties File
  • Log4J 2 Configuration: Using XML
  • Log4J 2 Configuration: Using JSON
  • Log4J 2 Configuration: Using YAML

In this post, we’ll take a look at asynchronous loggers (async loggers) introduced in Log4J 2.

Asynchronous Logging: Introduction

Performance is critical for enterprise applications and nobody wants the underlying logging framework to become a bottleneck. In small programs with little volume, the overhead of logging is rarely an issue. However, enterprise services can see significant volume. If the service is getting invoked hundreds or even thousands of times per second, the overhead of logging can become significant. In such scenarios, two fundamental performance-related concepts are:

  • Latency: Time required to perform some action or to produce some result. Time of a transaction, or service invocation.
  • Throughput: The number of some actions executed or results produced per unit of time.

For increased logging performance, we want lower logging latency and higher throughput. The asynchronous logger in Log4J 2 does this by decoupling the logging overhead from the thread executing your code. An async logger has consistently lower latency than a synchronous logger and high throughput of logging messages at 6 – 68 times the rate of a synchronous logger.

I/O operations are notorious performance killers. This is because of locks and waits which are typical when dealing with I/O operations.  I/O operations can be executed in a separate thread, thereby freeing the main thread to perform other tasks. With the multicore architectures of modern CPUs, multithreaded operations are an ideal way to improve application performance.

Multi-threaded logging was present prior to Log4J 2 through asynchronous appenders, and its support still exist. The new asynchronous logger differs from asynchronous appender in how work is passed by the main thread to a different thread. Async appender uses an ArrayBlockingQueue – A first-in-first-out (FIFO) queue to hand off the messages to the thread which performs the I/O operations. The ArrayBlockingQueue class internally uses locks to ensure data integrity and data visibility between threads. As locks introduce latency, ArrayBlockingQueue is not the most optimal data structure to pass information between threads. Async logger is designed to optimize this area by replacing the blocking queue with LMAX Disruptor – a lock-free inter-thread communication library. The use of Disruptor results in higher throughput and lower latency in Log4J 2 logging. Martin Fowler has written an excellent article on the architecture of LMAX Disruptor here.

Maven Dependencies

To use async logger in your application, you need to add dependency of LMAX Disruptor in addition to the required Log4J 2 libraries to your Maven POM, like this.

. . .

<dependency>

   <groupId>org.springframework.boot</groupId>

   <artifactId>spring-boot-starter</artifactId>

   <exclusions>

      <exclusion>

         <groupId>org.springframework.boot</groupId>

         <artifactId>spring-boot-starter-logging</artifactId>

      </exclusion>

   </exclusions>

</dependency>

<dependency>

   <groupId>org.apache.logging.log4j</groupId>

   <artifactId>log4j-api</artifactId>

   <version>2.5</version>

</dependency>

<dependency>

   <groupId>org.apache.logging.log4j</groupId>

   <artifactId>log4j-core</artifactId>

   <version>2.5</version>

</dependency>

<dependency>

   <groupId>com.lmax</groupId>

   <artifactId>disruptor</artifactId>

   <version>3.3.4</version>

</dependency>

. . .

Configuring Log4J 2

Before we configure Log4J 2 async loggers, lets create a logger class that uses the Log4J 2 API to log messages.

Log4J2AsyncLogger.java

package guru.springframework.blog.log4j2async;

import org.apache.logging.log4j.LogManager;

import org.apache.logging.log4j.Logger;

public class Log4J2AsyncLogger {

    private static Logger logger = LogManager.getLogger();

    public void performSomeTask(){

               logger.debug("This is a debug message.");

               logger.info("This is an info message.");

               logger.warn("This is a warn message.");

               logger.error("This is an error message.");

               logger.fatal("This is a fatal message.");

     }

}

To test the preceding class, we will use JUnit.

Log4J2AsyncLoggerTest.java

package guru.springframework.blog.log4j2async;

import org.junit.Test;

public class Log4J2AsyncLoggerTest {

    @Test

    public void testPerformSomeTask() throws Exception {

        Log4J2AsyncLogger log4J2AsyncLogger=new Log4J2AsyncLogger();

        log4J2AsyncLogger.performSomeTask();

    }

}

Next, we will use XML to configure Log4J2. The log4j2.xml file is this.

<?xml version="1.0" encoding="UTF-8"?>

<Configuration status="debug">

    <Appenders>

        <Console name="Console-Appender" target="SYSTEM_OUT">

            <PatternLayout>

                <pattern>

                    [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n

                </pattern>>

            </PatternLayout>

        </Console>

        <File name="File-Appender" fileName="logs/xmlfilelog.log" >

            <PatternLayout>

                <pattern>

                    [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n

                </pattern>

            </PatternLayout>

        </File>

    </Appenders>

    <Loggers>

        <Logger  name="guru.springframework.blog.log4j2async" level="debug">

            <AppenderRef ref="File-Appender"/>he preceding c

        </Logger>

        <Root level="debug">

            <AppenderRef ref="Console-Appender"/>

        </Root>

    </Loggers>

</Configuration>

In the code above, we added the status="debug" attribute to the <configuration> tag to output internal Log4J 2 log messages. This is required to verify that log messages are indeed getting logged asynchronously. We then configured a console and a file appender. We also configured an application-specific logger and the root logger to use the file and console appenders respectively. Notice that we haven’t written any asynchronous logging configuration code as of yet.

All Async Loggers

The simplest way to enable asynchronous logging in Log4J 2 is to make all loggers async. This involves setting the Log4jContextSelector system property. On the command line, you can set it like this.

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

To set the Log4jContextSelector system property in IntelliJ, you need to perform the following steps.

  1. Click Run->Edit Configurations from the IntelliJ main menu.
  2. Expand the JUnit node on the left pane of the Run/Debug Configurations window that appears, and select the test class.
  3. Type -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector in the Vm options text field.

  1. Click the OK button.

When you run the Log4J2AsyncLoggerTest test class, the configured loggers will start logging messages asynchronously. You can confirm this in the internal Log4J 2 output, as shown in this figure.

Mixed Sync and Async Loggers

A Log4J 2 configuration can contain a mix of sync and async loggers. You specify application-specific async loggers as <AsyncLogger>, like this.

. . .

<Loggers>

    <AsyncLogger  name="guru.springframework.blog.log4j2async" level="debug">

        <AppenderRef ref="File-Appender"/>

    </AsyncLogger>

    <Root level="debug">

        <AppenderRef ref="Console-Appender"/>

    </Root>

</Loggers>

. . .

In the preceding configuration code, the application-specific logger will asynchronously log messages to the file, while the root logger will synchronously log messages to console.

To make the root logger async, use <AsyncRoot>.

Random Access File Appender

A discussion on asynchronous logging won’t be complete without the mention of the random access file appender. A random access file is similar to the file appender we used, except it’s always buffered with a default buffer size of 256 * 1024 bytes. The buffer size, as of the current release, is not configurable. This means that once the buffer is pre-allocated with a size at first use, it will never grow or shrink during the life of the system. You can override the default size with the AsyncLoggerConfig.RingBufferSize system property. The random access file appender internally uses a ByteBuffer with RandomAccessFile instead of aBufferedOutputStream. This results in significant performance improvement. It is reported to have 20-200% more performance gain as compared to file appender.

Log4J 2 also provides the rolling random access file appender for high performance rolling files. This appender, similar to random access file, is always buffered with the default size of 256 * 1024 bytes, which is not configurable.

I have discussed configuring rolling files here, and also here. To configure a similar rolling random access file appender, replace the <RollingFile> tag with <RollingRandomAccessFile>.

The code to configure a rolling random access file appender, is this.

. . .

<RollingRandomAccessFile name="Rolling-Random-Access-File-Appender"

                          fileName="logs/rollingrandomaccessfile.log"

                          filePattern="archive/logs/rollingrandomaccessfile.log.%d{yyyy-MM-dd-hh-mm}.gz">

    <PatternLayout pattern="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n"/>

    <Policies>

        <SizeBasedTriggeringPolicy size="1 KB"/>

    </Policies>

    <DefaultRolloverStrategy max="30"/>

</RollingRandomAccessFile >

. . .

You can access the above configured appender from an asynchronous logger, like this.

. . .

<Loggers>

    <AsyncLogger  name="guru.springframework.blog.log4j2async" level="debug">

        <AppenderRef ref="Rolling-Random-Access-File-Appender"/>

    </AsyncLogger>

    <Root level="debug">

        <AppenderRef ref="Console-Appender"/>

    </Root>

</Loggers>

. . .

The complete XML code of configuring an async logger to use a rolling random access file appender, is this.

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>

<Configuration status="debug">

    <Appenders>

        <Console name="Console-Appender" target="SYSTEM_OUT">

            <PatternLayout>

                <pattern>

                    [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n

                </pattern>>

            </PatternLayout>

        </Console>

        <RollingRandomAccessFile name="Rolling-Random-Access-File-Appender"

                                 fileName="logs/rollingrandomaccessfile.log"

                                 filePattern="archive/logs/rollingrandomaccessfile.log.%d{yyyy-MM-dd-hh-mm}.gz">

            <PatternLayout pattern="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n"/>

            <Policies>

                <SizeBasedTriggeringPolicy size="1 KB"/>

            </Policies>

            <DefaultRolloverStrategy max="30"/>

        </RollingRandomAccessFile>

    </Appenders>

    <Loggers>

        <AsyncLogger  name="guru.springframework.blog.log4j2async" level="debug">

            <AppenderRef ref="Rolling-Random-Access-File-Appender"/>

        </AsyncLogger>

        <Root level="debug">

            <AppenderRef ref="Console-Appender"/>

        </Root>

    </Loggers>

</Configuration>

Conclusion

In this post, I’ve discussed configuring asynchronous logging in Log4j 2 using the Log4jContextSelectorsystem property (for all async loggers) and through <AsyncLogger> and <AsyncRoot> (For mix of sync and async loggers). One common mistakes that programmers make is to mix both of them. Although it works, you will end up with two background threads – an unnecessary thread in the middle that passes a log message from your application to the thread that finally logs the message to disk.

The average Java application will not need the performance benefits of Log4J 2’s asynchronous logging. In many cases, it would simply be overkill. However, Java and the Spring Framework are often used for highly scalable applications processing enormous amounts of information. When you’re developing enterprise class applications, optimal performance does become critical. The option for asynchronous in Log4J 2 is a tool you can use to optimize the performance of your Java and Spring Applications.

转载于:https://www.cnblogs.com/davidwang456/p/5369594.html

asynchronous-logging-with-log4j-2--转相关推荐

  1. log4j:WARN No appenders could be found for logger (org.apache.ibatis.logging.LogFactory). log4j:WARN

    1. 警告信息 log4j:WARN No appenders could be found for logger (org.apache.ibatis.logging.LogFactory). lo ...

  2. 【日志问题】JDK Logging、Commons Logging和Log4j、Slf4j和Logbacck的介绍和简单使用

    [日志问题]JDK Logging.Commons Logging和Log4j.Slf4j和Logbacck的介绍和简单使用 是什么 简介 如何使用 JDK logging log4j +slf4j ...

  3. java自带logging以及log4j的应用

    啊,在经过使用正则表达式之后我们的实验又让我们使用日志记录发生的异常了,老师上课时候非常高兴的告诉我们日志很简单并且有多种日志可以使用.我回去一看,嚯还真是不少,而且他们都有一个共同特点------我 ...

  4. Java日志输出Logger,Commons Logging,Log4j的运用

    日志 在编写程序的过程中,常常用System.out.println()打印出执行过程中的某些变量,观察每一步的结果与代码逻辑是否符合,然后有针对性地修改代码.改好之后又要删除打印语句,这样很麻烦. ...

  5. common.logging和log4j比较

    apache common logging是一种log的框架接口,它本身并不实现log记录的功能,而是在运行时动态查找目前存在的日志库,调用相关的日志函数,从而隐藏具体的日志实现 log4j是具体的日 ...

  6. java log4j和logback,跨过slf4j和logback,直接晋级log4j 2

    今年一直关注log4j 2,但至今还没有出正式版.等不及了,今天正式向大家介绍一下log4j的升级框架,log4j 2. log4j,相信大家都熟悉,至今对java影响最大的logging系统,至今仍 ...

  7. intro to Apache Log4j 2

    [0]README 0.1)本文作为 原文(http://logging.apache.org/log4j/2.x/)的译文,仅作参考, 旨在了解 Log4j 2 的相关知识 : 0.2) Apach ...

  8. log4j平稳升级到log4j2

    一.前言 公司中的项目虽然已经用了很多的新技术了,但是日志的底层框架还是log4j,个人还是不喜欢用这个的.最近项目再生产环境上由于log4j引起了一场血案,于是决定升级到log4j2. 二.现象 虽 ...

  9. java log4j 异步_Log4j2异步日志之异步格式化

    在优化系统响应时间的时候,除了优化业务逻辑/代码逻辑之外,把日志改成异步也是一种不错的方案 Log4j2在异步日志的性能上已经无人能挡了,其异步效率高的主要原因是使用disruptor来做异步队列 但 ...

最新文章

  1. “std::invoke”: 未找到匹配的重载函数
  2. shell中的文件处理
  3. python入门(七)
  4. 舰r4月28服务器维护,崩坏3 11月28日版本更新维护通知
  5. android rtsp 延时,ijkplayer 单视频流直播延迟问题解决过程
  6. 平安产险项目记录(二)
  7. mysql连接命令行,从命令行连接到MySQL
  8. 【JNI知识一】--JNI接口函数与指针
  9. base64转图片_从一道面试题说起:GET 请求能传图片吗?
  10. Python RSA
  11. 进程的描述和进程的创建
  12. snprintf与sprintf的区别
  13. layer数据加载中,loading的显示
  14. 为什么 PSP22 对 Polkadot 生态系统很重要
  15. 将STM32 Flash的一部分虚拟为大容量存储设备 USB_Device
  16. Windows 10桌面空白处鼠标右键转圈
  17. Excel如何分别提取出数值整数部分和小数部分
  18. frameset和frame的使用方法
  19. gthub获得star指南
  20. 山寨芯片不会像山寨机一样泛滥

热门文章

  1. 用安卓虚拟机运行程序时程序停止_程序运行时Trace:DynamoRIO Tool
  2. python收取wss数据_Python金融应用之提取交易日+合并截面数据
  3. 计算机考研专业课资料,计算机考研专业课资料.doc
  4. 湖南大学计算机学院软件专业杨磊,杨磊-湖大信息科学与工程学院
  5. linux 进程原理内存,linux进程通信之共享内存原理(基于linux 1.2.13)
  6. otc机器人氩弧焊机_轻松搞定砂光机前后连线翻转!【富全智能】全自动180度圆筒式翻板机...
  7. 启动php服务命令,启动|停止服务
  8. 基于keras 的神经网络股价预测模型
  9. 神经网络贷款风险评估(base on keras and python )
  10. MySQL数据库https接口_第三章 mysql 数据库接口程序以及SQL语句操作