What about the Java logging framework

Posted by howtoholdem on Tue, 07 Dec 2021 18:12:54 +0100

During project development, we can find problems through debug. In the online environment, we can only find problems by printing logs. Therefore, logging is a very important issue for a project. Therefore, how to choose an appropriate logging framework is also very important.

In Java development, common logging frameworks include JDKLog, Log4J, LogBack, SLF4J and SLF4J. These logging frameworks have their own characteristics and application scenarios. Understanding the characteristics and application scenarios of these frameworks is helpful for us to make correct judgment when making technology selection.

JDKLog: log knife

JDKLog is a log recording method officially provided by JDK. It can be used directly in JDK.

import java.util.logging.Logger;
 
/****
 ** JDKLog Demo
 **/
public class JDKLog
{
    public static void main( String[] args )
    {
        Logger logger = Logger.getLogger("JDKLog");
        logger.info("Hello World.");
    }
}

The advantage of JDKLog is that it is very simple to use and can be used directly in JDK. However, the JDKLog function is too simple, does not support placeholder display, and has poor expansibility, so few people use it now.

Log4J: log cannon

Log4J is a log open source framework of Apache. It has multiple levels (DEBUG/INFO/WARN/ERROR), which can record logs of different log levels separately, which greatly facilitates the viewing of logs.

Log4J has versions 1.X and 2.X. now the official recommendation is to use version 2.X. version 2.X has made some upgrades in the architecture and some changes in the configuration file. But fortunately Official configuration documentation It is clear that most problems can be solved by consulting the documentation.

To use the Log4J framework, you first need to introduce dependent packages:

<!-- Log4J -->
<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-api</artifactId>
  <version>2.6.2</version>
</dependency>
<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-core</artifactId>
  <version>2.6.2</version>
</dependency>

Add the configuration file log4j2.xml and put it in the resource directory:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

Where the level attribute of the node represents the lowest level of output.

Finally, write a test class:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
 
/****
 ** Log4J Demo
 **/
public class Log4jLog {
    public static void main(String args[]) {
        Logger logger = LogManager.getLogger(Log4jLog.class);
        logger.debug("Debug Level");
        logger.info("Info Level");
        logger.warn("Warn Level");
        logger.error("Error Level");
    }
}

Run test class output results:

10:16:08.279 [main] INFO  com.chanshuyi.Log4jLog - Info Level
10:16:08.280 [main] WARN  com.chanshuyi.Log4jLog - Warn Level
10:16:08.280 [main] ERROR com.chanshuyi.Log4jLog - Error Level

If the log4j2.xml configuration file is not configured, LOG4J will automatically enable a configuration file similar to the following:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Root level="error">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

Output using default profile:

ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.
11:40:07.377 [main] ERROR com.chanshuyi.Log4jLog - Error Level

It can be seen from the above steps that the use of Log4J is a little complicated, but the organization is still very clear. Moreover, because Log4J has multiple hierarchical (DEBUG/INFO/WARN/ERROR) recording levels, it can well record different business problems. Because of these advantages, almost everyone used Log4J as the logging framework a few years ago, and the mass base is very deep.

However, Log4J itself has some disadvantages, such as not supporting the use of placeholders and not conducive to code reading. However, compared with JDKLog, Log4J is a very good logging framework.

LogBack: log rocket

LogBack is actually an evolutionary version of log4j, because both of them are open source log components designed by the same person (Ceki G ü lc ü). In addition to all the advantages of log4j, LogBack also solves the problem that log4j cannot use placeholders.

To use LogBack, you need to first introduce dependencies:

<!-- LogBack -->
<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>1.1.7</version>
</dependency>

Configure the logback.xml configuration file:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
        </layout>
    </appender>
    <logger name="com.chanshuyi" level="TRACE"/>
 
    <root level="debug">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

The log level of LogBack can be subdivided into classes or packages, which can make logging more flexible. Then, the Logger class is introduced into the class file and logged:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
/****
 ** LogBack Demo
 **/
