[Java from 0 to architect] SpringBoot - log processing - SLF4J, Logback, Log4j 2.x

Posted by edwardoka on Sat, 25 Dec 2021 01:36:24 +0100

Java from 0 to architect Directory: [Java from 0 to architect] learning record

Gitee Code: https://gitee.com/szluyu99/mj_java_frame/tree/master/04_SpringBoot

SLF4J supports various frameworks:

SLF4J + Log4j 1.x

Import dependency:

<!-- rely on slf4j-api,log4j 1.x -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.30</version>
</dependency>

Use example:

  • In SLF4J, there is no FATAL level (or it can be understood that FATAL is equivalent to ERROR)
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TestSLF4J_Log4j {
    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(TestSLF4J_Log4j.class);
        log.error("error_ERROR");
        log.warn("warning_WARN");
        log.info("information_INFO");
        log.debug("debugging_DEBUG");
        log.trace("mark_TRACE");
    }
}

Use Lombok to automatically generate the Logger definition of SLF4J:

@Slf4j
public class TestSLF4J_Log4j {
	// Using @slf4j equivalent, the following code is generated
    // private static final Logger logger =
    // LoggerFactory.getLogger(TestSLF4J_Log4j.class);
    public static void main(String[] args) {
        log.error("error_ERROR");
        log.warn("warning_WARN");
        log.info("information_INFO");
        log.debug("debugging_DEBUG");
        log.trace("mark_TRACE");
    }
}

SLF4J + Logback

Logback syntax is relatively free, and there is no constraint in its xml. Log4j 1 X has a dtd constraint

Import dependency:

<!-- rely on slf4j-api,logback-core -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>

Use example:

  • Logback has a set of default configurations, which can be used without providing configuration files

log4j 1.x must provide a configuration file

@Slf4j
public class TestSLF4J_Logback {
	// Using @slf4j equivalent, the following code is generated
    // private static final Logger logger =
    // LoggerFactory.getLogger(TestSLF4J_Logback.class);
    public static void main(String[] args) {
        for (int i = 0; i < 500; i++) {
            log.error("error_ERROR");
            log.warn("warning_WARN");
            log.info("information_INFO");
            log.debug("debugging_DEBUG");
            log.trace("mark_TRACE");
        }
	}
}

Logback - Profile

Configuration file location: classpath: logback xml

Logback and log4j 1 The configuration content of X is very similar, which is easy to learn

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- Extract public content -->
    <property name="PATTERN" 
     		  value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5p] [%t]: %m%n"/>
    <property name="CHARSET" value="UTF-8"/>
    
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <charset>${CHARSET}</charset>
            <pattern>${PATTERN}</pattern>
        </encoder>
    </appender>
    
    <root level="INFO">
        <appender-ref ref="console"/>
    </root>

    <logger name="com.mj" level="TRACE" additivity="false">
        <appender-ref ref="console"/>
    </logger>
</configuration>

Logback - console color printing

reference resources: Console color print document

<property name="PATTERN" 
	      value="%d{HH:mm:ss.SSS} [%highlight(%-5p)] %cyan(%c{5}): %m%n"/>
<property name="CHARSET" value="UTF-8"/>

<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <charset>${CHARSET}</charset>
        <pattern>${PATTERN}</pattern>
    </encoder>
</appender>

Logback - configuration

Common properties of the configuration tag:

  • debug="true": you can print logs inside Logback
  • scan="true" + scanPeriod="30 seconds"
    Scan the profile every 30 seconds and apply the latest changes to the profile
    The units of scanPeriod can be: milliseconds, seconds, minutes and hours
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true" scan="true" scanPeriod="5 seconds">

</configuration>

Logback - Appender controls the location of log output

Similar to Log4j, there are several Appender s in Logback:

  • ConsoleAppender - output logs to the console
  • FileAppender - output logs to a file (single)
  • RollingFileAppender - output log to file (scroll)

FileAppender uses:

