java log framework JUL, JCL, Slf4j, Log4j, Log4j2, Logback

Posted by vinny199 on Wed, 22 Dec 2021 21:33:15 +0100

Why does the program need to log

It is impossible for us to manually monitor the system 24 hours in real time, so how to check if there are abnormal errors in the program? And how do we know what the system does when it runs? At this time, the concept of log appears. The emergence of log plays a vital role in system monitoring and exception analysis;

Take java as an example. In the early days, logs were recorded through system out. Println () records, but this method is not easy to manage, so apache first developed the first logging framework: log4j; It lays the foundation for the log framework;

The historical sequence of log frames is: log4j → JUL → JCL → SLF4J → logback → log4j2

java log framework classification

Log implementation

  1. JUL (java.util.logging): java's own logging framework is suitable for small projects
  2. Logback: a popular framework at present, spring 2 0 uses logback logs by default
  3. log4j: an old log framework under apache
  4. log4j2: log4j upgrade, the best log implementation technology at present

Log facade interface

  1. JCL (jakarta commons Logging): under apache
  2. slf4j (simple logging facade for java): it is popular at present

JUL java.util.logging -- Java's own logging framework

JUL log level

JUL has 7 log levels. The usage is as follows:

logger.(Level.INFO,"info");
  1. Level. Sever: the highest level log, which mainly records error information
  2. Level.WARNING: the second highest level, recording warning information
  3. Level.INFO: the third level, the most commonly used log level, records common messages, such as request information, connection information, parameter information, etc
  4. Level.CONFIG: the fourth highest level. You can use CONFIG to record configuration information, load configuration files and read configuration parameters
  5. Level.FINE: log messages recorded during debug, recording the running state, parameters passed, etc
  6. Level. Filter: log messages recorded during debug, recording the running state, parameters passed, etc
  7. Level.FINEST: log messages recorded during debug, recording the running state, parameters passed, etc
  8. Level.ALL: all records are turned on
  9. Level.OFF: turn off logging

Among them, FINE, FINER and FINEST all record debug information, and one of the three can be selected;

JUL principle

  1. The Logger is used to record logs,
  2. LogRecord is used to deliver logs,
  3. Handler is used to export (process) logs,
  4. Level is used to define the log level (control log output),
  5. Filter provides finer grained control beyond the log level,
  6. Formatter is used to format LogRecord,
  7. In addition, there is a single global LogManager to maintain loggers and manage logs. JUL is mainly composed of these seven core classes or interfaces, and some subclasses or implementation classes. The detailed description of the classes and methods of these classes or interfaces in the API will not be repeated here. Now that we have an overall understanding of JUL and a preliminary understanding of the functions and responsibilities of core classes or interfaces, we should take a look at the true face of JUL in combination with the code.

JUL configuration file details

Create a new file named logging Properties, the contents are as follows. The following configurations can be output to the console and files at the same time

#Specify the default processor for the top-level parent element RootLogger: ConsoleHandler, that is, if you do not have a custom Logger, use this Logger
handlers=java.util.logging.ConsoleHandler
#The default log level of the top-level parent element is INFO, that is, the log level of this Logger is INFO
.level=INFO 
#Customize the Logger, that is, the name of the Logger is com Yexindong, when called, so that Logger = Logger getLogger("com.yexindong");
#Specify the handlers of the custom Logger. ConsoleHandler is output to the console and FileHandler is output to a file. If both are specified, they can be output at the same time;
com.yexindong.handlers=java.util.logging.ConsoleHandler, java.util.logging.FileHandler
#Specifies the log level of the custom Logger
com.yexindong.level=INFO
#Turn off default configuration
com.yexindong.useParentHandlers=false

#*******************handler object output to file start*******************
#Specifies the path to the log file output
java.util.logging.FileHandler.pattern=D:\\ying.log
#Specifies the size of the file contents in bytes (b)
java.util.logging.FileHandler.limit=50000
#Specifies the number of log files
java.util.logging.FileHandler.count=10
#Specify the format of the log file,
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
#Specifies that the log content is added by appending
java.util.logging.FileHandler.append=true
#*******************handler object end output to file*******************