public class LogBack {
    static final Logger logger = LoggerFactory.getLogger(LogBack.class);
    public static void main(String[] args) {
        logger.trace("Trace Level.");
        logger.debug("Debug Level.");
        logger.info("Info Level.");
        logger.warn("Warn Level.");
        logger.error("Error Level.");
    }
}

Output results:

14:34:45.747 [main] TRACE com.chanshuyi.LogBack - Trace Level.
14:34:45.749 [main] DEBUG com.chanshuyi.LogBack - Debug Level.
14:34:45.749 [main] INFO  com.chanshuyi.LogBack - Info Level.
14:34:45.749 [main] WARN  com.chanshuyi.LogBack - Warn Level.
14:34:45.749 [main] ERROR com.chanshuyi.LogBack - Error Level.

LogBack solves the problem that Log4J cannot use placeholders, which makes it very convenient to read log code. In addition, LogBack has faster running speed and better internal implementation than Log4J. In addition, SLF4J is integrated in LogBack, which can realize some log recording more natively.

SLF4J: adapter

JDKLog, Log4J and LogBack, which are commonly used logging frameworks, have their own advantages and disadvantages and are suitable for use in different scenarios. Maybe simple projects can use JDKLog directly, while complex projects need Log4J.

Many times, our projects are from simple to complex, that is, we may use JDKLog at the beginning, and then the business is complex, so we need to use Log4J. At this time, how can we output the originally written logs with the new log framework?

One of the most rigid methods is to modify the code line by line. All the log codes previously used in JDKLog are modified into the log interface of Log4J. But this way is not only inefficient, but also repetitive work. How can we bear it.

Formally, in the actual project application, it is sometimes necessary to switch from one logging framework to another. At this time, it is often necessary to make great changes in the code. In order to avoid changing the code when switching logging components, a thing called SLF4J (Simple Logging Facade for Java, that is, java simple logging interface set) appears.

SLF4J (Simple Logging Facade for Java, i.e. java simple logging interface set) is a log interface specification. It provides users with a unified log interface and shields the differences of different log components. In this way, we only need to look at the interface document SLF4J when writing code, and we don't need to pay attention to the differences between different frameworks. When we need to replace the log component, we only need to replace a specific log component Jar package.

It is also a very simple thing to integrate SLF4J and log framework.

SLF4J+JDKLog

SLF4J + JDKLog needs to import the following dependent packages in Maven:

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.7.21</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-jdk14</artifactId>
  <version>1.7.21</version>
</dependency>

Write test class:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
/****
 ** SLF4J + JDKLog
 **/
public class Slf4jJDKLog {
    final static Logger logger = LoggerFactory.getLogger(Slf4jJDKLog.class);
    public static void main(String[] args) {
        logger.trace("Trace Level.");
        logger.info("Info Level.");
        logger.warn("Warn Level.");
        logger.error("Error Level.");
    }
}

Output results:

July 15, 2016 3:30:02 afternoon com.chanshuyi.slf4j.Slf4jJDKLog main
 information: Info Level.
July 15, 2016 3:30:02 afternoon com.chanshuyi.slf4j.Slf4jJDKLog main
 warning: Warn Level.
July 15, 2016 3:30:02 afternoon com.chanshuyi.slf4j.Slf4jJDKLog main
 serious: Error Level.

SLF4J+LOG4J

Jar packages to rely on: slf4j-api.jar, slf4j-412.jar, log4j.jar. Import Maven dependencies:

<!-- 2.SLF4J + Log4J -->
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.7.21</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
  <version>1.7.21</version>
</dependency>
<dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>1.2.17</version>
</dependency>

Configure log4j.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
 
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/' >
 
    <appender name="myConsole" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern"
                   value="[%d{dd HH:mm:ss,SSS\} %-5p] [%t] %c{2\} - %m%n" />
        </layout>
        <!--Filter sets the level of output-->
        <filter class="org.apache.log4j.varia.LevelRangeFilter">
            <param name="levelMin" value="debug" />
            <param name="levelMax" value="error" />
            <param name="AcceptOnMatch" value="true" />
        </filter>
    </appender>
 
    <!-- root logger Settings for-->
    <root>
        <priority value ="debug"/>
        <appender-ref ref="myConsole"/>
    </root>