<appender name="file" class="ch.qos.logback.core.FileAppender">
    <file>${BASE_PATH}/${BASE_NAME}.log</file>
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <charset>${CHARSET}</charset>
        <pattern>${FILE_PATTERN}</pattern>
    </encoder>
</appender>

<appender name="htmlFile" class="ch.qos.logback.core.FileAppender">
    <file>${BASE_PATH}/${BASE_NAME}.html</file>
    <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
        <charset>${CHARSET}</charset>
        <layout class="ch.qos.logback.classic.html.HTMLLayout">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}%p%t%m</pattern>
        </layout>
    </encoder>
</appender>

RollingFileAppender uses:

  • Timebasedlollingpolicy: time based rollingpolicy
<appender name="rollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${BASE_PATH}/${BASE_NAME}.log</file>
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <charset>${CHARSET}</charset>
        <pattern>${PATTERN}</pattern>
    </encoder>
    <!-- Time based rolling strategy -->
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <!-- Support compression -->
        <fileNamePattern>${BASE_PATH}/logback_rolling_%d{yyy-MM-dd-HH-mm-ss}.log.gz</fileNamePattern>
        <!-- Delete log files 20 seconds ago(The time unit depends on fileNamePattern) -->
        <maxHistory>20</maxHistory>
        <!-- Total log size limit(More than,Delete the oldest log) -->
        <totalSizeCap>10KB</totalSizeCap>
    </rollingPolicy>
</appender>
  • Sizeandtimebasedlollingpolicy: scrolling based on file size and time
<!--Scrolling strategy based on file size and time -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
    <!-- Support compression -->
    <fileNamePattern>${BASE_PATH}/logback_rolling_%d{HH-mm}_%i.log.gz</fileNamePattern>
    <!-- Delete log files 20 seconds ago(The time unit depends on fileNamePattern) -->
    <maxHistory>20</maxHistory>
    <!-- When the log file size exceeds 1 MB,A new log file is generated -->
    <maxFileSize>1MB</maxFileSize>
</rollingPolicy>

Logback - Filter filters log output information based on the Logger

Set Filter to print only WARN level information:

<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <charset>${CHARSET}</charset>
        <pattern>${CONSOLE_PATTERN}</pattern>
    </encoder>
    <!-- Print only WARN Level information -->
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
        <level>WARN</level>
        <!-- When matching: receive(Turn on Printing) -->
        <onMatch>ACCEPT</onMatch>
        <!-- When does not match: negative(Turn off printing) -->
        <onMismatch>DENY</onMismatch>
    </filter>
</appender>

You can also configure to turn off WARN and print only other levels:

<!-- close WARN,Open other -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
    <level>WARN</level>
    <onMatch>DENY</onMatch>
    <onMismatch>ACCEPT</onMismatch>
</filter>

Logback - AsyncAppender makes logging asynchronous

In Logback, you can use AsyncAppender to improve efficiency

  • The log writing operation will not affect the normal execution of the program (generally used for time-consuming operations such as writing logs to files)
<appender name="file" class="ch.qos.logback.core.FileAppender">
    <file>${BASE_PATH}/${BASE_NAME}.log</file>
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <charset>${CHARSET}</charset>
        <pattern>${PATTERN}</pattern>
    </encoder>
</appender>

<appender name="async" class="ch.qos.logback.classic.AsyncAppender">
    <!-- Capacity of blocking queue -->
    <param name="queueSize" value="512"/>
    <!-- When blocking the remaining 20 of the queue%Capacity time,It will be discarded by default TRACE,DEBUG,INFO Level log -->
    <!-- discardingThreshold Set to 0,It won't be discarded -->
    <param name="discardingThreshold" value="0"/>
    <!-- take file this appender Set to asynchronous -->
    <appender-ref ref="file"/>
</appender>

Principle of AsyncAppender:

Log4j 2.x

Example code: log4j 2.x

Import dependency:

<!-- rely on log4j-api -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.13.3</version>
</dependency>

Basic usage: log4j 2 X the default log level is ERROR (without configuration file)