#*******************handler object start output to console*****************
#Specify the log level. Try to be the same as the customized level. Otherwise, some logs will not be printed
java.util.logging.ConsoleHandler.level=INFO
#Specifies the format of the log
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
#Specifies the encoding of the log
java.util.logging.ConsoleHandler.encoding=UTF-8
#*******************handler object end output to console*****************
#Specifies the format of the log message
java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %2$s %5$s%6$s%n

log4j

An important defect of log4j is that it does not support placeholders, but users can define and implement the functions of placeholders themselves,

log4j log level

The default log level of log4j is debug;

  1. logger.fatal(info): record serious error information, which will generally cause the system to crash and terminate the operation
  2. logger.error(info): records the error information and will not affect the system operation
  3. logger.warn(info): log warning information
  4. logger.info(info): record operation information,
  5. logger.debug(info): (default) records the mode information, which is generally used in development
  6. logger.trace(info): record the tracking information and the process information of the program;

Appenders

Appenders · is used to specify where the log will be output. You can also specify the output destination of the log. log4j commonly used Appenders are as follows

Output typeeffect
ConsoleAppenderOutput log to console
FileAppenderOutput log to file
DailyRollingFileAppenderOutput the log to a log file, and output to a new file every day
RollingFileAppenderOutput the log information to a log file and specify the file size. When the file size reaches the specified size, the file will be renamed automatically and a new file will be generated at the same time;
JDBCAppenderSave the log information to the database

layouts

The layout is used to control the format of log output, so that we can customize the log format. log4j commonly used layouts are as follows

Formattereffect
HTMLLayoutFormat the log in html form
XMLLayoutFormat the log as an xml document
SimpleLayout(default) simple log output format. The printed log format is (info - message)
PatternLayoutThe most powerful formatter can output the log according to the custom format. If the conversion format is not specified, the default format only displays the message content;
PatternLayout format syntax
parameterexplaingive an example
%mOutput the log information specified in the codelogger. Info (log information)
%pOutput log levelINFO, DEBUG and error%-8p indicate that 8 characters are occupied. If the characters are not enough, replace them with spaces
%nNewline characterYou must add a newline at the end, or the log will be messy
%rOutput the number of milliseconds spent from application startup to outputting the log information(log print time - application start time)
%cOutput the full name of the class to which the print statement belongs%c : com.xd.App %c{1}: App
%CLists the full name of the class calling logger (including the package path)%C : com.xd.App %C{1}: App
%tOutput the name of the thread where the log is generatedmain ,thread-0,thread-1
%dOutput the current time of the server, accurate to seconds,Custom format 1,% d: 2021-12-16 16:05:07201 2,% d{yyyy MM DD HH: mm: SS}: 2021-12-16 16:05:07
%lThe location where the output log occurs, including package name, class name, method name and the code line treecom.log.App.haveConfigFile(App.java:25)
%LLine number in output code12
%FDisplays the file name of the class calling loggerApp.class
%%Output a percent sign%%

log4j2

apache log4j2 is an upgrade class for log4j. It refers to some excellent designs of logback and fixes some problems in the logback system. Therefore, it has brought some significant improvements, mainly including the following points

  1. Exception handling: in logback, exceptions in the appender will not be perceived by the application, but log4j 2 provides some exception handling mechanisms
  2. Performance improvement: log2j has a significant performance improvement over log4j and logback. The official data is 18 times higher
  3. Automatic overload configuration refers to the design of logback and provides the configuration of automatic refresh parameters. In production, the log level can be dynamically modified without restarting the application;
  4. No garbage mechanism, (enabled by default) log4j2 can use no garbage mechanism in most cases to avoid the garbage collection mechanism that triggers the jvm due to frequent log collection;

log4j2 asynchronous logging principle

  1. After the main thread of the application calls the method of printing the log, it is passed to the logEvent object
  2. event adds the object to an ArrayBlockingQueue
  3. At this point, the work of the main thread has been completed, and the rest of the work can be handed over to the log asynchronous thread
  4. After receiving the log message, the ArrayBlockingQueue immediately sends the message to the appender object
  5. After receiving the message, the appender starts printing and outputting the message;

Build log4j2 facade + log4j2 implementation

Add dependency

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

java code