</log4j:configuration>

We still use the above code without change. The running result is:

[15 16:04:06,371 DEBUG] [main] slf4j.SLF4JLog - Debug Level.
[15 16:04:06,371 INFO ] [main] slf4j.SLF4JLog - Info Level.
[15 16:04:06,371 WARN ] [main] slf4j.SLF4JLog - Warn Level.
[15 16:04:06,371 ERROR] [main] slf4j.SLF4JLog - Error Level.

SLF4J+LogBack

Import dependency:

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.7.21</version>
</dependency>
<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>1.1.7</version>
</dependency>
<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-core</artifactId>
  <version>1.1.7</version>
</dependency>

Configure the logback.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
        </layout>
    </appender>
    <logger name="com.chanshuyi" level="TRACE"/>
 
    <root level="warn">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

We still use the above code without change. The running result is:

16:08:01.040 [main] TRACE com.chanshuyi.slf4j.SLF4JLog - Trace Level.
16:08:01.042 [main] DEBUG com.chanshuyi.slf4j.SLF4JLog - Debug Level.
16:08:01.043 [main] INFO  com.chanshuyi.slf4j.SLF4JLog - Info Level.
16:08:01.043 [main] WARN  com.chanshuyi.slf4j.SLF4JLog - Warn Level.
16:08:01.043 [main] ERROR com.chanshuyi.slf4j.SLF4JLog - Error Level.

LogBack log framework

After the above introduction, I believe you have a certain understanding of the logging framework commonly used in Java.

So which logging framework is suitable for practical use?

According to the author's understanding, the most streaming log framework solution is SLF4J + LogBack. The reasons are as follows:

  • LogBack implements the log interface of SLF4J, and SLF4J is not required for further adaptation.
  • LogBack itself is optimized on the basis of log4j, and its running speed and efficiency are higher than log4j.
  • SLF4J + LogBack supports placeholders to facilitate the reading of log codes, while LOG4J does not.

From the above points, SLF4J + LogBack is a better choice.

LogBack is divided into three components: LogBack core, LogBack classic and LogBack access.

  • logback-core   Provides the core functions of LogBack, which is the basis of the other two components.
  • logback-classic   It implements the API of SLF4J, so when you want to use it with SLF4J, you need to introduce logback classic into the dependency.
  • logback-access   It is prepared to integrate the Servlet environment and provides a log interface of HTTP access.

The logging data flow of LogBack is from Class (Package) to Logger, then from Logger to Appender, and finally from Appender to specific output terminal.

The LogBack Configuration file can be divided into several nodes, in which Configuration is the Root node and Appender, Logger and Root are the child nodes of Configuration.

appender node

Yes, it is a child node of the. It is a component responsible for writing logs. The appender has two required attributes: name and class. Name specifies the name of the appender, and class specifies the fully qualified name of the appender
class, mainly including:

  • ch.qos.logback.core.ConsoleAppender console output
  • ch.qos.logback.core.FileAppender file output
  • ch.qos.logback.core.RollingFileAppender file scrolling output
<?xml version="1.0" encoding="utf-8"?> 
<configuration debug="true" scan="true" scanPeriod="2">
    <!-- conf consoel out -->
    <appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
    </appender>

    <!-- conf file out -->
    <appender name="file_out" class="ch.qos.logback.core.FileAppender">
    </appender>
    
    <!-- conf file out -->
    <appender name="file_out" class="ch.qos.logback.core.RollingFileAppender">
    </appender>

    <root></root>
    <logger></logger>
</configuration>

ConsoleAppender

Add the log to the console. There are the following nodes:

  • <encoder>  : Format the log.
  • <target>  : String System.out or System.err, default System.out;