public class TestLog4j2 {
    public static void main(String[] args) {
        Logger logger = LogManager.getLogger(TestLog4j2.class);
        logger.fatal("deadly_FATAL");
        logger.error("error_ERROR");
        logger.warn("warning_WARN");
        logger.info("information_INFO");
        logger.debug("debugging_DEBUG");
        logger.trace("mark_TRACE");
    }
}

Log4j 2.x - Profile

Configuration file: classpath: log4j2 xml

The configurations of various configuration files are similar. It's easy to understand with the previous foundation

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Properties>
        <Property name="PATTERN">%d{HH:mm:ss.SSS} [%-5p] %c{1.}: %m %n</Property>
        <Property name="CHARSET">UTF-8</Property>
    </Properties>
    <Appenders>
    	<Console name="Console">
	    	<PatternLayout pattern="${PATTERN}" charset="${CHARSET}"/>
		</Console>
	</Appenders>
	<Loggers>
	    <Root level="TRACE">
	        <AppenderRef ref="Console"/>
	    </Root>
	    <Logger name="com.mj" level="TRACE" additivity="false">
	        <AppenderRef ref="Console"/>
	    </Logger>
	</Loggers>
</Configuration>

Common properties in the Configuration tab:

  • Status: controls the printing level of Log4j internal logs, such as status="WARN"
  • monitorInterval: how many seconds to scan the configuration file and apply the latest modification of the configuration file
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="5">
</Configuration>

Log4j 2.x - console color printing

reference resources: http://logging.apache.org/log4j/2.x/manual/layouts.html#Patterns

<Properties>
	<Property name="PATTERN" value="%style{%d{HH:mm:ss.SSS}}{black}\
[%highlight{%t}] %highlight{%-5p}\
%style{%c{1.}}{magenta}: %m%n"/>
    <Property name="CHARSET">UTF-8</Property>
</Properties>

<Appenders>
	<Console name="Console" target="SYSTEM_OUT">
		<!-- disableAnsi="false" Turn on color printing -->
	    <PatternLayout pattern="${PATTERN}" charset="${CHARSET}"
	    			   disableAnsi="false"/>
	</Console>
</Appenders>

Log4j 2.x - Filter

Log4j 2. The commonly used filters in X are:

  • ThresholdFilter - takes a certain level as the threshold to control whether to output logs
  • LevelRangeFilter - controls the output of the log in a range
  • LevelMatchFilter - matches a log level
  • DenyAllFilter - disable all log levels
  • StringMatchFilter - matches according to the string in the log information

ThresholdFilter uses:

<Console name="Console">
    <PatternLayout pattern="${PATTERN}" charset="${CHARSET}"/>
    <!-- achieve WARN -> DENY -> close -->
    <!-- Not reached WARN -> ACCEPT -> open -->
	<ThresholdFilter level="WARN" onMatch="DENY" onMismatch="ACCEPT"/>
</Console>
  • ACCEPT: on; All subsequent filters will be ignored
  • DENY: closed; All subsequent filters will be ignored
  • NEUTRAL: NEUTRAL. Will be passed to
<!-- Open only[DEBUG,WARN]Level log -->
<Filters>
	<ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL">
	<ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY">
</Filters>

LevelRangeFilter uses:

  • Note that in log4j 2 In the LevelRangeFilter of X,
    minLevel is the maximum level and maxlLevel is the minimum level
<!-- Open only[DEBUG, WARN]Level log -->
<Filters>
	<LevelRangeFilter minLevel="WARN" maxLevel="DEDBUG"
					  onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>

Log4j 2.x - Appender

The structure of the log framework is similar, log4j 2 In X, you can specify the Appender directly through the label:

Log4j 1.x and Logback, specify the Appender through the < Appender > tag and class attribute

  • < console >: output logs to the console
  • < File >: output logs to a file (single)
  • < rollingfile >: output log to file (scroll)

<Console>:

  • target: the value can be SYSTEM_OUT (default), SYSTEM_ERR, controls the color of the output to the console
<Appenders>
	<Console name="Console" target="SYSTEM_ERR">
	    <PatternLayout pattern="${PATTERN}" charset="${CHARSET}"/>
	</Console>