package com;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
//Use log4j as facade
public class Log4j2App {
    public static void main(String[] args) {
        Logger logger = LogManager.getLogger(Log4j2App.class);
        logger.fatal("max error");
        logger.error("error");
        logger.warn("warn");
        logger.info("info");
        logger.debug("debug");
        logger.trace("trace");
        
    }
}

Configuration file log4j2 xml

<?xml version="1.0" encoding="UTF-8"?>
<!--Log level and prioritization: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration hinder status,This is used to set log4j2 The internal information output can not be set when it is set to trace You'll see log4j2 Various internal detailed outputs-->
<!--monitorInterval: Log4j It can automatically detect and modify the configuration file and reconfigure itself, and set the interval seconds-->
<configuration status="WARN" monitorInterval="30">

    <properties>
        <!--        Configure global variables by: ${name} obtain-->
        <property name="LOG_PATH">D:\\log\\</property>
        <property name="pattern_format">[%d{HH:mm:ss:SSS}] [%-5p] - %l -- %m%n</property>
    </properties>
    <!--Define all first appender-->
    <appenders>
        <!--Output configuration of console-->
        <console name="Console" target="SYSTEM_OUT">
            <!--Format of output log-->
            <PatternLayout pattern="${pattern_format}"/>
        </console>

        <!--The file will print out all the information, this log The program will be emptied automatically every time it is run, and the append Attribute decision, which is also very useful and suitable for temporary testing-->
        <File name="log" fileName="${LOG_PATH}/log4j2_all.log" append="false">
            <PatternLayout pattern="${pattern_format}"/>
        </File>
        <!--    RandomAccessFile Using random read-write stream to output log to file, with high performance    -->
        <RandomAccessFile name="file" fileName="${LOG_PATH}/randomAccessFile.log">
            <PatternLayout pattern="${pattern_format}"/>
        </RandomAccessFile>
        <!--        RollingFile Split files according to certain rules-->
        <!-- This will print out all the information info And below, each time the size exceeds size,Then this size Logs of size are automatically saved by year-The folder created in the month is compressed as an archive-->
        <RollingFile name="RollingFileInfo" fileName="${LOG_PATH}/info_low.log"
                     filePattern="${LOG_PATH}/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log">
            <!--Console output only level And above( onMatch),Other direct rejection( onMismatch)-->
            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${pattern_format}"/>
            <Policies>
                <!--                When the system starts or restarts, the split rule is triggered to generate a new log file-->
                <OnStartupTriggeringPolicy/>
                <!--                Split nodes according to time filePattern Defined rule split-->
                <TimeBasedTriggeringPolicy/>
                <!--                Split by file size-->
                <SizeBasedTriggeringPolicy size="100 KB"/>
            </Policies>
            <!--    In the same directory, the number of log files is limited to 30, and more than 30 will be overwritten. This configuration can effectively prevent too large log files from causing insufficient disk space;        -->
            <DefaultRolloverStrategy max="30"/>
        </RollingFile>
        <!--  Print only info Level information-->
        <RollingFile name="RollingFileInfo" fileName="${LOG_PATH}/info.log"
                     filePattern="${LOG_PATH}/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log">
            <!--Console output only info Level information-->
            <filters>
                <!--
                onMismatch="NEUTRAL" Indicates the level and below, by the next filter Processing. If the current is the last one, it does not match those below this level
                onMatch="DENY" Indicates that the level and above do not match
                -->
                <ThresholdFilter level="warn" onMatch="DENY" onMismatch="NEUTRAL"/>
                <!--
                onMatch="ACCEPT" Indicates matching this level and above
                onMismatch="DENY" Indicates a mismatch below this level
                -->
                <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
            </filters>

            <PatternLayout pattern="${pattern_format}"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="100 KB"/>
            </Policies>
        </RollingFile>
        <!--        Print only warn Level information and automatically archive it-->
        <RollingFile name="RollingFileWarn" fileName="${LOG_PATH}/warn.log"
                     filePattern="${LOG_PATH}/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log">
            <!--   Print only warn Level log-->
            <filters>
                <ThresholdFilter level="error" onMatch="DENY" onMismatch="NEUTRAL"/>
                <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
            </filters>
            <PatternLayout pattern="${pattern_format}"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="100 KB"/>
            </Policies>
            <!-- DefaultRolloverStrategy If the property is not set, it defaults to up to 7 files in the same folder. Here, 20 files are set -->
            <DefaultRolloverStrategy max="20"/>
        </RollingFile>
        <!--        Print error Information above level-->
        <RollingFile name="RollingFileError" fileName="${LOG_PATH}/error.log"
                     filePattern="${LOG_PATH}/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log">
            <!--            Print only error Level log-->
            <filters>
                <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
            </filters>
            <PatternLayout pattern="${pattern_format}"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="100 KB"/>
            </Policies>
        </RollingFile>