<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <!-- conf consoel out -->
  <appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%date [%thread] %-5level %logger - %message%newline</pattern>
        </encoder>
  </appender>

  <root level="INFO">             
    <appender-ref ref="console_out" />   
  </root>     
</configuration>

FileAppender

Add the log to the file. There are the following nodes:

  • < File >: the file name to be written can be a relative directory or an absolute directory. If the directory does not exist, it will be created automatically.
  • < append >: if true, the log will be appended to the end of the file. If false, the existing file will be cleared. The default is true.
  • < encoder >: format the log [please refer to the official website for specific description of conversion characters.]
<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <appender name="file_out" class="ch.qos.logback.core.FileAppender">
        <file>logs/debug.log</file>
        <encoder>
            <pattern>%date [%thread] %-5level %logger - %message%newline</pattern>
        </encoder>
    </appender>
</configuration>

rollingFileAppender

Rolling record file: first record the log to the specified file. When certain conditions are met, record the log to other files. There are the following nodes:

  • < File >: the written file name can be a relative directory or a directory. If the directory does not exist, it will be created automatically.
  • < append >: if true, the log will be appended to the end of the file. If false, the existing file will be cleared. The default is true.
  • < encoder >: format the log.
  • < rollingpolicy >: determines the behavior of RollingFileAppender when scrolling occurs, involving file movement and renaming.

rollingPolicy

  • TimeBaseRollingPolicy: the most commonly used rollingpolicy. The rollingpolicy is formulated according to time, that is, it is responsible for scrolling and triggering scrolling. There are the following nodes:;

    • < filenamepattern >: required node, including file and "% d" converter, ""% d "can contain a time format formulated by java.text.SimpleDateFormat, such as:% d {yyyy MM}. If% d is used directly, the default format is yyyy - MM - dd.
    • < maxhistory >: optional node, which controls the maximum number of archived files to be retained. If the number exceeds, the old files will be deleted. It is assumed that monthly rolling is set, and   If it is 6, only the files of the last 6 months will be saved, and the old files before will be deleted. Note: the directories created for archiving will also be deleted.
    • < filenamepattern >: must contain "% I". For example, set the minimum and maximum values to 1 and 2 respectively, and the naming mode to log%i.log, which will generate archive files log1.log and log2.log. You can also specify file compression options, such as log%i.log.gz or log%i.log.zip
  • Triggingpolicy: tells RollingFileAppender to activate RollingFileAppender scrolling.

<!-- 03:conf errorAppender out -->
<appender name="errorAppender" class="ch.qos.logback.core.RollingFileAppender">
    <file>logs/error.log</file>
    <!-- Set scrolling policy -->
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
        <!--Set log naming mode--> 
        <fileNamePattern>errorFile.%d{yyyy-MM-dd}.log</fileNamePattern>
        <!--Up to 30 days log-->
        <maxHistory>30</maxHistory>
    </rollingPolicy>
    <!-- Over 150 MB The scrolling strategy is triggered when -->
    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
        <maxFileSize>150</maxFileSize>
    </triggeringPolicy>
    <encoder>
        <pattern>%d [%p] %-5level %logger - %msg%newline</pattern>
    </encoder>
</appender>

logger node

logger is a child node of to set the log printing level of a package or a specific class, and specify. logger has only one name attribute and two optional attributes level / addtivity.

  • name: used to specify a package or a specific class constrained by this logger.
  • Level: used to set the printing level, regardless of case. The optional values are TRACE, DEBUG, INFO, WARN, ERROR, ALL and OFF. There is also a special value of INHERITED or the synonym NULL, which represents the level at which the superior is enforced. If this property is not set, the current logger inherits the level of the parent.
  • addtivity: whether to pass print information to the superior logger. The default value is true;

