Programmer light 2022-02-13 07:52:37 阅读数:406
JDK journal 、log4j Series log 、logback Series log
common-logging Log interface
sl4j Log interface
from jdk1.4 rise ,JDK Start to bring your own log system .JDK Logger The biggest advantage is that you don't need any class library support , As long as there is Java You can use the . Compared to other logging frameworks ,JDK The log you bring with you is chicken ribs , Regardless of ease of use , The function and scalability are slightly inferior , Therefore, it is rarely used directly in commercial systems .
JDK default logging The configuration file is :$JAVA_HOME/jre/lib/logging.properties, You can use system properties java.util.logging.config.file Specify the corresponding configuration file to overwrite the default configuration file , such as , java -Djava.util.logging.config.file=myfile
JDK Logging The log is divided into the following seven levels , The grades are reduced in turn .
If the level is set to INFO, be INFO The following will not output .info All previous outputs . Achieve the purpose of controlling the output through the control level .
import java.util.logging.Level;
import java.util.logging.Logger;
public class LogJDKTest {
private static Logger log = Logger.getLogger(LogJDKTest.class.toString());
public static void main(String[] args) {
// all→finest→finer→fine→config→info→warning→server→off
// The ranks go up in turn , The later log level will mask the previous level
log.setLevel(Level.INFO);
log.finest("finest");
log.finer("finer");
log.fine("fine");
log.config("config");
log.info("info");
log.warning("warning");
log.severe("server");
}
}
Console output :
June 23, 2021 11:07:29 In the morning com.test.log.LogJDKTest main
Information : info
June 23, 2021 11:07:29 In the morning com.test.log.LogJDKTest main
Warning : warning
June 23, 2021 11:07:29 In the morning com.test.log.LogJDKTest main
serious : server
1.JDK log There will be a console output by default , It has two parameters , The first parameter sets the output level , The second parameter sets the output string .
2. You can also set multiple outputs (Hander), Each output setting is not used level, And then through addHandler Added to the log in .
Be careful : by log Set the level and for each handler The meaning of setting the level is different .
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
public class LogJDKTest {
public static Logger log = Logger.getLogger(LogJDKTest.class.toString());
static {
Handler console = new ConsoleHandler();
console.setLevel(Level.SEVERE);
log.addHandler(console);
Handler console2 = new ConsoleHandler();
console2.setLevel(Level.INFO);
log.addHandler(console2);
}
public static void main(String[] args) {
// all→finest→finer→fine→config→info→warning→server→off
// The ranks go up in turn , The later log level will mask the previous level
log.setLevel(Level.INFO);
log.finest("finest");
log.finer("finer");
log.fine("fine");
log.config("config");
log.info("info");
log.warning("warning");
log.severe("server");
}
}
Console output :
June 23, 2021 11:09:03 In the morning com.middleware.test.log.LogJDKTest main
Information : info
June 23, 2021 11:09:03 In the morning com.middleware.test.log.LogJDKTest main
Warning : warning
June 23, 2021 11:09:03 In the morning com.middleware.test.log.LogJDKTest main
serious : server
June 23, 2021 11:09:03 In the morning com.middleware.test.log.LogJDKTest main
serious : server
all, Then all the information will be output , If it is set to off, Then all information will not be output .
Apache An open source project of , By using Log4j, The destination where we can control the delivery of log information is the console 、 file 、GUI Components 、 Even socket Services device 、NT Event recorder for 、UNIX Syslog Daemons, etc ; Users can also control the output format of each log ; By defining the level of each log message , Users can more carefully control the log generation process . These can be done through a Configuration file to flexibly configure , Without modifying the program code .
Import maven
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
stay resources Create and set up log4j.properties
### Set up ###
log4j.rootLogger = debug,stdout,D,E
### Output information to control lifting ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
### Output DEBUG Log above level to =E://logs/error.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = E://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
### Output ERROR Log above level to =E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =E://logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
Set log content
import org.apache.log4j.Logger;
public class TestLog4j {
private static Logger logger = Logger.getLogger(TestLog4j.class);
public static void main(String[] args) {
// Record debug Level information
logger.debug("This is debug message.");
// Record info Level information
logger.info("This is info message.");
// Record error Level information
logger.error("This is error message.");
}
}
Output results
The first is the information on the console
[DEBUG] 2021-06-23 12:00:46,717 method:com.middleware.test.log.TestLog4j.main(TestLog4j.java:11)
This is debug message.
[INFO ] 2021-06-23 12:00:46,719 method:com.middleware.test.log.TestLog4j.main(TestLog4j.java:13)
This is info message.
[ERROR] 2021-06-23 12:00:46,719 method:com.middleware.test.log.TestLog4j.main(TestLog4j.java:15)
This is error message.
Let's look at the output file
The contents are as follows , It is found that it has been output to the corresponding document as required .
Import maven package
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.1</version>
</dependency>
Test code
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class LoggerTest {
public static void main(String argv[]) {
Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
logger.trace("trace level");
logger.debug("debug level");
logger.info("info level");
logger.warn("warn level");
logger.error("error level");
logger.fatal("fatal level");
logger.error(" String splicing one :{}, Record main perform :","logger");
logger.error(" String splicing II :","logger");
}
}
Logback By log4j Another open source diary component designed by the founder .logback Currently divided into three modules :logback-core,logback- classic and logback-access.logback-core It is the basic module of the other two modules .logback-classic yes log4j One of the Improved version . Besides logback-classic Complete implementation SLF4J API So that you can easily change to other diary systems, such as log4j or JDK14 Logging.logback-access Access module and Servlet Container integration is provided through Http To access the diary function .
Logback By log4j Another open source logging component designed by the founder , Official website : Logback Home. It is currently divided into the following modules :
1、 Faster implementation :Logback The kernel of , Performance improvement on some critical execution paths 10 More than times . and logback Not only is the performance improved , Initialization memory loading is also smaller .
2、 Very well tested :Logback After a few years , Countless hours of testing .Logback The tests of are totally different levels .
3、Logback-classic It's very natural SLF4j:Logback-classic Realized SLF4j. In the use of SLF4j in , You can't feel logback-classic. And because logback-classic It's very natural that slf4j , the To switch to log4j Or other , Very easy to , Just provide another jar Baojiu OK, There's no need to move those through SLF4JAPI Implemented code .
4、 Very well documented The official website has more than 200 pages of documents .
5、 Auto reload profile , When the configuration file is modified ,Logback-classic Can automatically reload configuration files . Scanning is fast and safe , It doesn't need to create another scan thread . This technology ensures that the application can run happily JEE In the environment .
6、Lilith yes log The observer of the event , and log4j Of chainsaw similar . and lilith It can also handle a large number of log data .
7、 Careful mode and very friendly recovery , In cautious mode , Multiple FileAppender Examples run in multiple JVM Next , can Safe enough to write the same log file .RollingFileAppender There will be some restrictions .Logback Of FileAppender And its subclasses include RollingFileAppender Can be very friendly from I/O Recover in exception .
8、 Configuration files can handle different situations , Developers often need to judge different Logback Configuration files in different environments ( Development , test , production ). And these profiles are just a few small differences , Can pass , And to achieve , Such a configuration file can adapt to multiple environments .
9、Filters( filter ) Sometimes , Need to diagnose a problem , Need to log . stay log4j, Only reduce the log level , But it's going to be a lot of logs , Will affect application performance . stay Logback, You can go on Keep that log level and get rid of some special situation , Such as alice This user logs in , Her diary will be in DEBUG Level and other users can continue to type in WARN Level . To achieve this function, just add 4 That's ok XML To configure . You can refer to MDCFIlter .
10、SiftingAppender( A very versatile Appender): It can be used to split the log file according to any given running parameter . Such as ,SiftingAppender Can distinguish log event follow-up users Session, Then each user will have a log file .
11、 Automatic compression has been printed out log:RollingFileAppender When new documents are produced , Will automatically compress the log files that have been printed out . Compression is an asynchronous process , So even for large log files , Application will not be affected during compression .
12、 Stack tree with package version :Logback When making a stack tree log , Will bring the package's data .
13、 Automatically remove old log files : By setting TimeBasedRollingPolicy perhaps SizeAndTimeBasedFNATP Of maxHistory attribute , You can control the maximum number of log files that have been generated . If you set maxHistory 12, Those log The document exceeds 12 Months will be automatically removed .
Logger As a log recorder , Relate it to the application's corresponding context After the , It is mainly used to store log objects , You can also define the log type 、 Level .
Appender It is mainly used to specify the destination of log output , The destination can be the console 、 file 、 Remote socket server 、 MySQL、PostreSQL、 Oracle And other databases 、 JMS And remote UNIX Syslog Daemons, etc .
Layout Responsible for converting events to strings , Output of formatted log information .
each logger It's all connected to a LoggerContext,LoggerContext Be responsible for manufacturing logger, It is also responsible for arranging the trees logger. All of the other logger Also through org.slf4j.LoggerFactory Class static methods getLogger obtain . getLogger Methods to logger The name is parameter . Call... With the same name LoggerFactory.getLogger The results of the method are always the same logger References to objects .
Logger Can be assigned levels . Levels include :TRACE、DEBUG、INFO、WARN and ERROR, Defined in ch.qos.logback.classic.Level class . If logger Not assigned a level , Then it will inherit the level from the nearest ancestor who has the assigned level .root logger The default level is DEBUG.
The printing method determines the level of recording request . for example , If L It's a logger example , that , sentence L.info("..") Is a level for INFO The record statement of . Record requests at a level higher than or equal to logger The effective level of is called enabled , otherwise , Called Disabled . The record request level is p, Its logger The effective level of is q, Only when p>=q when , The request will be executed .
The rule is logback At the heart of . The ranking is : TRACE < DEBUG < INFO < WARN < ERROR
If the profile logback-test.xml and logback.xml It doesn't exist , that logback By default... Is called BasicConfigurator , Create a minimized configuration . Minimized configuration is associated with a root logger Of ConsoleAppender form . The output mode is %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n Of PatternLayoutEncoder format .root logger The default level is DEBUG.
Logback The syntax of the configuration file is very flexible . Because of the flexibility , So I can't use DTD or XML schema Define . For all that , The basic structure of the configuration file can be described in this way : With <configuration> start , There are zero or more at the back <appender> Elements , There are zero or more <logger> Elements , There is at most one <root> Elements .
1、 Try to classpath Look for the file logback-test.xml;
2、 If the file doesn't exist , Find the file logback.xml;
3、 If neither file exists ,logback use BasicConfigurator Automatically configure yourself , This causes the record to be output to the console .
(1) The root node <configuration>, Contains the following three properties :
scan: When this property is set to true when , If the configuration file changes , Will be reloaded , The default value is true.
scanPeriod: Set the time interval between changes in the monitoring profile , If no time unit is given , The default unit is milliseconds . When scan by true when , This property takes effect . The default time interval is 1 minute .
debug: When this property is set to true when , Will print out logback Internal log information , Real-time view logback Running state . The default value is false.
for example :
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- Other configurations are omitted -->
</configuration>
(2) Child node <contextName>: Used to set the context name , Every logger All related to logger Context , The default context name is default. But you can use <contextName> Set to a different name , Records used to distinguish different applications . Once set , Do not modify .
for example :
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<contextName>myAppName</contextName>
<!-- Other configurations are omitted -->
</configuration>
Child node <property> : Used to define variable values , It has two properties name and value, adopt <property> The defined value will be inserted into logger In the context of , You can make “${}” To use variables .
name: The name of the variable
value: The value of is the value defined by the variable
for example :
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<property name="APP_Name" value="myAppName" />
<contextName>${APP_Name}</contextName>
<!-- Other configurations are omitted -->
</configuration>
Child node <timestamp>: Get the timestamp string , He has two attributes key and datePattern
key: Mark this <timestamp> Name ;
datePattern: Set the current time ( Time to parse the configuration file ) Conversion to string mode , follow java.txt.SimpleDateFormat The format of .
for example :
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/>
<contextName>${bySecond}</contextName>
<!-- Other configurations are omitted -->
</configuration>
(5) Child node <appender>: The component responsible for writing logs , It has two necessary attributes name and class.name Appoint appender name ,class Appoint appender Full name of
<encoder>: Format the log .( The specific parameters will be explained later )
<target>: character string System.out( Default ) perhaps System.err( There's no more difference )
for example :
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</configuration>
>=DEBUG Level logs are output to the console
<file>: The name of the file being written , It can be a relative Directory , It can also be an absolute catalog , If the parent directory does not exist, it will be created automatically , No default .
<append>: If it is true, The log is appended to the end of the file , If it is false, Empty existing files , The default is true.
<encoder>: Format the recorded events .( The specific parameters will be explained later )
<prudent>: If it is true, The log will be safely written to the file , Even if the others FileAppender Also writing to this file , Low efficiency , The default is false.
for example :
<configuration>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>testFile.log</file>
<append>true</append>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
</root>
</configuration>
The above configuration shows that >=DEBUG Level logs are output to testFile.log
<file>: The name of the file being written , It can be a relative Directory , It can also be an absolute catalog , If the parent directory does not exist, it will be created automatically , No default .
<append>: If it is true, The log is appended to the end of the file , If it is false, Empty existing files , The default is true.
<rollingPolicy>: When rolling happens , decision RollingFileAppender act , It involves moving and renaming files . attribute class Define specific rolling strategy classes class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy": The most common rolling strategy , It makes rolling strategies based on time , Responsible for rolling as well as starting rolling . There are the following child nodes :
<fileNamePattern>: Necessary nodes , Contains the file name and “%d” Conversion character ,“%d” It can contain a java.text.SimpleDateFormat Specified time format , Such as :%d{yyyy-MM}.
If used directly %d, The default format is yyyy-MM-dd.RollingFileAppender Of file Byte points are optional , By setting file, You can specify different locations for active and archived files , The current log always records file Specified file ( Activity file ), The name of the active file will not change ;
If not file, The name of the activity file will be based on fileNamePattern Value , Change every once in a while .“/” perhaps “\” Will be used as a directory separator
<maxHistory>:
Optional nodes , Control the maximum number of archive files that are retained , Delete old files if the number exceeds . Suppose you set the scroll every month , And <maxHistory> yes 6, Save only recent 6 Months of documents , Delete old files before . Be careful , Deleting old files is , Directories created for archiving will also be deleted .
class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy": View the size of the currently active file , If it exceeds the specified size, it will inform RollingFileAppender Triggers the scrolling of the currently active file . Only one node :
<maxFileSize>: This is the size of the active file , The default value is 10MB.
<prudent>: When it comes to true when , I won't support it FixedWindowRollingPolicy. Support TimeBasedRollingPolicy, But there are two limitations ,1 File compression is not supported or allowed ,2 Cannot set file attribute , Must be left blank .
<triggeringPolicy >: inform RollingFileAppender Appropriate to activate scrolling .
class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy" According to the fixed window algorithm rename the file rolling strategy . There are the following child nodes :
<minIndex>: Minimum window index
<maxIndex>: Maximum window index , When the window specified by the user is too large , Will automatically set the window to 12.
<fileNamePattern>: Must contain “%i” for example , Suppose that the minimum and maximum values are respectively 1 and 2, The naming pattern is mylog%i.log, There will be an archive mylog1.log and mylog2.log. You can also specify file compression options , for example ,mylog%i.log.gz perhaps No, log%i.log.zip
for example :
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
</root>
</configuration>
remarks : The above configuration means that a log file is generated every day , preservation 30 Days of log files .
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>test.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>tests.%i.log.zip</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>3</maxIndex>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>5MB</maxFileSize>
</triggeringPolicy>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
</root>
</configuration>
On 5MB when , Generate a new log file . The window size is 1 To 3, When saved 3 After filing , The oldest log will be overwritten .
<encoder>: Format the recorded events . Responsible for two things , One is to convert log information into byte array , The second is to write the byte array to the output stream .
PatternLayoutEncoder Is the only useful and default encoder , There is one <pattern> node , Used to set the input format of the log . Use “%” Add “ Conversion character ” The way , If you want to output “%”, You have to use “\” Yes “\%” Transference .
You can refer to the official documents (Documentation), You can also write your own Appender.
Used to set the log printing level of a package or a specific class 、 And the designation <appender>.<loger> There is only one name attribute , An optional one level And an optional addtivity attribute .
It can contain zero or more <appender-ref> Elements , Identify this appender Will be added to this loger
name: Used to designate the recipient loger A package of constraints or a specific class .
level: Used to set the print level , Case is irrelevant :TRACE, DEBUG, INFO, WARN, ERROR, ALL and OFF, There is also a special custom value INHERITED Or synonyms NULL, Represents the level of enforcement superior . If this property is not set , Then the current loger Will inherit the level of the superior .
addtivity: Whether to report to the superior loger Transfer printed information . The default is true. Same as <loger> equally , It can contain zero or more <appender-ref> Elements , Identify this appender Will be added to this loger.
So is it <loger> Elements , But it's the root loger, It's all <loger> My superior . only one level attribute , because name It has been named "root", And he's already at the top .
level: Used to set the print level , Case is irrelevant :TRACE, DEBUG, INFO, WARN, ERROR, ALL and OFF, Cannot be set to INHERITED Or synonyms NULL. The default is DEBUG.
<!-- show parameters for hibernate sql Specially designed for Hibernate customized -->
<logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE" />
<logger name="org.hibernate.type.descriptor.sql.BasicExtractor" level="DEBUG" />
<logger name="org.hibernate.SQL" level="DEBUG" />
<logger name="org.hibernate.engine.QueryParameters" level="DEBUG" />
<logger name="org.hibernate.engine.query.HQLQueryPlan" level="DEBUG" />
<!--myibatis log configure-->
<logger name="com.apache.ibatis" level="TRACE"/>
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>
logback Use needs and slf4j Use it together , So the total packages that need to be added are slf4j-api.jar,logback-core.jar,logback-classic.jar,logback-access.jar This is not available for the time being, so we don't add dependencies ,maven To configure
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<logback.version>1.1.7</logback.version>
<slf4j.version>1.7.21</slf4j.version>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
</dependencies>
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!-- Define the storage address of the log file Stay away LogBack The relative path is used in the configuration of -->
<property name="LOG_HOME" value="/home" />
<!-- Console output -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- Format output :%d Indicates the date ,%thread Represents the thread name ,%-5level: The level is shown from the left 5 Character width %msg: Log message ,%n Is a newline -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- Generate log files per day -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- The filename of the log file output -->
<FileNamePattern>${LOG_HOME}/TestWeb.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!-- Log file retention days -->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- Format output :%d Indicates the date ,%thread Represents the thread name ,%-5level: The level is shown from the left 5 Character width %msg: Log message ,%n Is a newline -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
<!-- Maximum log file size -->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<!-- Log output level -->
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LogbackTest {
private final static Logger logger = LoggerFactory.getLogger(LogbackTest.class);
public static void main(String[] args) {
logger.info("info succeed ");
logger.error("error succeed ");
logger.debug("debug succeed ");
}
}
2021-06-24 16:42:59.131 INFO --- [ main] com.middleware.test.log.LogbackTest : info succeed
2021-06-24 16:42:59.136 ERROR --- [ main] com.middleware.test.log.LogbackTest : error succeed
logback Integrate springboot
springboot2.0 Integrate logback journal ( detailed ) - Baidu on Google - Blog Garden
springboot It has built-in log function
Create an empty SpringBoot project , Otherwise, the analysis will find other jar Package dependent logs
springboot Of pom Every document will quote a parent
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<relativePath />
</parent>
Point in this parent, There will be one of these dependency
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.4.0</version>
</parent>
Just a little bit more 2.4 edition , So called it gives you integrated package dependencies , And the version number , One of the bags is as follows
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.4.0</version>
</dependency>
Click in again
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<version>2.4.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.13.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.7.30</version>
<scope>compile</scope>
</dependency>
First, in the idea Install the plug-in in
You can clearly see dependencies
Jakarta Commons-logging(JCL) yes apache The earliest interface for logging . Provide simple log implementation and log decoupling function .
common-logging yes apache Provides a general log interface . Users can freely choose the third-party log component as the specific implementation , image log4j, perhaps jdk Self contained logging, common-logging Through the mechanism of dynamic search , Automatically find out the real log library when the program is running . Of course ,common-logging There's a Simple logger Simple implementation of , But the function is very weak . So use common-logging, Usually with log4j To use . The advantage of using it is , Code dependency is common-logging Instead of log4j, Avoid direct coupling with specific logging schemes , When necessary , Third party libraries that can change the log implementation .
Use common-logging Common code for :
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class A {
private static Log logger = LogFactory.getLog(this.getClass());
}
Dynamic search principle :Log Is an interface declaration .LogFactory The internal will load the specific log system , And achieve the Log Implementation class of interface .LogFactory The process of internal loading log system is as follows :
1、 First , seek org.apache.commons.logging.LogFactory Attribute configuration .
2、 otherwise , utilize JDK1.3 Start offering service Discovery mechanism , Can scan classpah Under the META-INF/services/org.apache.commons.logging.LogFactory file , If found, load the configuration inside , Use the configuration inside .
3、 otherwise , from Classpath Looking for commons-logging.properties , If found, load according to the configuration inside .
4、 otherwise , Use the default configuration : If you can find Log4j It is used by default log4j Realization , Use if not JDK14Logger Realization , If not, use commons-logging Provided internally SimpleLog Realization .
From the above loading process , Just introduce log4j And in classpath Configured with log4j.xml , be commons-logging Will make log4j Normal use , And the code doesn't need to rely on anything log4j Code for .
Maven rely on :
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
① newly build commons-logging.properties file , Put in classpath Under the root path :
org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
② The code uses
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class CommonsTest {
private final static Log logger = LogFactory.getLog(CommonsTest.class);
public static void main(String[] args) {
logger.debug("DEBUG ...CommonsTest");
logger.info("INFO ...CommonsTest");
logger.error("ERROR ...CommonsTest");
}
}
Output :
17:09:33.884 [main] DEBUG com.middleware.test.log.CommonsTest - DEBUG ...CommonsTest
17:09:33.886 [main] INFO com.middleware.test.log.CommonsTest - INFO ...CommonsTest
17:09:33.887 [main] ERROR com.middleware.test.log.CommonsTest - ERROR ...CommonsTest
commons-logging The most central and useful function is decoupling , its SimpleLog The implementation performance is not as good as other implementations , Such as log4j etc. .
① Add dependency
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
Change commons-logging.properties file : Specify by display log4j
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger
And add log4j.properties Configuration file for :
log4j.rootLogger=DEBUG,console
# Output to console
log4j.appender.console=org.apache.log4j.ConsoleAppender
# Set the output style
log4j.appender.console.layout=org.apache.log4j.PatternLayout
# The format of log output information is
log4j.appender.console.layout.ConversionPattern=[%-d{yyyy-MM-dd HH:mm:ss}]-[%t-%5p]-[%C-%M(%L)]: %m%n
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class CommonsTest {
private final static Log logger = LogFactory.getLog(CommonsTest.class);
public static void main(String[] args) {
logger.debug("DEBUG ...CommonsTest");
logger.info("INFO ...CommonsTest");
logger.error("ERROR ...CommonsTest");
}
}
Output :
17:15:00.459 [main] DEBUG com.middleware.test.log.CommonsTest - DEBUG ...CommonsTest
17:15:00.461 [main] INFO com.middleware.test.log.CommonsTest - INFO ...CommonsTest
17:15:00.461 [main] ERROR com.middleware.test.log.CommonsTest - ERROR ...CommonsTest
slf4j It's a typical application of facade pattern , So I'm talking about slf4j front , Let's briefly review the facade pattern , Facade mode , Its core is that external communication with a subsystem must be carried out through a unified appearance object , Makes the subsystem easier to use . The structure of the door pattern represented by a graph is :
The core of facade mode is Facade That is, the facade object , The core of the facade object is a few points :
Generally speaking , That's enough for the review of facade mode , Start next to SLF4J Learning from .
slf4j Its full name is Simple Logging Facade for JAVA,java Simple log face . Be similar to Apache Common-Logging, It is a facade package provided for different log frames , You can access a log implementation scheme without modifying any configuration during deployment . however , He statically binds real at compile time Log library . Use SLF4J when , If you need to use some kind of logging implementation , Then you have to choose the right SLF4J Of jar Collection of bags ( All kinds of bridge packages ).
Why do we use it slf4j, for instance :
We use... In our own system logback This log system
Our system uses A.jar,A.jar The logging system used in is log4j
Our system is using again B.jar,B.jar The logging system used in is slf4j-simple
such , Our system has to support and maintain at the same time logback、log4j、slf4j-simple Three logging frameworks , Very inconvenient .
Print the log without caring about how to print the log ,slf4j perhaps commons-logging This is the adaptation layer ,slf4j Is the object of this study .
From the description above , We have to know a little bit about :slf4j It's just a log standard , It's not the specific implementation of the log system . It's very important to understand this sentence ,slf4j Do only two things :
slf4j-simple、logback All are slf4j The concrete realization of ,log4j Not directly slf4j, But there is a special bridge slf4j-log4j12 To achieve slf4j.
For a better understanding of slf4j, Let's look at the example first , Reread the source code , I believe that readers will be right slf4j Have a deeper understanding of .
It says ,slf4j Direct / Indirect realization slf4j-simple、logback、slf4j-log4j12, Let's define a pom.xml, To introduce the relevant jar package :
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
Write a simple paragraph Java Code :
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestLog {
@Test
public void testSlf4j() {
Logger logger = LoggerFactory.getLogger(Object.class);
logger.info("info test");
logger.warn("warn test");
logger.debug("debug test");
logger.error("error test");
logger.trace("trace test");
}
}
Output :
09:40:10.438 [main] INFO java.lang.Object - info test
09:40:10.445 [main] WARN java.lang.Object - warn test
09:40:10.445 [main] DEBUG java.lang.Object - debug test
09:40:10.445 [main] ERROR java.lang.Object - error test
Note out the following :
<!--<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>-->
Once again, the output :
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
No log output , This proves our point of view :slf4j No specific implementation of logging is provided , Only slf4j It's impossible to print the log .
Then open logback-classic Notes , function Test Method , Let's look at the output of the console as :
10:02:51.496 [main] INFO testlog.TestLog - info test
10:02:51.499 [main] WARN testlog.TestLog - warn test
10:02:51.499 [main] DEBUG testlog.TestLog - debug test
10:02:51.499 [main] ERROR testlog.TestLog - error test
See, we just introduced one slf4j Implementation class of , You can use the log framework to output logs .
Finally, take a test , We open all the logs , introduce logback-classic、slf4j-simple、log4j, function Test Method , The console output is :
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/C:/Users/44075/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/Users/44075/.m2/repository/org/slf4j/slf4j-simple/1.7.25/slf4j-simple-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/Users/44075/.m2/repository/org/slf4j/slf4j-log4j12/1.7.21/slf4j-log4j12-1.7.21.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
10:03:51.185 [main] INFO testlog.TestLog - info test
10:03:51.187 [main] WARN testlog.TestLog - warn test
10:03:51.187 [main] DEBUG testlog.TestLog - debug test
10:03:51.187 [main] ERROR testlog.TestLog - error test
The difference from the above is , Log can be output , However, some alarm logs will be output , Prompt that we have introduced multiple slf4j The implementation of the , Then choose one of them as the logging system we use .
For example, we can draw an important conclusion , namely slf4j The role of : As long as all code uses facade objects slf4j, We don't need to care about its implementation , In the end, a specific implementation can be used everywhere , Replace 、 Maintenance is very convenient .
common-logging Through dynamic search mechanism , Automatically find out the real log library when the program is running . Because it uses ClassLoader Find and load the underlying log Library , Led to something like OSGI Such a framework doesn't work , because OSGI Different plug-ins use their own ClassLoader. OSGI This mechanism ensures that plug-ins are independent of each other , But it makes Apache Common-Logging Unable to work .
slf4j Static binding at compile time really Log library , So you can OSGI Use in . in addition ,SLF4J Support parameterized log character string , Avoid having to write in order to reduce the performance loss of string splicing if(logger.isDebugEnable()), Now you can write directly :logger.debug(“current user is: {}”, user). The assembly message is delayed until it can determine whether to display the message , But the cost of getting parameters is not spared .
LogBack As a general and reliable 、 Fast and flexible logging framework , Will serve as a Log4j Substitution and SLF4J A complete implementation of the new logging system .LOGBack Claim to have excellent performance ,“ Some key operations , For example, determine whether to record a log statement , Its performance has been greatly improved . This operation is LogBack China needs 3 nanosecond , And in the Log4J We need 30 nanosecond . LogBack Create a recorder (logger) It's faster :13 Microsecond , And in the Log4J China needs 23 Microsecond . what's more , It only needs to 94 nanosecond , and Log4J need 2234 nanosecond , Time has been reduced to 1/23. Follow JUL Compared to the performance improvement is also significant ”. in addition ,LOGBack All documents of are provided completely free of charge , Don't like Log4J In that way, only part of the free documents are provided and users need to purchase the paid documents .
Use... In application code slf4j Interface , The specific implementation method of access
Other log interfaces are used in the application code , Turn into slf4j Methods
Java There are many tools in the world to implement the logging function , The first widely used is log4j, The log section of many applications is handed over to log4j, But as a component developer , They want their components not to rely on a single tool , After all, there are many other logging tools at the same time , If an application uses two components , Just two components use different logging tools , Then the application will have two log outputs .
To solve this problem ,Apache Commons Logging ( Formerly called Jakarta Commons Logging,JCL) make oneself up and go on the stage ,JCL Only available log Interface , The specific implementation dynamically looks for . In this way, component developers only need to target JCL Interface development , The application calling the component can match its own logging practice tool at runtime .
So even now you'll still see a lot of applications JCL + log4j This collocation , But as the program gets bigger and bigger ,JCL Dynamic binding is not always successful , For specific reasons, you can Google once , I won't go into that here . One of the solutions is to statically bind the specified logging tool when the program is deployed , This is it. SLF4J Cause of occurrence .
Dynamic binding 、 Static binding :
Follow JCL equally ,SLF4J It's just about providing log Interface , The specific implementation is the binder put in when packaging the application ( The name is slf4j-XXX-version.jar) To decide ,XXX It can be log4j12, jdk14, jcl, nop etc. , They have implemented specific logging tools ( such as log4j) Binding and proxy work for . for instance : If a program wants to use log4j Logging tools , Then the program only needs to be directed at slf4j-api Interface programming , And then put it in when you pack it slf4j-log4j12-version.jar and log4j.jar That's all right. .
Now there's another question , If you are developing a component called by an application that already uses JCL Of , There are also some components that may directly call java.util.logging, Now you need a bridge ( The name is XXX-over-slf4j.jar) Redirect their log output to SLF4J, The so-called bridge is a fake log implementation tool , For example, when you put jcl-over-slf4j.jar Put it in CLASS_PATH when , Even if a component originally passes through JCL Output log , Now it will be jcl-over-slf4j “ In some of the ”SLF4J in , then SLF4J According to the binding machine, the log will be handed over to the specific log implementation tool . The process is as follows
Component
|
| log to Apache Commons Logging
V
jcl-over-slf4j.jar --- (redirect) ---> SLF4j ---> slf4j-log4j12-version.jar ---> log4j.jar ---> Output log
Looking at the flow chart above, you may find an interesting problem , If be in, CLASS_PATH At the same time log4j-over-slf4j.jar and slf4j-log4j12-version.jar What's going to happen ? you 're right , Logs will be kicked around , Finally, it goes into a dead cycle .
So use SLF4J The more typical collocation is to slf4j-api、JCL Bridge 、java.util.logging(JUL) Bridge 、log4j Binder 、log4j this 5 individual jar Put in CLASS_PATH in .
But not all APP Containers are used log4j Of , such as Google AppEngine It uses java.util.logging(JUL), This is the time to apply SLF4J The collocation becomes slf4j-api、JCL Bridge 、logj4 Bridge 、JUL The binder is 4 individual jar Put in WEB-INF/lib in .
copyright:author[Programmer light],Please bring the original link to reprint, thank you. https://en.javamana.com/2022/02/202202130752333385.html