<!--    Archive every day and automatically compress log files   -->
        <RollingRandomAccessFile name="applicationAppender" fileName="${LOG_PATH}/rollingRandomAccessFile.log"
                                 filePattern="${LOG_PATH}/$${date:yyyy-MM}/common-%d{yyyy-MM-dd}.log.gz"
                                 append="true">
            <PatternLayout pattern="${pattern_format}"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
            </Policies>
        </RollingRandomAccessFile>
    </appenders>
    <!--Then define logger,Only defined logger And introduced appender,appender Will take effect-->
    <loggers>
        <!--Filter out spring and mybatis Some useless DEBUG information-->
        <logger name="org.springframework" level="INFO"></logger>
        <logger name="org.mybatis" level="INFO"></logger>
        <root level="all">
            <!-- appender quote-->
            <appender-ref ref="Console"/>
            <appender-ref ref="log"/>
            <appender-ref ref="RollingFileInfo"/>
            <appender-ref ref="RollingFileWarn"/>
            <appender-ref ref="RollingFileError"/>
        </root>
    </loggers>
</configuration>

Run the above java code and print the log as follows

[21:10:17:717] [FATAL] - com.Log4j2App.main(Log4j2App.java:15) -- max error
[21:10:17:717] [ERROR] - com.Log4j2App.main(Log4j2App.java:16) -- error
[21:10:17:717] [WARN ] - com.Log4j2App.main(Log4j2App.java:17) -- warn
[21:10:17:717] [INFO ] - com.Log4j2App.main(Log4j2App.java:18) -- info
[21:10:17:717] [DEBUG] - com.Log4j2App.main(Log4j2App.java:19) -- debug
[21:10:17:717] [TRACE] - com.Log4j2App.main(Log4j2App.java:20) -- trace

Build slf4j facade + log4j2 implementation

Add pom dependency

<!--        slf4j Facade-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.30</version>
        </dependency>
<!--        slf4j And log4j2 Bridging package for: log4j-slf4j-impl-2.9.0.jar,The purpose of this package is to use slf4j of api,But the underlying implementation is based on log4j2.-->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>2.9.0</version>
        </dependency>


        <!--        log4j Facade, this is also needed-->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.15.0</version>
        </dependency>
        <!--        log4j2 rely on-->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.15.0</version>
        </dependency>
        <!--    log4j2 Asynchronous log dependency. If the asynchronous function is not used, this package can be omitted-->
        <dependency>
            <groupId>com.lmax</groupId>
            <artifactId>disruptor</artifactId>
            <version>3.3.4</version>
        </dependency>

java code

package com;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * Use Slf4j as facade
 */
public class Log4j2_Slf4j_App {
    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(Log4j2_Slf4j_App.class);
        logger.error("error");
        logger.warn("warn");
        logger.info("info");
        logger.debug("debug");
        logger.trace("trace");
    }
}

The configuration file still uses the original log4j2 XML is enough,

After executing the code, the print results are as follows

[11:20:56:866] [ERROR] - com.Log4j2_Slf4j_App.main(Log4j2_Slf4j_App.java:15) -- error
[11:20:56:866] [WARN ] - com.Log4j2_Slf4j_App.main(Log4j2_Slf4j_App.java:16) -- warn
[11:20:56:866] [INFO ] - com.Log4j2_Slf4j_App.main(Log4j2_Slf4j_App.java:17) -- info
[11:20:56:867] [DEBUG] - com.Log4j2_Slf4j_App.main(Log4j2_Slf4j_App.java:18) -- debug
[11:20:56:867] [TRACE] - com.Log4j2_Slf4j_App.main(Log4j2_Slf4j_App.java:19) -- trace