It can contain zero or more elements, indicating that this appender will be added to the logger.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <!-- conf consoel out -->
    <appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!-- Filter out non INFO level -->
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!--  conf infoAppender out -->
    <appender name="infoAppender" class="ch.qos.logback.core.RollingFileAppender">
        <file>logs/info.log</file>
        <!-- Set scrolling policy -->
        <rollingPoliy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <!--Set log naming mode--> 
            <fileNamePattern>infoFile.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!--Up to 30 days log-->
            <maxHistory>30</maxHistory>
        </rollingPoliy>
        <!-- Over 150 MB The scrolling strategy is triggered when -->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <maxFileSize>150</maxFileSize>
        </triggeringPolicy>
        <encoder>
            <pattern>%d [%p] %-5level %logger - %msg%newline</pattern>
        </encoder>
    </appender>
 
    <!-- Add two appender node -->
    <logger name="logback.olf.log" level="info">
        <appender-ref ref = "console_out"/>
        <appender-ref ref = "infoAppender"/>
    </logger>
</configuration>

root node

Element to configure the root logger. This element has a level attribute and no name attribute because it has been named root. The value of the level property is case independent, and its value is one of the following strings: TRACE, DEBUG, INFO, WARN, ERROR, ALL and OFF. If the root element does not reference any Appenders, ALL Appenders will be lost.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <!-- conf consoel out -->
    <appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!-- Filter out non INFO level -->
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 01:conf infoAppender out -->
    <appender name="infoAppender" class="ch.qos.logback.core.RollingFileAppender">
        
        <file>logs/info.log</file>
        <!-- Set scrolling policy -->
        <rollingPoliy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <!--Set log naming mode--> 
            <fileNamePattern>infoFile.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!--Up to 30 days log-->
            <maxHistory>30</maxHistory>
        </rollingPoliy>
        <!-- Over 150 MB The scrolling strategy is triggered when -->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <maxFileSize>150</maxFileSize>
        </triggeringPolicy>
        <encoder>
            <pattern>%d [%p] %-5level %logger - %msg%newline</pattern>
        </encoder>
    </appender>

    <!-- 02:conf debugAppender out -->
    <appender name="debugAppender" class="ch.qos.logback.core.RollingFileAppender">
        <file>logs/debug.log</file>
        <!-- Set scrolling policy -->
        <rollingPoliy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <!--Set log naming mode--> 
            <fileNamePattern>debugFile.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!--Up to 30 days log-->
            <maxHistory>30</maxHistory>
        </rollingPoliy>
        <!-- Over 150 MB The scrolling strategy is triggered when -->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <maxFileSize>150</maxFileSize>
        </triggeringPolicy>
        <encoder>
            <pattern>%d [%p] %-5level %logger - %msg%newline</pattern>
        </encoder>
    </appender>

    <!-- 03:conf errorAppender out -->
    <appender name="errorAppender" class="ch.qos.logback.core.RollingFileAppender">
        <file>logs/error.log</file>
        <!-- Set scrolling policy -->
        <rollingPoliy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <!--Set log naming mode--> 
            <fileNamePattern>errorFile.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!--Up to 30 days log-->
            <maxHistory>30</maxHistory>
        </rollingPoliy>
        <!-- Over 150 MB The scrolling strategy is triggered when -->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <maxFileSize>150</maxFileSize>
        </triggeringPolicy>
        <encoder>
            <pattern>%d [%p] %-5level %logger - %msg%newline</pattern>
        </encoder>
    </appender>
 
    <root level="ALL">
        <appender-ref ref="infoAppender"/>
        <appender-ref ref="debugAppender"/>
        <appender-ref ref="errorAppender"/>
    </root>
</configuration>

Filter filter node

Level filter

LevelFilter filters recorded events according to the record level. If the level of the event is equal to the configured level, the filter accepts or rejects the event according to the onMatch and onMismatch properties. Here is an example of a configuration file:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <!-- conf consoel out -->
    <appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!-- Filter out non INFO level -->
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        
        <encoder>
            <pattern>%-4relative [%thread] %-5level %logger{30} - %msg%n</pattern>
        </encoder>
    </appender>
    <root level="DEBUG">
        <appender-ref ref="console_out" />
    </root>