</Appenders>

<File>:

<Properties>
    <Property name="PATTERN">%d{HH:mm:ss.SSS} [%-5p] %c{1.}: %m %n</Property>
    <Property name="CHARSET">UTF-8</Property>
    <Property name="BASE_PATH">F:/logs</Property>
    <Property name="BASE_NAME">log4j2</Property>
</Properties>
<File name="File" fileName="${BASE_PATH}/${BASE_NAME}_file.log">
	<PatternLayout pattern="${PATTERN}" charset="${CHARSET}"/>
</File>

<RollingFile>:

<RollingFile name="RollingFile"
             fileName="${BASE_PATH}/${BASE_NAME}.log"
             filePattern="${BASE_PATH}/%d{yyyy}/%d{MM}/%d{dd}/HH_mm_%i.log.gz">
    <PatternLayout pattern="${PATTERN}" charset="${CHARSET}"/>
    <Policies>
        <!-- Time based scrolling strategy: scroll when the time span reaches 2 minutes -->
        <!-- The time unit depends on filePattern Minimum time unit -->
        <TimeBasedTriggeringPolicy interval="2"/>

        <!-- File size based scrolling strategy: when the file size reaches 10 KB Scroll when -->
        <SizeBasedTriggeringPolicy size="10KB"/>
    </Policies>
    <!-- The default value is 7,set up%i Maximum value of -->
    </DefaultRolloverStrategy max="10">
</RollingFile>

Scroll policy - Delete

For output to a scrolling file, you can set a scrolling policy:

Reference documents: Delete

<!-- set up%i The default value is 7 -->
<DefaultRolloverStrategy max="100">
    <!-- maxDepth: The maximum number of levels to access the directory, Default 1, Delegate access only basePath Files in directory -->
    <Delete basePath="${BASE_PATH}" maxDepth="10">
        <!-- IfFileName && IfLastModified -->
        <!-- Fill in relative basePath Relative path of -->
        <IfFileName glob="*.log.gz"/>
        <!-- The file is older than 5 minutes s -->
        <IfLastModified age="5s">
            <!-- IfAccumulatedFileSize || IfAccumulatedFileCount -->
            <IfAny>
                <IfAccumulatedFileSize exceeds="20KB"/>
                <IfAccumulatedFileCount exceeds="10"/>
            </IfAny>
        </IfLastModified>
    </Delete>
</DefaultRolloverStrategy>

Log4j 2.x - Loggers

<Loggers>
    <Root level="WARN">
        <AppenderRef ref="Console"/>
    </Root>
	<Logger name="com.mj" level="TRACE" additivity="false">
		<AppenderRef ref="RollingFile"/>
	</Logger>
</Loggers>

Log4j 2.x - Async

<Console name="Console">
	<PatternLayout pattern="${PATTERN}" charset="${CHARSET}"/>
</Console>
<Async name="Async">
    <Appender-ref redf="Console"/>
</Async>

SLF4J + Log4j 2.x

Example code: SLF4J + Log4j 2.x

Import dependency:

<!-- rely on slf4j-api,log4j-api,log4j-core -->
<dependency>
	<groupId>org.apache.logging.log4j</groupId>
	<artifactId>log4j-slf4j-impl</artifactId>
	<version>2.13.3</version>
</dependency>

Code example:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TestSLF4J_Log4j2 {
    public static void main(String[] args) {
    	Logger logger = LoggerFactory.getLogger(TestSLF4J_Log4j2.class);
        log.error("error_ERROR");
        log.warn("warning_WARN");
        log.info("information_INFO");
        log.debug("debugging_DEBUG");
        log.trace("mark_TRACE");
    }
}

Use @slf4j annotation:

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class TestSLF4J_Log4j2 {
    public static void main(String[] args) {
        log.error("error_ERROR");
        log.warn("warning_WARN");
        log.info("information_INFO");
        log.debug("debugging_DEBUG");
        log.trace("mark_TRACE");
    }
}

Topics: Logback slf4j log4j2