Asynchronous log

Asynchrony is divided into global asynchrony and hybrid asynchrony

  • Global asynchrony: all logs are recorded asynchronously
  • Hybrid asynchrony: synchronous log and asynchronous log are used in the application at the same time, so the log configuration is more flexible

Add maven dependency

<!--    log4j2 Asynchronous log dependency-->
<dependency>
    <groupId>com.lmax</groupId>
    <artifactId>disruptor</artifactId>
    <version>3.3.4</version>
</dependency>
Global asynchrony
  1. Globally enable asynchronous Logger scheme 1: JVM startup parameter plus - dlog4jcontextselector = org apache. logging. log4j. core. async. AsyncLoggerContextSelector
  2. Globally enable asynchronous Logger scheme 2: add the file log4j2. In the classpath component. Properties, add the following content to the file:
Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
Hybrid asynchronous

log4j2 provides two implementations of asynchronous logging

  • AsyncAppender: less performance improvement
  • Asyncloger: the performance is greatly improved. It is recommended

AsyncAppender configuration mode

<?xml version="1.0" encoding="UTF-8"?>
<configuration status="WARN" monitorInterval="30">
  <appender name="xindong_file" class="ch.qos.logback.core.FileAppender">
    <file>myapp.log</file>
    <encoder>
      <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%level] [%thread] [%logger{50}] >>> %msg%n</pattern>
    </encoder>
  </appender>
 
  <appender name="xindong_async" class="ch.qos.logback.classic.AsyncAppender">
    <appender-ref ref="xindong_file" />
  </appender>
 
  <root level="DEBUG">
    <appender-ref ref="xindong_async" />
  </root>
</configuration>

Asyncloger configuration mode

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="30">
    <Appenders>
        <RollingRandomAccessFile name="applicationAppender" fileName="./log/application.log"
                                 filePattern="./log/$${date:yyyy-MM}/common-%d{yyyy-MM-dd}.log.gz"
                                 append="false">
            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%p] - %l - %m%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
            </Policies>
        </RollingRandomAccessFile>

        <Console name="CONSOLE" target="SYSTEM_OUT">
            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%p] %t - %l - %m%n"/>
        </Console>


    </Appenders>

    <Loggers>
        <!-- AsyncLogger to configure -->
        <AsyncLogger name="log4j2" >
            <AppenderRef ref="applicationAppender"/>
        </AsyncLogger>

        <Root level="info">
            <!--<AppenderRef ref="CONSOLE"/>-->
            <AppenderRef ref="applicationAppender"/>
        </Root>

        <!--<Logger name="log4j2" level="debug" additivity="false" >-->
            <!--<AppenderRef ref="CONSOLE"/>-->
            <!--<AppenderRef ref="applicationAppender"/>-->
        <!--</Logger>-->

    </Loggers>
</Configuration>

logback

logback is another open source log component designed by the founder of log4j, with better performance than log4j;
logback is mainly divided into three modules

  1. Logback core: the basic module and core module of the other two modules
  2. Logback classic: it is an improved version of log4j, and it fully implements the slf4j API
  3. Logback access: the access module integrates with the servlet container to access logs through http;
logback default log level

The default log level of logback is debug;

logback profile

logback supports the following configuration files. If none of the following files exist, the default configuration file will be used;

  • logback.groovy
  • logback-test.xml
  • logback.xml

logback usage

First, import maven dependency. Here, slf4j is used to manage logback

<!-- Use log facade management logback-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.30</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>1.2.3</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>

java code

package com.log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LogbackApp {
    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(LogbackApp.class);
        logger.error("error");
        logger.info("123445");
        logger.debug("debug");
        logger.trace("trace");
        
    }
}