</configuration>

Threshold filter

ThresholdFilter filters out events below the specified threshold.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <!-- conf consoel out -->
    <appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">  
        <!-- Filter out TRACE and DEBUG Level log -->
            <level>INFO</level> 
        </filter>
        
        <encoder>
            <pattern>%-4relative [%thread] %-5level %logger{30} - %msg%n</pattern>
        </encoder>
    </appender>
    <root level="DEBUG">
        <appender-ref ref="console_out" />
    </root>
</configuration>

Evaluator filter

Evaluate whether the specified conditions are met

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <!-- conf consoel out -->
    <appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.EvaluatorFilter">  
             <evaluator>
             <!--Filter out all logs that do not contain hello Character log-->
                <expression>
                    message.contains("hello")
                </expression>
                <onMatch>NEUTRAL</onMatch>
                <onMismatch>DENY</onMismatch>
             </evaluator>
        </filter>
        
        <encoder>
            <pattern>%-4relative [%thread] %-5level %logger{30} - %msg%n</pattern>
        </encoder>
    </appender>
    <root level="DEBUG">
        <appender-ref ref="console_out" />
    </root>
</configuration>

Matchers

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <!-- conf consoel out -->
    <appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.EvaluatorFilter">  
             <evaluator> 
                <matcher>
                    <Name>odd</Name>
                    <!-- Filter out statements with odd sequence numbers-->
                    <regex>statement [13579]</regex>
                </matcher>
                <expression>odd.matches(formattedMessage)</expression>
                <onMatch>NEUTRAL</onMatch>
                <onMismatch>DENY</onMismatch>
             </evaluator>
        </filter>
        
        <encoder>
            <pattern>%-4relative [%thread] %-5level %logger{30} - %msg%n</pattern>
        </encoder>
    </appender>
    <root level="DEBUG">
        <appender-ref ref="console_out" />
    </root>
</configuration>

The following is a commonly used logback.xml configuration file for your reference:

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

