Java logging system Log4j2

Introduction to Log4j2

Log4j2 is an upgraded version of Log4j. It refers to the excellent design of Logback and fixes some problems. The main advantages are:

  • Exception handling. In logback, exceptions in Appender will not be perceived by the application, but in log4j2, some exception handling mechanisms are provided.
  • Performance improvement, log4j2 has obvious performance improvement compared to log4j and logback.
  • Auto-reload configuration, referring to the design of logback, will provide automatic refresh parameter configuration. The most practical thing is that we can dynamically modify the log level in production without restarting the application. .
  • No garbage mechanism. In most cases, log4j2 can use its designed garbage-free mechanism to avoid jvmgc caused by frequent log collection.

Simple use of Log4j2

Log4j2, like Slf4j, can be implemented as both a portal and a log. But usually Slf4j is used as the portal and Log4j2 is used as the log implementation. First use Log4j2 alone for log printing

 <dependencies>
        <!--log portal-->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.19.0</version>
        </dependency>
        <!--log log implementation-->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.19.0</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
public class TestLog4j2 {
    public final static Logger logger = LogManager.getLogger(TestLog4j2.class);

    @Test
    public void testLog() throws Exception {
        logger.fatal("fatal");
        logger.error("error");
        logger.warn("wring");
        logger.info("info");
        logger.debug("debug");
        logger.trace("trace");
    }
}

20:05:28.830 [main] FATAL com.zmt.TestLog4j2 – fatal

20:05:28.831 [main] ERROR com.zmt.TestLog4j2 – error

It can be seen that the default level of Log4j2 is error.

Next use Slf4j mixed with Log4j2.

Just add the slf4j-api and log4j-slf4j-impl dependencies in the pom file. Nothing else needs to be changed.

 <dependencies>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>2.0.7</version>
        </dependency>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>2.13.3</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

Log4j2 configuration file

Log4j2 loads the log4j2.xml file in the classpath by default

<?xml version="1.0" encoding="UTF-8"?>
<!--
        status: The output log level of the log framework itself (output framework information)
        monitorInterval: The interval for automatically loading configuration files. In a production environment, there is no need to restart the project.
-->
<configuration status="warn" monitorInterval="5">
    <properties>
        <property name="log_dir" value="D:/logs"></property>
    </properties>
    <!--
    Log output format:
        %-5level log level
        %d{yyyy-MM-dd HH:mm:ss} date
        %cThe full name of the class
        %M is method
        %L is the line number
        %thread thread name
        %m or %msg is information
        %nLine break
    -->
    <Appenders>
        <!--Console output appender-->
        <Console name="Console" target="SYSTEM_ERR">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] [%-5level] %c{36}:%L --- %m%n"/>
        </Console>
        <!--Log file output appender-->
        <File name="file" fileName="${log_dir}/myfile.log">
            <Patternlayout pattern="[%d{yyyy-MM-dd HH:mm:ss}] [%-5level] %l %c{36} - %m%n"/>
        </File>

        <!--Use the log file output appender of random read and write streams to improve performance-->
        <RandomAccessFile name="accessFile" fileName="${log_dir}/myAcclog.log">
            <Patternlayout pattern="[%d{yyyy-MM-dd HH:mm:ss}] [%-5level] %l %c{36} - %m%n"/>
        </RandomAccessFile>
        <!--Appender for log files split according to certain rules-->
        <RollingFile name="rollingFile" fileName="${log_dir}/myrollog.log"
                     filePattern="${log_dir}/$${date:yyyy-MM-dd}/myrollog-%d{yyyy-MM-dd-HH-mm}-%i.log">
            <!--Log level filter-->
            <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/>
            <!--Log message format-->
            <Patternlayout pattern="[%d{yyyy-MM-dd HH:mm:ss}] [-5level] %l %c{36} - %msg%n"/>
            <Policies>
                <!--When the system starts, start the splitting rule and produce a new log file-->
                <OnStartupTriggeringPolicy/>
                <!--Split according to file size, 10MB-->
                <SizeBasedTriggeringPolicy size="10 MB"/>
                <!--Split according to time nodes, the rules are defined according to filePattern-->
                <TimeBasedTriggeringPolicy/>
            </Policies>
            <!--In the same directory, the number of files is limited to 30, and any excess files will be overwritten-->
            <DefaultRolloverStrategy max="30"/>
        </RollingFile>
    </Appenders>

    <!--logger definition-->
    <Loggers>
        <!--Use rootLogger to configure the log level level="trace"-->
        <Root Level="trace">
            <!--Specify the processor used by the log-->
            <AppenderRef ref="Console"/>
            <AppenderRef ref="file"/>
        </Root>
    </Loggers>