logback configuration file. The configuration here is relatively complete. Children's shoes can be configured as needed

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

    <!--    Configuration variables, and maven of properties Functional Hospital of label-->
    <property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%t] [%-5level] %c %M %L %m %n"></property>
    <property name="html_pattern" value="%d{yyyy-MM-dd HH:mm:ss}%t%-5level%c%M%L%m%n"></property>


    <!--    Output to console-->
    <appender name="yexindong_console_appender" class="ch.qos.logback.core.ConsoleAppender">
        <!--     Controls the output flow object. The default is System.out(Black font), System.err It's in red -->
        <!--        <target>System.err</target>-->
        <!-- Output log message format configuration-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--
            Log output format
            %-5level :  Log level, occupying a position of 5 characters
            %d{yyyy-MM-dd HH:mm:ss,SSS} : Date and specify format
            %c : The full name of the class
            %M :  Method name
            %L : Code line number
            %t :  call logger Of printing method thread Thread name
            %m :  Printed log content
            %n :  Line feed
            -->
            <pattern>${pattern}</pattern>
        </encoder>
    </appender>

    <!--    output to a file-->
    <!--    <appender name="yexindong_file_appender" class="ch.qos.logback.core.FileAppender">-->
            <!--        Log file save path-->
    <!--        <file>D:\\log\\logback.log</file>-->
            <!-- Output log message format configuration-->
    <!--        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">-->
    <!--            <pattern>${pattern}</pattern>-->
    <!--        </encoder>-->
    <!--    </appender>-->

    <!--    Output to html Log file in format-->
    <!--    <appender name="yexindong_html_appender" class="ch.qos.logback.core.FileAppender">-->
            <!--        Log file save path-->
    <!--        <file>D:\\log\\logback_html.html</file>-->
            <!--        html Message format configuration-->
    <!--        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">-->
    <!--            <layout class="ch.qos.logback.classic.html.HTMLLayout">-->
    <!--                <pattern>${html_pattern}</pattern>-->
    <!--            </layout>-->
    <!--        </encoder>-->
    <!--    </appender>-->

    <!--    Log splitting, automatic archiving and compression-->
    <appender name="yexindong_roll_file_appender" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--        Log file save path-->
        <file>D:\\log\\logback_rolling.log</file>
        <!-- Output log message format configuration-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>

        <!--        Specify file split rules-->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- Split the node by time and automatically compress the file name-->
            <fileNamePattern>D:\\log\\logback_rolling.%d{yyyy-MM-dd HH_mm_ss}.log%i.gz</fileNamePattern>
            <!--      Split according to the file size. When the file size reaches 1 MB The log is compressed when      -->
            <maxFileSize>1MB</maxFileSize>
        </rollingPolicy>
        <!--        Log level filter-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!-- Set the log level,-->
            <level>ERROR</level>
            <!--            Logs above this level will be printed-->
            <onMatch>ACCEPT</onMatch>
            <!--            Logs smaller than this level will not be printed-->
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!--    Asynchronous log, because each time the log is printed before, it is output in the main thread, which will affect the response speed. Configuring asynchronous log will improve the response speed-->
    <appender name="yexindong_async_appender" class="ch.qos.logback.classic.AsyncAppender">
        <!--        Here will be automatically archived appender Set to asynchronous-->
        <appender-ref ref="yexindong_roll_file_appender"></appender-ref>
    </appender>

    <!--root logger to configure-->
    <root level="All">
        <!--        appender quote-->
        <appender-ref ref="yexindong_console_appender"></appender-ref>
        <!--        <appender-ref ref="yexindong_file_appender"></appender-ref>-->
        <!--        <appender-ref ref="yexindong_html_appender"></appender-ref>-->
        <appender-ref ref="yexindong_async_appender"></appender-ref>
    </root>
    <!--
    custom logger object
    name="com" :  Here is com Is the package name, indicating com The classes of all sub packages under the package use custom logger
    level="info" : custom logger Log level for
    additivity="false" : Represents a custom logger Whether the object inherits rootLogger(root logger)
    -->
    <logger name="com" level="all" additivity="false">
        <appender-ref ref="yexindong_console_appender"></appender-ref>
    </logger>

</configuration>

After running, you can see the printed log content

2021-12-17 19:55:38 [main] [ERROR] com.log.LogbackApp main 13 error 
2021-12-17 19:55:38 [main] [INFO ] com.log.LogbackApp main 14 123445 
2021-12-17 19:55:38 [main] [DEBUG] com.log.LogbackApp main 15 debug 
2021-12-17 19:55:38 [main] [TRACE] com.log.LogbackApp main 16 trace 

Log facade Technology

What is log facade technology