<configuration debug="true" scan="true" scanPeriod="30 seconds"> 

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> 
    <!-- encoders are  by default assigned the type
         ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
    <encoder>
        <pattern>%d{yyyy-MM-dd HH:mm:ss} [%level] - %m%n</pattern>
        
        <!-- frequently-used Pattern variable,You can open the pattern Perform output observation -->
        <!-- 
          <pattern>
              %d{yyyy-MM-dd HH:mm:ss} [%level] - %msg%n
              Logger: %logger
              Class: %class
              File: %file
              Caller: %caller
              Line: %line
              Message: %m
              Method: %M
              Relative: %relative
              Thread: %thread
              Exception: %ex
              xException: %xEx
              nopException: %nopex
              rException: %rEx
              Marker: %marker
              %n
              
          </pattern>
           -->
    </encoder>
  </appender>
  
  <!-- Rolling log by date -->
  <appender name="ERROR-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <file>logs/error.log</file>
      
    <encoder>
        <pattern>%d{yyyy-MM-dd HH:mm:ss} [%class:%line] - %m%n</pattern>
    </encoder>
      
      <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>ERROR</level>
      <onMatch>ACCEPT</onMatch>
      <onMismatch>DENY</onMismatch>
    </filter>
      
      <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <!-- daily rollover -->
      <fileNamePattern>error.%d{yyyy-MM-dd}.log.zip</fileNamePattern>

      <!-- keep 30 days' worth of history -->
      <maxHistory>30</maxHistory>
    </rollingPolicy>
  </appender>
  
  <!-- Scrolling logs by file size -->
  <appender name="INFO-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <file>logs/info.log</file>
      
    <encoder>
        <pattern>%d{yyyy-MM-dd HH:mm:ss} [%class:%line] - %m%n</pattern>
    </encoder>
    
      <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>INFO</level>
      <onMatch>ACCEPT</onMatch>
      <onMismatch>DENY</onMismatch>
    </filter>
      
      <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
      <fileNamePattern>info.%i.log</fileNamePattern>
      <minIndex>1</minIndex>
      <maxIndex>3</maxIndex>
    </rollingPolicy>
    
    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
      <maxFileSize>5MB</maxFileSize>
    </triggeringPolicy>
    
  </appender>
  
  
  <!-- Rolling logs by date and case -->
  <appender name="DEBUG-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <file>logs/debug.log</file>

    <encoder>
        <pattern>%d{yyyy-MM-dd HH:mm:ss} [%class:%line] - %m%n</pattern>
    </encoder>
      
      <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>DEBUG</level>
      <onMatch>ACCEPT</onMatch>
      <onMismatch>DENY</onMismatch>
    </filter>
      
      <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <!-- rollover daily -->
      <fileNamePattern>debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
      
      <timeBasedFileNamingAndTriggeringPolicy
            class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
        <!-- or whenever the file size reaches 100MB -->
        <maxFileSize>100MB</maxFileSize>
      </timeBasedFileNamingAndTriggeringPolicy>
      
    </rollingPolicy>
    
  </appender>
  
  
   <!-- Level threshold filtering -->
  <appender name="SUM-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <file>logs/sum.log</file>

    <encoder>
        <pattern>%d{yyyy-MM-dd HH:mm:ss} [%class:%line] - %m%n</pattern>
    </encoder>
      
    <!-- deny all events with a level below INFO, that is TRACE and DEBUG -->
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
      <level>INFO</level>
    </filter>

      
      <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <!-- rollover daily -->
      <fileNamePattern>debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
      
      <timeBasedFileNamingAndTriggeringPolicy
            class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
        <!-- or whenever the file size reaches 100MB -->
        <maxFileSize>100MB</maxFileSize>
      </timeBasedFileNamingAndTriggeringPolicy>
      
    </rollingPolicy>
    
  </appender>
  
  
  <root level="debug">
    <appender-ref ref="STDOUT" />
    <appender-ref ref="ERROR-OUT" />
    <appender-ref ref="INFO-OUT" />
    <appender-ref ref="DEBUG-OUT" />
    <appender-ref ref="SUM-OUT" />
  </root>
</configuration>

How to perform log system conversion?

In the actual log conversion process, SLF4J actually acts as an intermediary. For example, when we use LOG4J for logging in a project, we need to change LogBack for logging.

At this time, we need to convert LOG4J into SLF4J log system, and then from SLF4J log system to LogBack log system.

From log frame to SLF4J

  • jul-to-slf4j: bridge from JDK logging to slf4j
  • Log4j over slf4j: bridge from log4j1 to slf4j
  • JCL over slf4j: a bridge from commons logging to slf4j

Shift from SLF4J to specific log framework

  • slf4j-jdk14: bridge from slf4j to JDK logging
  • slf4j-log4j12: bridge from slf4j to log4j1
  • Log4j slf4j impl: bridge from slf4j to log4j2
  • Logback classic: slf4j the bridge to logback
  • Slf4j JCL: bridge from slf4j to commons logging

For example, we first used the Log4J logging framework. Now we want to convert to the LogBack framework. First, we need to add log4j-over-slf4j.jar to convert Log4J to SLF4J, and then add logback-classic.jar to convert SLF4J to LogBack.

List of log technology framework

  • JUL: the logging tool in JDK, also known as JDKLog and JDK logging.
  • LOG4J1: a specific log implementation framework.
  • LOG4J2: a specific log implementation framework, which is the next version of LOG4J1.
  • Logpack: a specific log implementation framework, but its performance is better.
  • JCL: a log facade that provides a unified logging interface, also commonly known as common logging.
  • SLF4J: a log facade. Like JCL, it provides a unified log recording interface, which can be easily switched to see the specific implementation framework.

JUL, LOG4J1, LOG4J2 and logpack are the log implementation framework, while JCL and SLF4J are the log implementation facade

Topics: Java Apache Programmer