</configuration>

Log4j2 asynchronous log

There are three types of asynchronous logs:

  • AsyncAppender: Asynchronous Appender
  • Global AsyncLogger: Global asynchronous Logger
  • Mixed AsyncLogger: Logger that mixes asynchronous and synchronous use

Among them, the asynchronous Appender has the worst performance and is basically not used.

The global asynchronous Logger has the best performance, but sometimes not all businesses require asynchronous logging, so it is not commonly used.

Typically a hybrid AsyncLogger is used.

Simple implementation of asynchronous Appender

Add configuration under the Appenders tag in the xml configuration file

 <Appenders>
        <!--Console output appender-->
        <Console name="Console" target="SYSTEM_ERR">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] [%-5level] %c{36}:%L --- %m%n"/>
        </Console>
        <!--Log file output appender-->
        <File name="file" fileName="${log_dir}/myfile.log">
            <Patternlayout pattern="[%d{yyyy-MM-dd HH:mm:ss}] [%-5level] %l %c{36} - %m%n"/>
        </File>
      <!--Configuring asynchronous implementation-->
<Async name="async">
            <AppenderRef ref="file"></AppenderRef>
        </Async>
    </Appenders>

    <!--logger definition-->
    <Loggers>
        <!--Use rootLogger to configure the log level level="trace"-->
        <Root Level="trace">
            <!--Specify the processor used by the log-->
            <AppenderRef ref="Console"/>
            <AppenderRef ref="async"/>
        </Root>
    </Loggers>
public class TestLog4j2 {
    public final static Logger logger = LogManager.getLogger(TestLog4j2.class);

    @Test
    public void testLog() throws Exception {
        logger.fatal("fatal");
        logger.error("error");
        logger.warn("wring");
        logger.info("info");
        logger.debug("debug");
        logger.trace("trace");
    }
}

Watch log files

Simple implementation of global asynchronous Logger

Just create a file named log4j.component.properties in the resource directory and add the following configuration

Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector

The log4j2.xml configuration file does not require any changes.

Simple implementation of hybrid asynchronous Logger

If you use a hybrid asynchronous Logger, you need to comment or delete the configuration file of the global asynchronous Logger, and add dependencies.

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

Make modifications in the log4j.xml file

 <!--logger definition-->
    <Loggers>
        <!--Customized Logger-->
        <!--
            includeLocation: Set to false to turn off log line number recording. If turned on, it will affect performance.
            additivity: no longer inherit rootLogger
        -->
        <AsyncLogger name="com.zmt" level="debug" includeLocation="false" additivity="false">
            <AppenderRef ref="Console"/>
        </AsyncLogger>


        <!--Use rootLogger to configure the log level level="trace"-->
        <Root Level="trace">
            <!--Specify the processor used by the log-->
            <AppenderRef ref="Console"/>
            <AppenderRef ref="async"/>
        </Root>
    </Loggers>

Observe the console output

As you can see, even if %L is added to the log format, the line number is still not printed in the console.

Notice:

  • If you use asynchronous logs AysncAppender, AsyncLogger and global logs do not appear at the same time, the performance will be consistent with the worst
  • It is necessary to set includeLocation to false. Printing location information will reduce the performance of asynchronous logs, which is slower than synchronous logs.

Log4j2 garbage-free mode

Other logging systems will allocate temporary objects when recording logs, such as log event objects, strings, character arrays, etc. When there are too many temporary objects, the JVM’s gc operation will be triggered (this operation will suspend the running of the program). Starting from version 2.6, Log4j2 runs in garbage-free mode by default. The main principle is to reuse objects and buffers and not allocate temporary objects as much as possible.

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. Java Skill TreeHomepageOverview 138082 people are learning the system