The log facade technology draws on the idea of JDBC and provides a set of facade for the log system. Developers can develop for these interface specifications and avoid directly relying on specific log frameworks. Because different log frameworks have different usages, a large number of codes need to be changed when replacing the log framework. Therefore, in order to reduce the amount of development, With the log facade technology, the facade technology simply means that your log framework has changed, but you don't need to change the code, just modify the dependency and configuration files, which improves the development efficiency;

At present, there are two mainstream log facade technologies

  • JCL
  • SLF4J

Because JCL supports few logging technologies, it only supports the current mainstream logging framework and does not support extension. If you need to extend other logging implementation technologies, you need to modify the source code yourself. However, with the development of technology, more and better logging frameworks will be developed in the future, but JCL does not support these new frameworks, Therefore, JCL was eliminated by apache in 2014. At present, slf4j is the most widely used;

Why use facade technology?
  1. Interface oriented development does not rely on specific implementation classes and reduces code coupling
  2. The project can flexibly switch the log framework by importing different log implementation classes
  3. Unified API for developers to learn and use
  4. Unified configuration is convenient for project log management

Log facade technology - JCL

Log prioritization

jcl facade technology will obtain the implementation of logger in the following order when obtaining the log implementation. We can see that it gives priority to log4j. If it finds the implementation of log4j, it will not find other implementations

  1. Log4j: log4j is preferred
  2. jdk14Logger: jdk comes with a logger
  3. jdk13LumberjackLogger: it is also jdk's own logger
  4. SimpleLog: jcl's own logging framework, which has relatively simple functions
JCL usage
  1. First, add the pom dependency of apache facade
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>
  1. Print log
package com.log;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class App {
    public static void main(String[] args) {
        Log log = LogFactory.getLog(App.class);
        // jcl gives priority to log4j logging. If log4j dependency is not added, the logging framework provided by java will be used by default: java util. logging
        log.info("hello world");
    }
}
  1. The print results are as follows. It is found that the jdk's own log framework is used by default
December 17, 2021 11:34:22 morning com.log.App main
 information: hello world
  1. Next, we add the dependency of log4j
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
  1. Add the configuration file log4j Properties in the resources directory
# Configure the top-level parent element of log4j, specify the log level as trace, and use the appender as yexindong, which is user-defined
log4j.rootLogger=trace,yexindong
# ***********************Output to console start****************
# Specifies the appender for console log output
log4j.appender.yexindong=org.apache.log4j.ConsoleAppender
# Specify message layout
log4j.appender.yexindong.layout=org.apache.log4j.PatternLayout
# Specifies the message output format
log4j.appender.yexindong.layout.conversionPattern=%t %d [%t] %-5p %l -- %m %n
  1. Other codes remain unchanged. After running the main method again, the print results are as follows. You will find that log4j is automatically used to output the log;
main 2021-12-17 11:36:06,642 [main] INFO  com.log.App.main(App.java:17) -- hello world 

Log facade technology - SLF4J

Origin of SLF4J

After log4j was developed, log4j was loved by many developers and began to use log4j. However, later, the founder of log4j resigned from apache and started his own business because of some contradictions. In order to make a reputation for his company, the founder developed a new logging framework logback based on log4j, Logback is better than log4j in both performance and function, but few people use it. Because the jcl facade does not support logback, the creator designed slf4j, which supports all mainstream log frameworks on the market; So far, the most used is slf4j; Later, apache designed log4j2 logs based on the source code of logback. In terms of performance, log4j2 is better than logback, and log4j2 is both a log framework and a facade technology. However, few people use the facade technology of log4j2, and most of them still use slf4j;

matters needing attention

=In maven dependency, try to ensure that there is only one log implementation. If multiple logs are implemented, the first one (the one in front of maven dependency) is used by default, and the following warning message will be displayed on the console

