2021/12/14
- There are 44 days to miss home before the Chinese New Year ๐๏ผ There's a lot of noise these two days~
There are serious bugs in a log framework. It's said that there are a lot of them. The bosses of big factories work overtime to correct the bugs~ ๐ฑ
Then, I think I don't know much about the log framework. I only know the import dependency, configuration file and normal use More in-depth is not clear
*** ๐
Log frame ๐
Concept of log
Log files are a collection of files used to record system operation events
In the computer field, the log file is logfile
It is a file that records events in the running operating system or other software, or records messages sent between users of network chat software.
Why logs are needed:
Logging is an essential part of an application
It can help developers quickly locate problems, find problems and solve them ๐
Existing logging framework ๐
Occurrence date sorting:
The Java log framework has been developed for many years, and there have been many versions ~ the development process is also chaotic~
- log4j โ JUL โ JUCCommons Logging โ Slf4j โ Logback โ log4j2
History of Java logging framework โ:
log4j 1999
It is a project of the Apache Software Foundation in jdk1 Before 3, there was no ready-made log framework:
Java engineers can only use the original system out. println() System. err. Println() or e.printStackTrace()
Write the debug log to the StdOut stream and the error log to the ErrOut stream to record the running status of the application
- This original logging method has obvious defects, not only can not be customized, but also the output granularity of the log is not fine enough
- In 1999, Daniel Ceki G ü lc ü cheki gulku created the Log4j project
JUL 2002
- Log4j as a member of Apache foundation, Apache hopes to introduce log4j into jdk, but sun company refused
Subsequently, sun imitated Log4j and created a new version in jdk1 JUL is introduced in 4 ๐
sun company is so proud that it finally knows how to go bankrupt~
JCL 2002
- At that time, there were two different ways of using log frameworks, and different log levels ~ were not very friendly to developers~
Therefore, in 2002, Apache launched the JCL log facade to define a set of interfaces, which are implemented by Log4j or JUL
When the program runs, the ClassLoader class loader will be used to find and load the underlying log library, so you can freely choose log4j or JUL to implement the log function
Similar to JDBC
It defines the addition, deletion, modification and query interface of a group of databases, MySQL and Oracle All databases implement classes. These interfaces can do this without changing the code to switch the database~
Slf4j 2005 & Logback 2006
For two reasons, the implementation of JCL is too cumbersome, and it is inconvenient to expand the new logging framework in the later stage
Ceki G ü lc ü left Apache behind and developed a new log facade Slf4j Logback~
- Compared with log4j, it has faster execution speed and more perfect functions! ๐
log4j2 2014
In order to maintain its position in the Java log Jianghu
To prevent JCL and Log4j from being replaced by Slf4j and Logback, Apache launched Log4j2 'sanctions' from its old owner in 2014 ๐'
- Log4j 2 is incompatible with log4j, and there is no pipe. After a lot of in-depth optimization, its performance is significantly improved ๐
Log facade and log frame:
From the above, we know that the common logging frameworks are: Log4j JUL JCL Slf4j Logback Log4j2
These log frames can be divided into two types: facade log and log system
Log facade: design mode appearance mode
โ JCL,slf4j
- Only log related interface definitions are provided, that is, the corresponding API provides simple implementation
- In order to facilitate the implementation of different logs, no major changes will be made to the code ~ improve the use of developers~
Log system:
JUL,logback,log4j,log4j2
- Compared with the log facade, it provides a specific log interface implementation, through which the application program performs the function of log printing
JUL
JUL full name: Java util. Logging
- It is a native logging framework of java. It does not need to refer to a third-party class library when using it
- Compared with other log frameworks, it is easy to use and learn, and can be used flexibly in small applications
Introduction to JUL architecture
Logger
- Logger, the application uses getLogger(); Get the logger object and call its API to publish log information
- Logger is usually considered as an entry program to access the logging system
Handler
- Processor, each Logger will be associated with one or a group of handlers, console files
- The Logger will send the log to the associated Handler for processing, and the Handler is responsible for recording the log
Filter
Filter, which information will be recorded and which information will be skipped according to needs
Formatter
The format component is responsible for converting and formatting the data and information in the log, so it determines the final form of our output log
Level
The output level of the log. Each log message has an associated level. It is used to display the final log information according to the output level settings
The logger logger has its own default Filter Formatter Level, which can be associated with one or more hanlders for log output~
Getting started Demo:
Create a JUL Maven project
JUL is provided by Java itself, so there is no need to introduce any dependency
JULTest.Java
import org.junit.Test; import java.util.logging.Level; import java.util.logging.Logger; public class JULTest { //Introductory case: @Test public void Test(){ //1. Get the logger object logger Getlogger ("the parameter is a unique string, generally using the 'full pathname' of the class"); Logger logger = Logger.getLogger("com.wsm.JULTest"); //2. Log record output logger.info("Output log,info level~"); /** common method */ //Pass log(); Method to specify the output level of the log logger.log(Level.INFO,"Specify output level: info~"); logger.log(Level.WARNING,"Specify output level: WARNING~"); //Output logs in the form of placeholders, similar to printf(); String name = "WSM"; Integer age = 3; logger.log(Level.INFO,"My name is: "{0},this year{1}year",new Object[]{name,age}); } }
Console output:
December 15, 2021 9:43:06 afternoon com.wsm.JULTest Test information: Output log,info level~ December 15, 2021 9:43:06 afternoon com.wsm.JULTest Test information: Specify output level: info~ December 15, 2021 9:43:06 afternoon com.wsm.JULTest Test warning: Specify output level: WARNING~ December 15, 2021 9:43:06 afternoon com.wsm.JULTest Test information: My name is: "WSM,He is 3 years old
JUL log level description and display
JUL has seven log levels and two special off All
log level | numerical value | explain |
---|---|---|
OFF | Integer.MAX_VALUE Max integer | Turn off logging of all messages |
SEVERE: the color is crooked~ | 1000 | The highest log level for error messages |
WARNING | 900 | Warning message |
INFO | 800 | Default information default level |
CONFIG | 700 | configuration information |
FINE | 500 | Details (less) |
FINER | 400 | Details (medium) |
FINEST | 300 | Details (multiple) the lowest log level |
ALL | Integer.MIN_VALUE minimum integer | Enable logging of all messages |
The significance of the value is: the setting specifies the log level, and the final displayed information must be greater than the value of > the specified level!
- OFF and ALL are special log levels, ALL OFF and ALL on
Advanced Demo
Verify that JUL default output level:
//Check JUL default output level @Test public void Test2(){ // 1. Get logger object Logger logger = Logger.getLogger("com.itheima.JULTest"); //Parameter to ensure uniqueness. Generally, fill in the class path name; // 2. Log record output logger.severe("severe"); logger.warning("warning"); logger.info("info"); //Default log output level logger.config("config"); logger.fine("fine"); logger.finer("finer"); logger.finest("finest"); } //Custom log level 1.0 @Test public void Test3(){ // 1. Get logger object Logger logger = Logger.getLogger("com.itheima.JULTest"); //Parameter to ensure uniqueness. Generally, fill in the class path name; // 2. Set the log output level: change the Logger log object // Turn off the system default configuration first logger.setUseParentHandlers(false); // Reconfigure the specific level of the log (do you think this is all right? Nothing is found during execution ~ because the log configuration is not complete, and the Handler and Formatter are missing) logger.setLevel(Level.ALL); // 3. Log record output logger.severe("severe"); logger.warning("warning"); logger.info("info"); logger.config("config"); logger.fine("fine"); logger.finer("finer"); logger.finest("finest"); } //Custom log level 2.0 @Test public void Test4(){ // 1. Get logger object Logger logger = Logger.getLogger("com.itheima.JULTest"); // 2. Set the log output level: change the Logger log object // Turn off the system default configuration first logger.setUseParentHandlers(false); // Reconfigure the log level logger.setLevel(Level.ALL); // Create consolehhandler console output ConsoleHandler consoleHandler = new ConsoleHandler(); // Create a simple format conversion object SimpleFormatter simpleFormatter = new SimpleFormatter(); // Associate Handler with Formatter: logger -- association -- Handler -- association -- Formatter consoleHandler.setFormatter(simpleFormatter); logger.addHandler(consoleHandler); // Set the console output level of consoleHandler~ consoleHandler.setLevel(Level.ALL); // 3. Log record output logger.severe("severe"); logger.warning("warning"); logger.info("info"); logger.config("config"); logger.fine("fine"); logger.finer("finer"); logger.finest("finest"); }
Test2 December 15, 2021 9:45:17 afternoon com.itheima.JULTest testLogLevel serious: severe December 15, 2021 9:45:17 afternoon com.itheima.JULTest testLogLevel warning: warning December 15, 2021 9:45:17 afternoon com.itheima.JULTest testLogLevel information: info Test3 CMD Output empty! because,The configuration of the log is incomplete,Missing Handler Formatter Test4 December 15, 2021 10:33:34 afternoon com.wsm.JULTest Test4 serious: severe December 15, 2021 10:33:34 afternoon com.wsm.JULTest Test4 warning: warning December 15, 2021 10:33:34 afternoon com.wsm.JULTest Test4 information: info December 15, 2021 10:33:34 afternoon com.wsm.JULTest Test4 to configure: config December 15, 2021 10:33:34 afternoon com.wsm.JULTest Test4 detailed: fine December 15, 2021 10:33:34 afternoon com.wsm.JULTest Test4 More detailed: finer December 15, 2021 10:33:34 afternoon com.wsm.JULTest Test4 Very detailed: finest
Test2
- Find three lines after the output log Nothing else is output Because the default level of JUL is info, and values less than info cannot be output
Test3
- There is no row of data because: the log configuration is incomplete and the Handler Formatter is missing
Test4
- Finally, all levels of logs are completely output
- A Console's ConsoleHandler is created and associated with a simple output format simpleformat~ ๐ Most importantly, set the output level of Console, which is the log level of your Console output!
be careful:
consoleHandler.setLevel(Level.ALL); The set level is better than that of logger setLevel(Level.ALL);
Logger is used to set the log level of input, but it needs to be output by consoleHandler because of incomplete configuration The level of consoleHandler is smaller at the large logger level, and the output data is not much~
The relationship between the two is like two buckets ๐ง The logger bucket is placed in the consoleHandler bucket
The water outlet of the big bucket is in the big bucket. The small bucket emits one drop of water at a time, and the big bucket has only one drop of water flow rate ๐
The water outlet of the small bucket is very large, and a lot of water flows every time. The mouth of the large bucket is small, and the water flowing out every time is not big!
Setting, log file output:
//Output of log file: @Test public void Test5() throws IOException { // 1. Get logger object Logger logger = Logger.getLogger("com.itheima.JULTest"); // 2. Set the log output level: change the Logger log object // Turn off the system default configuration first logger.setUseParentHandlers(false); // Reconfigure the log level logger.setLevel(Level.ALL); //Set the bucket flow rate! // Create format SimpleFormatter simpleFormatter = new SimpleFormatter(); // Create consolehhandler console output: Associate output levels ConsoleHandler consoleHandler = new ConsoleHandler(); consoleHandler.setFormatter(simpleFormatter); logger.addHandler(consoleHandler); consoleHandler.setLevel(Level.ALL); // Create file output Handler FileHandler fileHandler = new FileHandler("C:\\Users\\Wang Siming\\Desktop\\jul.log"); /** Ensure that the output directory exists! */ fileHandler.setFormatter(simpleFormatter); logger.addHandler(fileHandler); // Not set, log level, output log ~. It is found that all logs are output by default (inheriting the traffic of bucket logger ~) logger.severe("severe"); logger.warning("warning"); logger.info("info"); logger.config("config"); logger.fine("fine"); logger.finer("finer"); logger.finest("finest"); }
be careful โ :
The Logger can hold multiple processor handlers
FileHandler to set the output file and address directory of the log to exist in advance!
If you do not specify the output log level, by default, the parent-child relationship of the logger object is based on the level set by the logger~
JUL Logger parent-child relationship:
// Logger object parent-child relationship @Test public void Test6(){ Logger logger1 = Logger.getLogger("com.wsm"); Logger logger2 = Logger.getLogger("com"); // test System.out.println("logger1 Superior and logger2 compare:"+(logger1.getParent() == logger2)); // Top level parent element of all loggers LogManager$RootLogger,name "" System.out.println("logger2 Parent:"+logger2.getParent() + ",name:" + logger2.getParent().getName()); System.out.println("The subordinate will inherit the configuration of the superior by default,change logger2 logger1 It will also change~"); // Turn off default configuration logger2.setUseParentHandlers(false); // Set logger2 log level // Custom configuration log level // Create consolehhandler console output ConsoleHandler consoleHandler = new ConsoleHandler(); // Create a simple format conversion object SimpleFormatter simpleFormatter = new SimpleFormatter(); // Associate consoleHandler.setFormatter(simpleFormatter); logger2.addHandler(consoleHandler); // Configure log specific level logger2.setLevel(Level.ALL); consoleHandler.setLevel(Level.ALL); System.out.println(); System.out.println("output logger1 find,The output level becomes info"); logger1.severe("severe"); logger1.warning("warning"); logger1.info("info"); logger1.config("config"); logger1.fine("fine"); logger1.finer("finer"); logger1.finest("finest"); }
logger1 Superior and logger2 compare:true logger2 Parent:java.util.logging.LogManager$RootLogger@61e4705b,name: The subordinate will inherit the configuration of the superior by default,change logger2 logger1 It will also change~ output logger1 find,The output level becomes info December 16, 2021 12:00:11 morning com.wsm.JULTest Test6 serious: severe December 16, 2021 12:00:11 morning com.wsm.JULTest Test6 warning: warning December 16, 2021 12:00:11 morning com.wsm.JULTest Test6 information: info December 16, 2021 12:00:11 morning com.wsm.JULTest Test6 to configure: config December 16, 2021 12:00:11 morning com.wsm.JULTest Test6 detailed: fine December 16, 2021 12:00:11 morning com.wsm.JULTest Test6 More detailed: finer December 16, 2021 12:00:11 morning com.wsm.JULTest Test6 Very detailed: finest
The logger object of the JUL has a parent-child relationship
The descent will have the parent's attribute configuration by default` The default parent is LogManager$RootLogger@61e4705b,name
JUL configuration file form:
The above hard coded form can complete simple log recording and output, but it is not convenient to use in actual development ๐
- As we know above, the logger object has a parent-child relationship. The default parent is LogManager$RootLogger@61e4705b,name
- What about this logmanager$ RootLogger@61e4705b , where does name come from and why is it the default info configuration ๐ง?
Source code analysis
- Logger.getLogger(""); Method, obtain a logger object, and ctrl + right-click to enter the method~
Found only one demandLogger(); get into!,
Found LogManager = LogManager getLogManager(); Get a LogManager log manager object! LogManager is a singleton object that records and manages log objects
Enter getLogManager(); Enter ensuelogmanagerinitialized(); Discovery: owner readPrimordialConfiguration(); Load configuration file!
After the configuration file is loaded, the owner.exe is executed rootLogger = owner. new RootLogger(); Set the top-level, = = rootlogger object==
Enter readPrimordialConfiguration(); Method to view and load the configuration file process: find readConfiguration(); Read the configuration file and continue ๐
First: string CNAME = system getProperty("java.util.logging.config.class"); Whether there is a configuration class in the current system! If not, go down!
Judge string fname = system getProperty("java.util.logging.config.file"); Of course, there is no custom configuration file under the system!
If not: fname = system getProperty("java.home"); Get the Java installation directory,
File f = new File(fname, "lib"); f = new File(f, "logging.properties"); Read the logging. In the Lib directory in the JDK directory properties ๐
logging.properties
- I removed the official English notes and replaced them with normal notes!
# Set a Handler for console output handlers= java.util.logging.ConsoleHandler # Set the default log level Info .level= INFO # Configure default file processor # Specify the default output path of the log file, (% h output the user directory of the current device) (% u output log file suffix 1 2 3...) java.util.logging.FileHandler.pattern = %h/java%u.log # The maximum number of records stored in the current file java.util.logging.FileHandler.limit = 50000 # The number of current files and the number of output log files~ java.util.logging.FileHandler.count = 1 # The format of the current processor output file. The default format is xml! java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter # Default level of console processor INfo java.util.logging.ConsoleHandler.level = INFO # Format of log output java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter # Example to customize the SimpleFormatter output format com.xyz.foo.level = SEVERE
Therefore, we only need to be responsible for the configuration file, ensure that the name remains unchanged, and go to the resources directory of the project to configure the log information in the form of configuration file!
log configuration file:
Under the resources directory, add logging properties
# The default processors specified by the top-level parent element of RootLogger are: consolehandler and filehandler (set the processor associated with the highest price of RootLogger) handlers= java.util.logging.ConsoleHandler,java.util.logging.FileHandler # The default log level of the top-level parent element of RootLogger is ALL .level= ALL # Turn off default configuration com.itheima.useParentHanlders = false # handler object output to log file # Specify the log file path / logs / java0 Log ensure that the installation directory exists! java.util.logging.FileHandler.pattern = /java%u.log # Specify the log file content size java.util.logging.FileHandler.limit = 50000 # Specify the number of log files java.util.logging.FileHandler.count = 1 # Specifies the handler object log message format object java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter # Specifies that the log content is added by appending (if not, each added data will replace the previous data) java.util.logging.FileHandler.append = true # handler object output to console # Specifies the log level of the handler object java.util.logging.ConsoleHandler.level = ALL # Specifies the log message format object for the handler object java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter # Specifies the character set of the handler object java.util.logging.ConsoleHandler.encoding = UTF-8 # Specify log message format java.util.logging.SimpleFormatter.format = %4$s: %5$s [%1$tc]%n
JULConfigTest.Java
/** Configuration file form, JUL */ public class JULConfigTest { @Test public void Test() throws Exception{ // Read the configuration file through the class loader InputStream ins = JULTest.class.getClassLoader().getResourceAsStream("logging.properties"); // Create LogManager LogManager logManager = LogManager.getLogManager(); // Loading configuration files through LogManager logManager.readConfiguration(ins); // Create logger Logger logger = Logger.getLogger("com.wsm"); logger.info("--------------------------------------------------------------------------------------------"); logger.severe("severe"); logger.warning("warning"); logger.info("info"); logger.config("config"); logger.fine("fine"); logger.finer("finer"); logger.finest("finest"); System.out.println(""); // //Create logger 2 // Logger logger2 = Logger.getLogger("www"); // logger2.severe("severe"); // logger2.warning("warning"); // logger2.info("info"); // logger2.config("config"); // logger2.fine("fine"); // logger2.finer("finer"); // logger2.finest("finest"); } }
Custom configuration: log object level:
Except through logging The properties configuration file can be used to set the public's configuration, or you can set a log object separately!
## The user-defined Logger is used, and the user-defined log elements are set separately www.handler = java.util.logging.ConsoleHandler www.level = INFO
Release the above logger getLogger("www"); notes!
ok, JUL knows so much and uses very little now Few companies are using
Log4j
Log4j is an open source logging framework under Apache: Official website
- Through Log4J, we can control the output of log information to the console, files, and even databases
- We can control the output format of each log. By defining the log output level, we can more flexibly control the log output process
Log4j component
Log4J is mainly composed of Loggers, Loggers, appendersoutput, Layout, and log formatter
Loggers loggers
Controls the output level of the log and whether the log is output
- Logger. Getlogger (fully qualified name of class / class object ~);
The Logger's name is case sensitive and has an inheritance mechanism
com.wsm inherits the log attribute of COM qualified name~
There is a special logger called "root" in Log4J
It is the root of all loggers, which means that all other loggers will directly or indirectly inherit from rootroot. Loggers can be used Getrootlogger() method
Appenders output
Specify the output place of the log and output it to the console and file
Output type | effect |
---|---|
ConsoleAppender | Output log to console |
FileAppender | Output log to file |
DailyRollingFileAppender | Output the log to a log file, and output to a new file every day |
RollingFileAppender | Output 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 |
JDBCAppender | Save the log information to the database |
Layout log formatter
Controls the output format of log information
Formatter type | effect |
---|---|
HTMLLayout | Format the log output to HTML tabular form |
SimpleLayout | Simple log output format. The log format for printing is (info - message). What you enter and what you print |
PatternLayout | In the most powerful format period, you can output the log according to the user-defined format. If the conversion format is not specified, the default conversion format is used |
Format of Layout:
log4j Adopt similar C Linguistic printf The print format of the function formats the log information. The specific placeholders and their meanings are as follows: %m Output the log information specified in the code %p Output priority, and DEBUG,INFO etc. %n Newline character( Windows The newline character of the platform is "\n"๏ผUnix Platform is "\n") %r Output from application startup to output log The number of milliseconds the message took %c Output the full name of the class to which the print statement belongs %t Output the full name of the thread that generated the log %d The current time of the output server. The default is ISO8601๏ผYou can also specify the format, For example:%d{yyyy year MM month dd day HH:mm:ss} %F The name of the file where the output log message is generated %L Line number in output code %% Output a "%" character %l Output the location where the log time occurs, including the class name%c,thread %t,And the number of lines in the code%L For example: Test.main(Test.java:10) Can be in % And characters to control the minimum width, maximum width, and alignment of text. For example: %5c output category Name, minimum width is 5, category<5๏ผRight justified by default %-5c output category Name, minimum width is 5, category<5๏ผ"-"Number specifies the left alignment,There will be spaces %.5c output category Name, maximum width is 5, category>5๏ผThe extra characters on the left will be cut off,<5 There will be no spaces %20.30c category name<20 Fill in the blanks and align right,>30 Characters, cut off from the characters handed in for export on the left
Log4j getting started Demo
Establish maven project
Add dependencies because they are not provided by Java itself. You need to introduce corresponding dependencies~
<!--log4j--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!-- To facilitate testing,Can import JUnit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!-- log4j It has the function of operating database,Introduce the corresponding database driver --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency>
Log4jTest.Java
//Apache log4j's bag~ import org.apache.log4j.BasicConfigurator; import org.apache.log4j.Logger; import org.junit.Test; public class Log4jTest { /** Introductory case */ @Test public void test(){ //1. Initialize the configuration information before use, otherwise an error will be reported! (the actual development is through the configuration file; the introduction case needs to introduce the default) BasicConfigurator.configure(); //2. Create log object Logger logger = Logger.getLogger(Log4jTest.class);//Not only unique characters but also class objects are supported //3. Output log information! System.out.println("log4j and JUL Log level for,Some different.."); logger.fatal("fatal A serious error, which usually causes the system to crash and terminate the operation"); logger.error("error The error message will not affect the system operation"); logger.warn("warn Warning messages, problems may occur"); logger.info("info Track information and record all process information of the program"); logger.debug("debug Debugging information is generally used in development, recording program variable parameter transfer information, etc"); logger.trace("trace Track information and record all process information of the program"); } }
Log4j profile usage:
Source code analysis:
Logger.getLogger() enters and finds that the logger object is another LogManager object getLogger(); establish
Enter the LogManage class and find} url = loader in the static {code block getResource("log4j.properties");
Class scan read log4j Properties configuration file, as long as log4j exists in the resource resource directory Properties file, there is no need to initialize the configuration information!
There is an optionconverter inside} in the static {code block selectAndConfigure(..) Read configuration file Dynamically read the xml properties and obtain the Configurator object according to the file type
The Configurator object is used to load and initialize the root object. You can use it to view how the configuration file is written
In the selectAndConfigure method, new PropertyConfigurator(); get into
Discovery: APPENDER_PREFIX RENDERER_PREFIX and many other configuration files, properties
The rootLogger configuration file loads the default log object
log4j. Under the properties resources resource file, add a configuration file; โ
# Set the default log object rootLogger # Log level and bound Appenders (can be multiple) are separated by commas log4j.rootLogger = trace,console # Specifies the appender for console log output log4j.appender.console = org.apache.log4j.ConsoleAppender # Specifies the layout format of console log output. The default is SimpleLayout log4j.appender.console.layout = org.apache.log4j.SimpleLayout
Log4jTest.Java
/** Configuration file loading: rootlogger object; */ @Test public void test1(){ //Add one in the resources directory, log4j properties //This eliminates the need for basic configurator configure(); The default configuration file has been loaded; // Enable log4j built-in log recording (optional), enable log output and log information of log framework~ LogLog.setInternalDebugging(true); //Create log object Logger logger = Logger.getLogger(Log4jTest.class); //Output log information! System.out.println("log4j and JUL Log level for,Some different.."); logger.fatal("fatal A serious error, which usually causes the system to crash and terminate the operation"); logger.error("error The error message will not affect the system operation"); logger.warn("warn Warning messages, problems may occur"); logger.info("info Track information and record all process information of the program"); logger.debug("debug Debugging information is generally used in development, recording program variable parameter transfer information, etc"); logger.trace("trace Track information and record all process information of the program"); }
log4j and JUL Log level for,Some different.. FATAL - fatal A serious error, which usually causes the system to crash and terminate the operation ERROR - error The error message will not affect the system operation WARN - warn Warning messages, problems may occur INFO - info Track information and record all process information of the program DEBUG - debug Debugging information is generally used in development, recording program variable parameter transfer information, etc TRACE - trace Track information and record all process information of the program
Try to modify the configuration file and run test1()
# Specify the layout output format of console log output. The default is simplelayout (htmllayout (displaying log information in HTML) / xml Xmllayout (display data in xml) / patternlayout (customize common!) log4j.appender.console.layout = org.apache.log4j.HTMLLayout
The output log will be displayed in html ๐บ
PatternLayout custom, log format output:
log4j.properties append
# Set the default log object rootLogger # Log level and bound Appenders (can be multiple) are separated by commas log4j.rootLogger = trace,console # Specifies the appender for console log output log4j.appender.console = org.apache.log4j.ConsoleAppender # Specify the layout output format of console log output. The default is SimpleLayout (HTMLLayout / xml.XMLLayout / PatternLayout) log4j.appender.console.layout = org.apache.log4j.PatternLayout # Specify the content layout of the message format conversionPattern log4j.appender.console.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n # Setting, data format: # [% - 10p]: [data length 10 and left]% r is the number of milliseconds from application startup to output the log information # %r: Output the number of milliseconds spent from application startup to outputting the log information # %l: The location where the output log time occurs, including class name, thread, and the number of lines in the code # %d: The current time of the output server is ISO8601 by default, or the format can be specified
In the later stage, the company has fixed specifications, which can be configured and understood!
Output log, save file: file
log4j.properties append
Set log4j Rootlogger = appender corresponding to trace, console and file binding
# Log level and bound Appenders (can be multiple) are separated by commas log4j.rootLogger = trace,console,file # appender object for log file output log4j.appender.file = org.apache.log4j.FileAppender # Specify message format layout log4j.appender.file.layout = org.apache.log4j.PatternLayout # Specifies the content of the message format log4j.appender.file.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n # Specify the path to save the log file (it needs to be specified manually, and the log file is saved to disk... Otherwise, an error occurs. This time, I default the drive letter of the project to disk D, and no file is created~ log4j.appender.file.file = /logs/log4j.log # Specifies the character set of the log file log4j.appender.file.encoding = UTF-8
Run test1()
Unlike JUL, log4j adds data by default~
Split rollingFile by file size
log4j.properties append
Set log4j Rootlogger = appender corresponding to trace, console and rollingfile binding
# Log level and bound Appenders (can be multiple) are separated by commas log4j.rootLogger = trace,console,rollingFile # appender object split by file size # appender object for log file output log4j.appender.rollingFile = org.apache.log4j.RollingFileAppender # Specify message format layout log4j.appender.rollingFile.layout = org.apache.log4j.PatternLayout # Specifies the content of the message format log4j.appender.rollingFile.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n # Specify the path to save the log file log4j.appender.rollingFile.file = /logs/log4j.log # Specifies the character set of the log file log4j.appender.rollingFile.encoding = UTF-8 # Specify the size of the log file content (no file 1mb generates a new log file)~ log4j.appender.rollingFile.maxFileSize = 1MB # Specify the number of log files (up to 10 log files are generated, log4j.log log4j2.log log4j3.log. If the number of files exceeds, the old file will be overwritten by the new file log4j.appender.rollingFile.maxBackupIndex = 10
Log4jTest.Java loop 1w times to view the results~
for (int i = 0; i < 10000; i++) { logger.fatal("fatal A serious error, which usually causes the system to crash and terminate the operation"); logger.error("error The error message will not affect the system operation"); logger.warn("warn Warning messages, problems may occur"); logger.info("info Track information and record all process information of the program"); logger.debug("debug Debugging information is generally used in development, recording program variable parameter transfer information, etc"); logger.trace("trace Track information and record all process information of the program"); }
dailyFile split by time rule
log4j.properties append
Set log4j Rootlogger = appender corresponding to trace, console and dailyfile binding
# Log level and bound Appenders (can be multiple) are separated by commas log4j.rootLogger = trace,console,dailyFile # appender objects split according to time rules; (by default, a new file is generated every day~ log4j.appender.dailyFile = org.apache.log4j.DailyRollingFileAppender # Specify message format layout log4j.appender.dailyFile.layout = org.apache.log4j.PatternLayout # Specifies the content of the message format log4j.appender.dailyFile.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n # Specify the path to save the log file log4j.appender.dailyFile.file = /logs/log4j.log # Specifies the character set of the log file log4j.appender.dailyFile.encoding = UTF-8 # Specify the date splitting rule (year, month, day, hour, minute and second, generating one file per second~ log4j.appender.dailyFile.datePattern = '.'yyyy-MM-dd-HH-mm-ss
Run: test1()
Log file write to database:
Create corresponding database and database table script sql
CREATE TABLE `log` ( `log_id` int(11) NOT NULL AUTO_INCREMENT, `project_name` varchar(255) DEFAULT NULL COMMENT 'Item name', `create_date` varchar(255) DEFAULT NULL COMMENT 'Creation time', `level` varchar(255) DEFAULT NULL COMMENT 'priority', `category` varchar(255) DEFAULT NULL COMMENT 'Full name of the class', `file_name` varchar(255) DEFAULT NULL COMMENT 'The name of the file where the output log message is generated ', `thread_name` varchar(255) DEFAULT NULL COMMENT 'Thread name of the log event', `line` varchar(255) DEFAULT NULL COMMENT 'No. line', `all_category` varchar(255) DEFAULT NULL COMMENT 'Where the log event occurred', `message` varchar(4000) DEFAULT NULL COMMENT 'Output the message specified in the code', PRIMARY KEY (`log_id`) );
log4j.properties append
Set log4j Rootlogger = appender corresponding to trace, console and dailyfile binding
# Log level and bound Appenders (can be multiple) are separated by commas log4j.rootLogger = trace,console,logDB #mysql log4j.appender.logDB=org.apache.log4j.jdbc.JDBCAppender log4j.appender.logDB.layout=org.apache.log4j.PatternLayout log4j.appender.logDB.Driver=com.mysql.jdbc.Driver # Setting database: the database of connection information and operation (log of my database)~ log4j.appender.logDB.URL=jdbc:mysql://localhost:3306/log # Database user name log4j.appender.logDB.User=root # Database password log4j.appender.logDB.Password=ok # Set the receipt statement,%? For the data to be saved in the corresponding column, refer to PatternLayout log4j.appender.logDB.Sql=INSERT INTO log(project_name,create_date,level,category,file_name,thread_name,line,all_category,message) values('itcast','%d{yyyy-MM-dd HH:mm:ss}','%p','%c','%F','%t','%L','%l','%m')
Run test1()
Custom logger object:
Function: for multiple generation environments, different logs need to be recorded You can use custom log object class settings~
log4j.properties
# Custom logger object settings (the output log level is changed to info, and the appender also inherits rootlogger by default log4j.logger.com.wsm = info,console
Log4jTest.Java
/** Custom logger object */ @Test public void test2(){ //Get custom log object~ Logger logger = Logger.getLogger("com.wsm"); //Output~ logger.fatal("fatal A serious error, which usually causes the system to crash and terminate the operation"); logger.error("error The error message will not affect the system operation"); logger.warn("warn Warning messages, problems may occur"); logger.info("info Track information and record all process information of the program"); logger.debug("debug Debugging information is generally used in development, recording program variable parameter transfer information, etc"); logger.trace("trace Track information and record all process information of the program"); }
Only log levels greater than or equal to info are displayed~
[FATAL ]0 com.wsm.Log4jTest.test2(Log4jTest.java:57) 2021-12-19 22:35:11.558 fatal A serious error, which usually causes the system to crash and terminate the operation [ERROR ]3 com.wsm.Log4jTest.test2(Log4jTest.java:58) 2021-12-19 22:35:11.561 error The error message will not affect the system operation [WARN ]3 com.wsm.Log4jTest.test2(Log4jTest.java:59) 2021-12-19 22:35:11.561 warn Warning messages, problems may occur [INFO ]3 com.wsm.Log4jTest.test2(Log4jTest.java:60) 2021-12-19 22:35:11.561 info Track information and record all process information of the program
JCL
The full name is Jakarta common logging, which is a general logging API provided by Apache and a logging facade
It provides a unified interface for "all Java log implementations". It also provides a log implementation itself, but the function is very weak. SimpleLog is almost eliminated and will not be used alone
It allows developers to use different specific log implementation tools: Log4j, Jdk's own log (JUL)
- JCL has two basic abstract classes: Log (basic logger) and LogFactory (responsible for creating Log instances)
Getting started with JCL
Create Maven project
Add POM XML dependency
<dependencies> <!-- JCL Log dependency for --> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> <!-- junit Dependence of --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!-- log4j Dependence of! --> <!-- <dependency>--> <!-- <groupId>log4j</groupId>--> <!-- <artifactId>log4j</artifactId>--> <!-- <version>1.2.17</version>--> <!-- </dependency>--> </dependencies>
JCLTest.Java
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.Test; /** JUL Introductory case~ */ public class JCLTest { @Test public void test(){ // Obtain the log logger object, and JCL obtains a log object through a log factory; Log log = LogFactory.getLog(com.wsm.JCLTest.class); // Logging output log.info("hello jcl"); } }
The same log data as JUL is output. When log4j dependency is not introduced, JCL is implemented through JUL by default, and log4j is used
December 19, 2021 11:02:59 afternoon com.wsm.JCLTest test information: hello jcl
Switch log4j logging framework
Unlock the dependency configuration of log4j and add: dependency, configuration file log4j properties
# Set the default log object rootLogger # Log level and bound Appenders (can be multiple) are separated by commas log4j.rootLogger = trace,console # Specifies the appender for console log output log4j.appender.console = org.apache.log4j.ConsoleAppender # Specify the layout output format of console log output. The default is SimpleLayout (HTMLLayout / xml.XMLLayout / PatternLayout) log4j.appender.console.layout = org.apache.log4j.PatternLayout # Specify the content layout of the message format conversionPattern log4j.appender.console.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n
Run test(), which is the output mode of log4j
[INFO ]1 com.wsm.JCLTest.test(JCLTest.java:13) 2021-12-19 23:17:35.636 hello jcl
Summary: โญ
JCL is a log facade. With the frequent use of logs, there are many different log frameworks on the market. Developers need to master multiple log frameworks at the same time (it's not very friendly)~
Apache withdrew from a log facade to implement the interface uniformly. Both JUL and log4j implemented it.
The advantage is that developers only need to learn how to use a logging framework. Even if the logging framework is changed later, it will not have any impact on the code~ ๐ Just replace one dependency!
- JCL is SimpleLog implemented by default, but few people use it~
- JUL comes with Java, so you don't need to introduce dependencies, so you use the JUL implementation by default!
However, JCL's switching implementation for different logging frameworks
It is implemented in a hard coded form, which is compatible with a small number of log frameworks. If a new log needs to be introduced later, the configuration file needs to be changed~
Therefore, a new log facade Slf4j appears later, which can be compatible with all / and future log frameworks on the market
Slf4j
Simple Logging Facade For Java
- SLF4J is mainly to provide a set of standard and standardized API frameworks for Java log access. Its main significance is to provide interfaces. The specific implementation can be handed over to other log frameworks
- Of course slf4j, it also provides a relatively simple implementation, but it is rarely used
- Now many Java projects use slf4j API as a facade
- With specific implementation frameworks (log4j, logback, etc.), the bridge is used in the middle to complete the bridge
- Official address
The SLF4J log interface mainly provides two functions:
- Binding of log framework
- Bridging of log frame
SLF4J getting started
Create Maven project:
Import corresponding dependencies:
<!-- slf4j Log facade --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.26</version> </dependency>
Slf4jTest.Java
import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** Slf4j Introductory case */ public class Slf4jTest { //Declare a global log object public final static Logger LOGGER = LoggerFactory.getLogger(Slf4jTest.class); /** Simple introduction */ @Test public void Test(){ // Log output (default output to console info level); LOGGER.error("error"); LOGGER.warn("wring"); LOGGER.info("info"); LOGGER.debug("debug"); LOGGER.trace("trace"); // Output log information using placeholders String name = "wsm"; Integer age = 540; LOGGER.info("User:{},{}",name,age); // Output the abnormal information of the system try { int i = 1/0; } catch (Exception e) { // e.printStackTrace(); In this way, the program will not print Java stack push error LOGGER.error("Exception occurred:",e); } } }
[main] ERROR com.wsm.Slf4jTest - error [main] WARN com.wsm.Slf4jTest - wring [main] INFO com.wsm.Slf4jTest - info [main] INFO com.wsm.Slf4jTest - User: wsm,540 [main] ERROR com.wsm.Slf4jTest - Exception occurred: java.lang.ArithmeticException: / by zero at com.wsm.Slf4jTest.Test(Slf4jTest.java:29) #More exception information is omitted below~
Binding of log framework
Slf4j, as a powerful log facade, can switch between different log frameworks without changing the code Support binding of different log frameworks!
The above figure is the official picture of Slf4j, which is bound with various frameworks:
application specifies that the SLF4J API is the Slf4j log facade from left to right - > 1-6
- โ Slf4j unbound project simply introduces the log facade
โก โค โฅ logback slf4j is the built-in implementation of log4j2
They all appear after the Slf4j facade, so they are implemented. You can import the Slf4j log facade dependency and the corresponding implementation dependency between them, and the binding is completed automatically
โข โฃ it was developed before slf4j, and there is no direct implementation of slf4j facade
Therefore, before use, you need to import the corresponding Adaptation adapter for Adaptation
Using the slf4j facade method, the internal adapter calls the JUL / log4j method~
Next, let's briefly introduce the binding of each logging framework: slf4j built-in implementation. The entry case is
Logback binding
Because the class has been implemented by default, slf4j directly introduce dependencies Don't forget annotations, slf4j built-in implementation dependencies
- Not detailed here, but the use of Logback
<!--logback Log implementation--> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency>
slf4j null implementation:
Slf4j NOP can be introduced when we are not sure what logging framework to implement
It is an empty implementation of slf4j, because if the implementation of slf4j is not introduced, an error defaulting to no operation (NOP) logger implementation will be reported
- Note other dependency log dependency running program exceptions~
- Add slf4j NOP dependency and run test();
<!-- nop Log switch: slf4j An empty implementation of~ --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-nop</artifactId> <version>1.7.25</version> </dependency>
- Run, no exception, but no result
Log4j binding
Because log4j was born earlier than slf4j, it is not implemented directly. An adapter needs to be added to bind slf4j to log4j
Annotate other implementation dependencies
<!--binding log4j For log implementation, the adapter needs to be imported --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.12</version> </dependency> <!-- log4j rely on --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
An error occurred when running test(): log4j: warn no appends could be found for logger (COM. WSM. Slf4jtest)
- You need to import the corresponding appenders and add the corresponding log4j Properties configuration file~
JUL binding
As above, JUL also needs to add an adapter. Because JUL comes with JDk, you only need to introduce an adapter dependency!
<!--binding jul For log implementation, the adapter needs to be imported --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-jdk14</artifactId> <version>1.7.25</version> </dependency>
There are default configuration files in JUL and JDK
Summary: โญ
Log binding process using slf4j:
- Add slf4j API dependencies
- Use slf4j's API for unified logging in the project
Bind specific log implementation framework:
The binding has implemented slf4j's logging framework, and the corresponding dependencies are added directly
Bind the log framework that does not implement slf4j. First add the log adapter, and then add the dependency of the implementation class
- slf4j has only one log implementation framework binding (if there are multiple, the first log implementation is used by default)
Bridging of log framework
Suppose you suddenly have to maintain an older project. The boss asked you to replace the log framework log4j of the original project with logback
- What should I do? One of the two frameworks belongs to slf4j facade and the other belongs to JCL facade. It's definitely not possible to directly replace the jar package!
- What can we do? โ Remove dependencies and modify code โ That's really dog blood ๐!
Fortunately, slf4j provides bridging. Technical support developers to introduce the corresponding log bridge to complete the configuration!
log4j switch logback Demo
Slf4j module, add Log4jTest Java
import org.apache.log4j.Logger; import org.junit.Test; public class Log4jTest { // Define log4j logger public static final Logger LOGGER = Logger.getLogger(Log4jTest.class); // Test bridge @Test public void test01()throws Exception{ LOGGER.info("hello lgo4j"); } }
Don't forget that log4j needs to import the configuration file log4j Properties, run test01();
15:52:04.308 [main] INFO com.itheima.Log4jTest - hello lgo4j
The above is the code and output of log4j, and the following is the code output of switched logback
Introduce dependency: annotation log4j's dependency
<!-- Slf4j Bridging technology --> <!-- take log4j Log frame,Clear without changing the code,Replace with logback: Comment out all dependencies,Keep only JUnit --> <!-- log4j Required dependencies for --> <!-- <dependency>--> <!-- <groupId>log4j</groupId>--> <!-- <artifactId>log4j</artifactId>--> <!-- <version>1.2.17</version>--> <!-- </dependency>--> <!-- notes,log4j Implementation dependency of; --> <!--logback Log implementation--> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <!--to configure log4j Bridge for--> <dependency> <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> <version>1.7.25</version> </dependency>
December 20, 2021 4:48:50 afternoon com.wsm.log4jTest test01 information: hello lgo4j
It is found that the code remains unchanged, and the output mode has changed to logback
Reason: the log4j over Slf4j bridge internally calls the Slf4j method, which is equivalent to a redirection~
be careful โ :
log4j-over-slf4j.jar and slf4j-log4j12 Jars cannot appear at the same time
jcl-over-slf4j.jar and slf4j JCL Jars cannot appear at the same time
jul-to-slf4j.jar and slf4j-jdk14 Jars cannot appear at the same time
The log bridge cannot appear at the same time as the log implementation dependency, because the underlying layer of the log bridge still calls the interface method of slf4j Slf4j goes back to call the log implementation
If the same bridge log implementation is introduced at the same time, the log implementation -- call -- > bridge -- call -- > slf4j -- call -- > log implementation falls into an endless loop and the stack overflows!
Logback
Logback is another open source log component designed by the founder of log4j: Official address
Logback is mainly divided into three modules:
- Logback core: the basic module of the other two modules. Maven has the inheritance feature. By introducing classic/access, it has a core by default
- Logback classic: it is an improved version of log4j, and it fully implements the slf4j API
- Logback access: the access module is integrated with the Servlet container and provides the function of accessing logs through Http. It is used to directly output Tomcat/Jetty logs to the corresponding server logs!
Logback starter case:
Create Maven project
Introduce logback dependency:
<!--slf4j Log facade--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.26</version> </dependency> <!--logback Log implementation--> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <!--junti unit testing --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency>
LogbackTest.Java
import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** logBack Log entry case */ public class LogbackTest { //Create a global logger object public static final Logger LOGGER = LoggerFactory.getLogger(LogbackTest.class); @Test public void test(){ //Call Slf4j interface to realize log output; // logback has five log levels. The default level is debug LOGGER.error("error"); LOGGER.warn("wring"); LOGGER.info("info"); LOGGER.debug("debug"); LOGGER.trace("trace"); } }
Yes, the rootLogger is configured by default: console output, log level debug ๐ถ
10:28:18.657 [main] ERROR com.wsm.LogbackTest - error 10:28:18.662 [main] WARN com.wsm.LogbackTest - wring 10:28:18.662 [main] INFO com.wsm.LogbackTest - info 10:28:18.662 [main] DEBUG com.wsm.LogbackTest - debug
Logback introduction:
logback reads the following types of configuration files in turn:
- logback.groovy
- logback-test.xml
- logback. If XML does not exist, the default configuration will be adopted, and any configuration file can be created in the resources resource directory
xml format is easy to read and operate. It is also used more. This article introduces logback xml configuration file writing โ~
Relationship between logback components:
Like other logging frameworks, the output format of the log object logger is roughly the same
Logger logger object
- According to the context environment (configuration file, LoggerFactory.getLogger() generates a logger object, which is mainly used to store log objects and define log types and levels
Logger s can be assigned levels:
The levels include TRACE, DEBUG, INFO, WARN and ERROR, which are defined in ch.qos logback. classic. Level
Appender recorder
- Used to specify the destination of log output. The destination can be console, file, database, etc
Layout log output format
- It is responsible for converting events into strings and outputting formatted log information. The Layout object in logback is encapsulated in encoder
Logback configuration โ:
Getting started with profiles:
Add logback. Log in the resources directory xml
<?xml version="1.0" encoding="UTF-8"?> <!-- configuration xml Root node of,There are three properties; scan: When this property is set to true If the configuration file changes,Will be reloaded,The default value is true scanPeriod: Set the time interval for monitoring whether the configuration file is modified,If no time unit is given,The default unit is milliseconds,When scan by true Time,This property takes effect; debug: When this property is set to true Time,Print out logback Internal log information,Real time view logback Running status. The default value is false; --> <configuration scan="true" scanPeriod="60 seconds" debug="false"> <!-- contextName: Used to set the context name, each logger Are associated with logger Context, the default context name is default; Set to another name,Records used to distinguish between different applications; --> <contextName>mylog</contextName> <!-- property: Used to define variable values. It has two properties name and value,adopt<property>The defined value can be referenced by the configuration file context, ${name name} To use variables name: Name of the variable value: The value defined by the variable --> <!--Define log file save path attribute--> <property name="log_dir" value="/logs"></property> <property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n"></property> <!-- Log output format: %-5level %d{yyyy-MM-dd HH:mm:ss.SSS}date %c The full name of the class %M by method %L Is the line number %thread Thread name %m perhaps%msg For information %n Line feed --> </configuration>ใ
appender for console log output
logback.xml append:
<!-- Console log output appender It has two required properties name and class; name appoint appender name class appoint appender Fully qualified name of,Different outputs Appender There are different child element settings: --> <!-- ConsoleAppender Output log to console; <encoder>: Format log <target>: Java console output ,character string System.out(default)perhaps System.err(Red font --> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <!--Controls the default output flow object System.out Change to System.err--> <target>System.err</target> <!--Log message format configuration--> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>${pattern}</pattern> </encoder> </appender> <!-- rootlogger to configure: level: Set log output level; <appender-ref>: set up rootlogger Bound appender,Support binding multiple~ --> <root level="ALL"> <appender-ref ref="console"/> <!-- according to appender of name Property; --> </root>
Console: output system in the corresponding format Err output in red font~
[ERROR] 2021-12-21 16:54:09.008 com.itheima.LogbackTest testQuick 16 [main] error [WARN ] 2021-12-21 16:54:09.012 com.itheima.LogbackTest testQuick 17 [main] wring [INFO ] 2021-12-21 16:54:09.012 com.itheima.LogbackTest testQuick 18 [main] info [DEBUG] 2021-12-21 16:54:09.012 com.itheima.LogbackTest testQuick 19 [main] debug [TRACE] 2021-12-21 16:54:09.012 com.itheima.LogbackTest testQuick 20 [main] trace
Output log file:
logback.xml
<!-- Log file output appender--> <!-- FileAppender Add log to file; <file>: File name to be written,It can be a relative directory,It can also be an absolute directory,If the parent directory does not exist, it will be created automatically,No default value; <append>: If it is true The log is appended to the end of the file (default true; <encoder>: Format logged events; <prudent>: If it is true,The log will be safely written to the file,Even other FileAppender You are also writing to this file; (Inefficient default is false; --> <appender name="file" class="ch.qos.logback.core.FileAppender"> <!--Log file save path: ${log_dir}Introduce the above,global variable--> <file>${log_dir}/logback.log</file> <!--Log message format configuration--> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>${pattern}</pattern> </encoder> </appender> <!-- rootlogger to configure: level: Set log output level; <appender-ref>: set up rootlogger Bound appender,Support binding multiple~ --> <root level="ALL"> <appender-ref ref="console"/> <!-- according to appender of name Property; --> <appender-ref ref="file"/> </root>
Output file html
logback.xml
<!--html Format log file output appender--> <appender name="htmlFile" class="ch.qos.logback.core.FileAppender"> <!--Log file save path--> <file>${log_dir}/logback.html</file> <!--html Message format configuration--> <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"> <layout class="ch.qos.logback.classic.html.HTMLLayout"> <pattern>%-5level%d{yyyy-MM-dd HH:mm:ss.SSS}%c%M%L%thread%m</pattern> </layout> </encoder> </appender> <!-- set up: rootlogger to configure -->
Log splitting and archiving compressed / asynchronous logs
logback.xml
<!-- Log splitting and archive compression appender object--> <!-- RollingFileAppender Omission and FileAppender Same element; <rollingPolicy>: When scrolling occurs,decision RollingFileAppender act,Involves file movement and renaming. attribute class Define specific rolling policy classes; <prudent>: should be true Not supported when FixedWindowRollingPolicy, --> <appender name="rollFile" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!--Log file save path--> <file>${log_dir}/roll_logback.log</file> <!--Log message format configuration--> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>${pattern}</pattern> </encoder> <!--Specify split rules--> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <!--fileNamePattern Declare the split file name in time and compression format--> <fileNamePattern>${log_dir}/rolling.%d{yyyy-MM-dd}.log%i.gz</fileNamePattern> <!--maxFileSize Set split by file size: --> <maxFileSize>1MB</maxFileSize> <!-- maxHistory Optional node, which controls the maximum number of archived files to be retained. If the number exceeds, the old files will be deleted; --> </rollingPolicy> <!--Log level filter--> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <!--Log filtering rules <level>: Set filter level <onMatch>: Used to configure operations that meet filtering criteria <onMismatch>: Used to configure operations that do not meet the filter criteria onMatch/onMismatch Executing a filter will return enumerated values: DENY๏ผNEUTRAL๏ผACCEPT DENY The log will be discarded immediately and will not pass through other filters; NEUTRAL The next filter in the ordered list then processes the log; ACCEPT The log is processed immediately without going through the remaining filters; --> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <!-- Asynchronous log appender Support through, appender-ref Direct reference to other appender attribute~ --> <!-- AsyncAppender Write file,When will a thread start,Write out log files asynchronously~ --> <appender name="async" class="ch.qos.logback.classic.AsyncAppender"> <!--Specify a specific appender--> <appender-ref ref="rollFile"/> </appender> <!-- set up: rootlogger to configure -->
In order to see the effect, cycle 1w times of log printing~
Custom looger object
logback.xml
<!--custom looger object additivity="false" custom logger Whether the object inherits rootLogger --> <logger name="com.wsm" level="info" additivity="false"> <appender-ref ref="console"/> </logger>
Name sets the package name of the project Package name xxx the package will have a custom logger object by default. additivity can be used to set whether to inherit rootlogger
[ERROR] 2021-12-21 23:20:13.702 com.wsm.LogbackTest test 16 [main] error [WARN ] 2021-12-21 23:20:13.705 com.wsm.LogbackTest test 17 [main] wring [INFO ] 2021-12-21 23:20:13.705 com.wsm.LogbackTest test 18 [main] info
The output level becomes info
Log4j2:
Apache Log4j 2 is an upgraded version of Log4j)
Some excellent designs of logback are referenced and some problems are fixed, which brings some significant improvements:
exception handling
In logback, exceptions in the Appender are not perceived by the application, but in log4j 2, some exception handling mechanisms are provided;
Performance improvement
Compared with log4j and logback, log4j2 has obvious performance improvement. It is said that it provides more than ten times!
Auto reload configuration
Referring to the design of logback, automatic refresh parameter configuration is provided. The most practical thing is that we can dynamically modify the log level in production without restarting the application;
Garbage free mechanism
In most cases, log4j2 can use its designed garbage free mechanism to avoid frequent log collection, resulting in jvm gc;
Log4j2 entry case:
Create a Maven project:
Import dependency: POM xml
<dependencies> <!--log4j2 Log facade--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.11.1</version> </dependency> <!--log4j2 Log implementation--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.11.1</version> </dependency> <!--junit unit testing --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies>
Write an introductory case: log4j2test Java
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.junit.Test; /** log4j2 quick get start */ public class Log4j2Test { // Define the logger object logmanager getLogger(); public static final Logger LOGGER = LogManager.getLogger(Log4j2Test.class); /** quick get start */ @Test public void test(){ //log4j2 the default log level is error; LOGGER.fatal("fatal"); LOGGER.error("error"); LOGGER.warn("warn"); LOGGER.info("inf"); LOGGER.debug("debug"); LOGGER.trace("trace"); } }
ERROR StatusLogger No Log4j 2 configuration file found. Using default configuration (logging only errors to the console), or user programmatically provided configurations. Set system property 'log4j2.debug' to show Log4j 2 internal initialization logging. See https://logging.apache.org/log4j/2.x/manual/configuration.html for instructions on how to configure Log4j 2 09:38:36.825 [main] FATAL com.wsm.Log4j2Test - fatal 09:38:36.838 [main] ERROR com.wsm.Log4j2Test - error
The output result indicates that there is no corresponding configuration file!, You can create a log4j2. Log in the resources directory XML configuration file log4j2 configuration file and logback configuration file are roughly the same;
Although there are warnings in the output results, the log is still printed normally: the default log level of log4j2 is error
Log4j2 profile:
Create a log4j2. Log in the current resources directory XML and logback The XML configuration file is roughly the same~
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- status="warn" The output log level of the log framework itself monitorInterval="5" The interval between automatic loading of configuration files shall not be less than 5 seconds. The advantages are: projects in production environment,Make changes,The system will reload automatically! --> <Configuration status="debug" monitorInterval="5"> <!-- Centralized configuration attribute management,Think of: Member variable ,Use through:${name} --> <properties> <property name="LOG_HOME">/logs</property> </properties> <!--Log processing,set up appenders collection--> <Appenders> <!--console output appender target: Console output mode System.err / System.out --> <Console name="Console" target="SYSTEM_ERR"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] [%-5level] %c{36}:%L --- %m%n" /> </Console> <!--Log file output appender--> <File name="file" fileName="${LOG_HOME}/myfile.log"> <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n" /> </File> <!--Log file output using random read / write streams appender๏ผPerformance improvement--> <RandomAccessFile name="accessFile" fileName="${LOG_HOME}/myAcclog.log"> <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n" /> </RandomAccessFile> <!--Of log files split according to certain rules appender filePattern: Split file name,$${date:yyyy-MM-dd}Generate one folder per day, %i Numerical sorting~ --> <RollingFile name="rollingFile" fileName="${LOG_HOME}/myrollog.log" filePattern="/logs/$${date:yyyy-MM-dd}/myrollog-%d{yyyy-MM-dd-HH-mm}-%i.log"> <!--Log level filter--> <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" /> <!--Log message format--> <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %msg%n" /> <Policies> <!--When the system starts, start the split rule to produce a new log file--> <OnStartupTriggeringPolicy /> <!--Split by file size, 10 MB --> <SizeBasedTriggeringPolicy size="10 MB" /> <!--Split by time node, rule by filePattern Defined--> <TimeBasedTriggeringPolicy /> </Policies> <!--In the same directory, the number of files is limited to 30, exceeding which can be overwritten--> <DefaultRolloverStrategy max="30" /> </RollingFile> </Appenders> <!--logger definition--> <Loggers> <!--use rootLogger Configure log level level="trace"--> <Root level="trace"> <!--Specifies the processor used by the log--> <AppenderRef ref="Console" /> </Root> </Loggers> </Configuration>
15:41:00.743 [main] [FATAL] com.wsm.Log4j2Test:15 --- fatal 15:41:00.754 [main] [ERROR] com.wsm.Log4j2Test:16 --- error 15:41:00.754 [main] [WARN ] com.wsm.Log4j2Test:17 --- warn 15:41:00.755 [main] [INFO ] com.wsm.Log4j2Test:18 --- inf 15:41:00.755 [main] [DEBUG] com.wsm.Log4j2Test:19 --- debug 15:41:00.755 [main] [TRACE] com.wsm.Log4j2Test:20 --- trace
There is no exception information for direct output, and the log level is trace
Slf4j + log4j2
At present, the most mainstream log facade in the market is SLF4J. Log4j2 is also a log facade and has its own corresponding implementation. Now it has very powerful functions and superior performance
- Although Slf4j and logback are the same developer, log4j2 is powerful!
- Slf4j + Log4j2 should be the general trend in the future, but a recent bug is estimated to be dangerous โ
Slf4j + log4j2 integration case:
pom. Add dependency to XML:
- To use slf4j as the log facade, you need to use the adapter of log4j2:
<!--use slf4j As a log facade--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.26</version> </dependency> <!--use log4j2 Bind to your adapter--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.9.1</version> </dependency>
Rewrite slf4j the interface call method! Slf4jTest.Java
import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** slf4j + log4j2 integration */ public class Slf4jTest { //slf4j acquisition, log object method; public static final Logger LOGGER = LoggerFactory.getLogger(Slf4jTest.class); // quick get start @Test public void test01()throws Exception{ // Log output LOGGER.error("error"); LOGGER.warn("wring"); LOGGER.info("info"); LOGGER.debug("debug"); LOGGER.trace("trace"); } }
15:52:17.495 [main] [ERROR] com.wsm.Slf4jTest:16 --- error 15:52:17.500 [main] [WARN ] com.wsm.Slf4jTest:17 --- wring 15:52:17.501 [main] [INFO ] com.wsm.Slf4jTest:18 --- info 15:52:17.501 [main] [DEBUG] com.wsm.Slf4jTest:19 --- debug 15:52:17.501 [main] [TRACE] com.wsm.Slf4jTest:20 --- trace
Now the output is Slf4j data, but its bottom layer is still log4j2, so log4j2 The XML configuration file still works ๐
Asynchronous log:
The biggest feature of log4j2 is asynchronous logging. The improvement of its performance mainly benefits from asynchronous logging, which greatly improves the running efficiency of the program;
Log4j2 provides two ways to implement asynchronous logging:
- One is that the efficiency has not been greatly improved through AsyncAppender
- One is commonly used through asyncloger
Both need to add dependencies:
<!--Asynchronous log dependency--> <dependency> <groupId>com.lmax</groupId> <artifactId>disruptor</artifactId> <version>3.3.4</version> </dependency>
AsyncAppender asynchronous recorder;
The AsyncAppender method is directly in log4j2 Add the corresponding adaptation to XML;
<Appenders> <!-- Asynchronous output appender --> <Async name="Async"> <!-- Specifies the adapter that needs to be executed asynchronously: ref="Adapter name" --> <AppenderRef ref="Console"/> <!-- <AppenderRef ref="file"/> Can have more than one...--> </Async> </Appenders>
AsyncLogger asynchronous object;
AsyncLogger mode. There are two modes: Global asynchrony and hybrid asynchrony
Global asynchrony
That is, all logs are recorded asynchronously. There is no need to make any changes in the configuration file, just add a log4j2 component. Properties configuration file;
Hybrid asynchronous
You can use both synchronous log and asynchronous log in the application, which makes the log configuration more flexible
Global asynchronous object:
You only need to create a configuration file log4j2. In the resources resource directory component. Properties:
Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
Mixed asynchronous objects:
It's in log4j2 XML file, defined in < loggers >, and the class object under the corresponding package path Set to asynchronous execution
<!--logger definition--> <Loggers> <!-- Custom asynchronous logger object --> <AsyncLogger name="com.wsm" level="trace" includeLocation="false" additivity="false"> <AppenderRef ref="Console"/> </AsyncLogger> </Loggers>
Garbage free mode ๐ฎ:
Garbage collection pauses are a common cause of peak latency, and for many systems, a lot of effort is spent on controlling these pauses
Many logging frameworks allocate temporary objects during steady-state logging
Log event object, string, character array, byte array, etc. This puts pressure on the garbage collector and increases the frequency of GC pauses;
- After version 2.6, Log4j2 introduces the garbage free operation mode by default, and tries not to use temporary objects
After 2.6, the garbage free mode is used by default
log4j2.enableThreadlocals is set to true, and the object is stored in the ThreadLocal field and reused. Otherwise, a new object will be created for each log event, which is not the default value of the Web application
log4j2. If enabledirectencoders is set to true and log events are converted to text, this text will be converted to bytes without creating temporary objects. Note: since synchronization on the shared buffer is used, it is recommended to use asynchronous logger!
So, just upgrade to version 2.6~
Summary:
The performance of log4j2 logging framework is much higher than that of other frameworks. Two concepts are mainly introduced after 2.6: asynchronous logging and garbage free mode
SpringBoot integrated logging framework:
Idea spring lntializr spring constructor creates a SpringBoot project:
By default, the bottom layer of SpringBoot uses SLF4J as the log facade and logback as the log implementation
Maven dependency diagram:
It also introduces the bridging of JUL and log4j, which can be converted directly!
SpringBoot log usage
test module: demoapplicationtests Java
import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest class DemoApplicationTests { //Create logger Guide: slf4j public static final Logger LOGGER = LoggerFactory.getLogger(DemoApplicationTests.class); @Test void contextLoads() { // Print log information LOGGER.error("error"); LOGGER.warn("warn"); LOGGER.info("info"); LOGGER.debug("debug"); LOGGER.trace("trace"); } }
Omit Above SpringBoot logs
2021-12-23 15:12:08.771 ERROR 18772 --- [ main] com.wsm.demo.DemoApplicationTests : error 2021-12-23 15:12:08.771 WARN 18772 --- [ main] com.wsm.demo.DemoApplicationTests : warn 2021-12-23 15:12:08.771 INFO 18772 --- [ main] com.wsm.demo.DemoApplicationTests : info
As you can see, SpringBoot integrates Slf4j logback by default. The default log level is info. You can also use SpringBoot application Properties / YML configuration to change the configuration file!
SpringBoot configuration file โ
SpringBoot can simply modify the log configuration through the configuration file:
application.properties pro can be replaced by yml here
# Specify the log level of the user-defined logger object and directly set the root directory level; logging.level.com.wsm=trace # Specifies the format of the console output message logging.pattern.console=[%-5level] %d{yyyy-MM-dd HH:mm:ss} %c [%thread]===== %msg %n # Specify the specific path to store log files # logging. The file has expired because this setting is inconvenient to manage # logging.file=/logs/springboot.log # logging.file.path can specify the directory where the log files are stored, and the default file name is spring Log has better identification; logging.file.path=/logs/springboot/ # Specifies the log file message format logging.pattern.file=[%-5level] %d{yyyy-MM-dd HH:mm:ss} %c [%thread]===== %msg %n # Insufficient configuration files provided by Springboot It can only represent basic log configuration!
SpringBoot parsing configuration file:
Springboot is the default configuration file and only supports basic log configuration
Assign each log framework's own configuration file to the classpath; SpringBoot does not use the default configuration
Log frame | configuration file |
---|---|
Logback | logback-spring.xml or logback xml |
Log4j2 | log4j2-spring.xml or log4j2 xml |
JUL | logging.properties |
With logback spring XML example:
<?xml version="1.0" encoding="UTF-8"?> <configuration> <property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] -------- %m %n"></property> <!--Console log output appender--> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <!--Controls the default output flow object System.out Change to System.err--> <target>System.err</target> <!--Log message format configuration--> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <!-- <springProfile>: SpringBoot This supports setting different scenarios for logs~ --> <!-- development environment --> <springProfile name="dev"> <pattern>${pattern}</pattern> </springProfile> <!-- production environment --> <springProfile name="pro"> <pattern>[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] xxxxxxxx %m %n</pattern> </springProfile> </encoder> </appender> <!--custom looger object additivity="false" custom logger Whether the object inherits rootLogger --> <logger name="com.wsm" level="info" additivity="false"> <appender-ref ref="console"/> </logger> </configuration>
application.properties can be dynamically adjusted, including production environment pro and development environment dev
# Specify the specific environment used by the project spring.profiles.active=pro
Switch the environment back and forth to see the operation effect ๐
dev [ERROR] 2021-12-23 15:51:26.148 com.wsm.demo.DemoApplicationTests contextLoads 15 [main] -------- error [WARN ] 2021-12-23 15:51:26.149 com.wsm.demo.DemoApplicationTests contextLoads 16 [main] -------- warn [INFO ] 2021-12-23 15:51:26.149 com.wsm.demo.DemoApplicationTests contextLoads 17 [main] -------- info [DEBUG] 2021-12-23 15:51:26.149 com.wsm.demo.DemoApplicationTests contextLoads 18 [main] -------- debug [TRACE] 2021-12-23 15:51:26.149 com.wsm.demo.DemoApplicationTests contextLoads 19 [main] -------- trace pro [ERROR] 2021-12-23 15:52:03.623 com.wsm.demo.DemoApplicationTests contextLoads 15 [main] xxxxxxxx error [WARN ] 2021-12-23 15:52:03.623 com.wsm.demo.DemoApplicationTests contextLoads 16 [main] xxxxxxxx warn [INFO ] 2021-12-23 15:52:03.623 com.wsm.demo.DemoApplicationTests contextLoads 17 [main] xxxxxxxx info [DEBUG] 2021-12-23 15:52:03.623 com.wsm.demo.DemoApplicationTests contextLoads 18 [main] xxxxxxxx debug [TRACE] 2021-12-23 15:52:03.623 com.wsm.demo.DemoApplicationTests contextLoads 19 [main] xxxxxxxx trace
Switch log to log4j2
First, remove the logback implementation dependency and add the dependency of log4j2~
Add the dependency configuration of log4j2: POM xml
<dependencies> <!-- SpringBoot web starter Centralized dependency of --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <!--idea After execution,exclude logback Log implementation--> <exclusions> <exclusion> <artifactId>spring-boot-starter-logging</artifactId> <groupId>org.springframework.boot</groupId> </exclusion> </exclusions> </dependency> <!-- SpringBoot test starter Centralized dependency of --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--use log4j2 Log initiator for--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> </dependencies>
The output log information is the information of log4j2
[ERROR] 2021-12-23 16:04:54 com.wsm.demo.DemoApplicationTests [main]===== error [WARN ] 2021-12-23 16:04:54 com.wsm.demo.DemoApplicationTests [main]===== warn [INFO ] 2021-12-23 16:04:54 com.wsm.demo.DemoApplicationTests [main]===== info [DEBUG] 2021-12-23 16:04:54 com.wsm.demo.DemoApplicationTests [main]===== debug [TRACE] 2021-12-23 16:04:54 com.wsm.demo.DemoApplicationTests [main]===== trace [INFO ] 2021-12-23 16:04:54 com.wsm.demo.DemoApplicationTests [main]===== log4j2 info
Add the corresponding configuration file: log4j2 xml
<?xml version="1.0" encoding="UTF-8"?> <!-- status="warn" The output log level of the log framework itself monitorInterval="5" The interval between automatic loading of configuration files shall not be less than 5 seconds --> <Configuration status="trace" monitorInterval="5"> <!--Log processing--> <Appenders> <!--console output appender--> <Console name="Console" target="SYSTEM_ERR"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] [%-5level] %c{36}:%L -------------- %m%n" /> </Console> </Appenders> <!--logger definition--> <Loggers> <!--use rootLogger Configure log level level="trace"--> <Root level="trace"> <!--Specifies the processor used by the log--> <AppenderRef ref="Console" /> </Root> </Loggers> </Configuration>
The re execution output information is the configuration red font, ------------- interval in the configuration file;
ok, here's the introduction of the log. Thank you for watching! ๐๐บ