# Prompt that there are multiple log implementations
SLF4J: Class path contains multiple SLF4J bindings.
# First log implementation
SLF4J: Found binding in [jar:file:/D:/repository/org/slf4j/slf4j-simple/1.7.25/ slf4j-simple-1.7.25.jar!/org/slf4j/impl/StaticLoggerBin
# The second log implementation
SLF4J: Found binding in [jar:file:/D:/repository/org/slf4j/slf4j-log4j12/1.7.12/slf4j-log4j12-1.7.12.jar!/org/slf4j/impl/StaticLoggerBinder.class]
# Default bind first
SLF4J: Actual binding is of type [org.slf4j.impl.SimpleLoggerFactory]
Prepare java print log code

First add slf4j's dependencies

   <!--        Log facade dependency-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.26</version>
        </dependency>

The log print code is as follows

package com.log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class App {
    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(App.class);
        logger.error("12322");
        logger.warn("warn");
        logger.info("info {}", "yexindong");
        logger.debug("debug");
        logger.trace("trace");
    }
}

At this time, the content will not be printed because there is only an interface and no specific implementation

1. slf4j binding default log

Slf4j simple is a simple log implementation framework built into slf4j, and its functions are relatively simple;

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>1.7.25</version>
</dependency>

After running the above java code, the console prints the following results

[main] ERROR com.log.App - 12322
[main] WARN com.log.App - warn
[main] INFO com.log.App - info yexindong
2. Binding java's own logging framework jul
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-jdk14</artifactId>
    <version>1.7.25</version>
</dependency>

After running the above java code, the console prints the following results

December 17, 2021 5:03:58 afternoon com.log.App main
 serious: 12322
 December 17, 2021 5:03:58 afternoon com.log.App main
 warning: warn
 December 17, 2021 5:03:58 afternoon com.log.App main
 information: info yexindong
3. Binding log4j log framework

slf4j-log4j12 is an adapter. You must have an adapter, otherwise log4j will not take effect

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.12</version>
</dependency>
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

In addition, you need to add the configuration file of log4j: log4j properties

# Configure the top-level parent element of log4j, specify the log level as trace, and use the appender as yexindong, which is user-defined
log4j.rootLogger=trace,yexindong
# ***********************Output to console start****************
# Specifies the appender for console log output
log4j.appender.yexindong=org.apache.log4j.ConsoleAppender
# Specify message layout
log4j.appender.yexindong.layout=org.apache.log4j.PatternLayout
# Specifies the message output format
log4j.appender.yexindong.layout.conversionPattern=%t %d [%t] %-5p %l -- %m %n
# ***********************Output to console end****************

After running the above java code, the console prints the following results

main 2021-12-17 17:22:03,345 [main] ERROR com.log.App.main(App.java:11) -- 12322 
main 2021-12-17 17:22:03,350 [main] WARN  com.log.App.main(App.java:12) -- warn 
main 2021-12-17 17:22:03,351 [main] INFO  com.log.App.main(App.java:13) -- info yexindong 
main 2021-12-17 17:22:03,351 [main] DEBUG com.log.App.main(App.java:14) -- debug 
main 2021-12-17 17:22:03,351 [main] TRACE com.log.App.main(App.java:15) -- trace 
4. Binding logback log framework
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>1.2.3</version>
</dependency>

After running the above java code, the console prints the following results

17:14:23.500 [main] ERROR com.log.App - 12322
17:14:23.508 [main] WARN com.log.App - warn
17:14:23.508 [main] INFO com.log.App - info yexindong
17:14:23.510 [main] DEBUG com.log.App - debug

slf4j log bridge

Usage scenario

The logging framework used in the old project is log4j. Now I want to use logback, but log4j is imported into a lot of java files

import org.apache.log4j.Logger;

Because logback is used, the maven dependency related to log4j must be deleted. After the dependency is deleted, the import will report an error. It's too troublesome to correct it one by one. It's even more troublesome. Therefore, there is a log bridge. You only need to add the maven dependency of the bridge. There is no need to change a line of code. The dependencies are as follows

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>log4j-over-slf4j</artifactId>
    <version>1.7.25</version>
</dependency>

After adding this dependency, although the import is log4j, the underlying call is actually the log implementation of logback;

Attention problem
  1. Log4j over slf4j and slf4j JCL Jars cannot be deployed at the same time, otherwise it will cause an infinite loop
  2. Log4j over slf4j bridge and slf4j log4j adapter cannot appear at the same time
  3. jul-to-slf4j.jar and slf4j-jdk14 Jars cannot appear at the same time
  4. All bridges are valid only for the Logger logger object. If the internal configuration class or object such as Appender or Filter is invoked, the result will not be effective.

finish

Topics: Java Apache Spring Boot