1. What is the role of Log?
With the increase of Internet applications, the business is becoming more and more complex, and the demand for recording the operation of the business is also growing. The log framework came into being. The purposes of the log framework are roughly as follows.
1.1 problem tracking
Through the log, we can trace the bug s in the program. For example, in case of exceptions caused by some dirty data, it is easy to trace the problem through the log, so as to quickly repair and solve it.
1.2 status monitoring
The running status of the system can be analyzed through the log. You can connect with other systems to analyze the running state of the current program, and find and deal with some busy time services in advance.
1.3 safety audit
Logs can be used to analyze whether there are currently unauthorized operations. Improve the security of the current business system by connecting with some audit systems.
At present, there are many log class frameworks in< Spring MVC learning (III) -- actual combat sharing of spring MVC + slf4j + log4j + logback log integration >This paper also introduces some log facade and log framework. This paper mainly introduces log4j, logback and log4j2, which are common log frameworks.
Test code in the text: https://gitee.com/leo825/spring-framework-learning-example.git
2,Log4j
2.1 introduction
Log4j is an open source component of Apache Software Foundation, which also refers to Log4j1. Log4j2 and Log4j1 are quite different, so they are analyzed separately.
Log4j has three main components:
Loggers: loggers. It can be simply understood as distinguishing log categories.
Appenders: output source. It can be simply understood as the place where the log is to be output.
Layouts: layouts. It can be simply understood as the form of log output.
The architecture of Log4j is as follows:
- Console: output to the screen;
- File: exporting to a file
- Socke: output to remote computer through network;
- Jdbc: output to database;
2.2 Loggers
The Loggers component has five levels: debug, INFO, WARN, ERROR and FATAL.
The five sectors are in order: debug < INFO < warn < ERROR < FATAL. This order represents the importance of logs. Log4j only outputs log information with a level not lower than the set level. If Loggers is set to INFO, log information of INFO, wrap, ERROR and fat levels will be output, while debug with a level lower than INFO will not be output.
Logger usage rules:
# rootLogger exists even if there is no display configuration, and the default output level is DEBUG. All other loggers inherit from rootLogger by default log4j.rootLogger = [ level ] , appenderName1, appenderName2, ... log4j.additivity.org.apache=false: express Logger Not in the father Logger of appender Output in, default to true. level : Set the minimum level of logging. The values that can be set are OFF,FATAL,ERROR,WARN,INFO,DEBUG,ALL Or a custom level, Log4j It is recommended to use only the middle four levels. By setting the level here, you can control the switch of the corresponding level of log information in the application. For example, you can set the level here INFO Level, all in the application DEBUG Level log information will not be printed. appenderName: Specifies where the log information should be output. Multiple output destinations can be specified at the same time, separated by commas. For example: log4j.rootLogger=INFO,A1,B2,C3
2.3 Appenders
The Log4j log system also provides many powerful functions, such as allowing the log to be output to different places, such as Console and Files. New Files can be generated according to the number of days or file size, and can be sent to other places in the form of stream.
The commonly used classes are described as follows:
org.apache.log4j.ConsoleAppender((console) org.apache.log4j.FileAppender((file) org.apache.log4j.DailyRollingFileAppender((one log file per day) org.apache.log4j.RollingFileAppender(When the file size reaches the specified size, a new file is generated) org.apache.log4j.WriterAppender(Send log information in stream format to any specified place)
- appenderName option:
log4j.appender.appenderName = className appenderName: custom appderName,stay log4j.rootLogger Used in settings; className: The settable values are as follows: (1)org.apache.log4j.ConsoleAppender((console) (2)org.apache.log4j.FileAppender((file) (3)org.apache.log4j.DailyRollingFileAppender((one log file per day) (4)org.apache.log4j.RollingFileAppender(When the file size reaches the specified size, a new file is generated) (5)org.apache.log4j.WriterAppender(Send log information in stream format to any specified place)
- ConsoleAppender options
Threshold=WARN: Specifies the minimum output level of log information. The default is DEBUG. ImmediateFlush=true: Indicates that all messages will be output immediately, set to false The default value is true. Target=System.err: The default value is System.out.
- FileAppender options
Threshold=WARN: Specifies the minimum output level of log information. The default is DEBUG. ImmediateFlush=true: Indicates that all messages will be output immediately, set to false The default value is true. Append=false: true Indicates that the message is added to the specified file, false The message will overwrite the specified file content. The default value is true. File=D:/logs/logging.log4j: Specify message output to logging.log4j File.
- DailyRollingFileAppender option
Threshold=WARN: Specifies the minimum output level of log information. The default is DEBUG. ImmediateFlush=true: Indicates that all messages will be output immediately, set to false The default value is true. Append=false: true Indicates that the message is added to the specified file, false The message will overwrite the specified file content. The default value is true. File=D:/logs/logging.log4j: Specifies the output of the current message to logging.log4j File. DatePattern='.'yyyy-MM: Scroll the log file once a month, that is, generate a new log file every month. The log file name of the current month is logging.log4j,The log file name of the previous month is logging.log4j.yyyy-MM. In addition, you can specify to scroll log files by week, day, hour, minute, etc. the corresponding format is as follows: 1)'.'yyyy-MM: monthly 2)'.'yyyy-ww: weekly 3)'.'yyyy-MM-dd: Every day 4)'.'yyyy-MM-dd-a: Twice a day 5)'.'yyyy-MM-dd-HH: Per hour 6)'.'yyyy-MM-dd-HH-mm: per minute
- RollingFileAppender option
Threshold=WARN: Specifies the minimum output level of log information. The default is DEBUG. ImmediateFlush=true: Indicates that all messages will be output immediately, set to false The default value is true. Append=false: true Indicates that the message is added to the specified file, false The message will overwrite the specified file content. The default value is true. File=D:/logs/logging.log4j: Specify message output to logging.log4j File. MaxFileSize=100KB: The suffix can be KB, MB perhaps GB. When the log file reaches this size, it will automatically scroll, that is, move the original content to logging.log4j.1 File. MaxBackupIndex=2: Set the maximum number of files that can be generated by scrolling to 2, for example logging.log4j.1,logging.log4j.2 Two scrolling files and one logging.log4j File.
2.4 Layouts
Log4j can complete this function by attaching layouts after Appenders. Layouts provides four log output styles, such as HTML style, freely specified style, style containing log level and information, and style containing log time, thread, category and other information.
org.apache.log4j.HTMLLayout(with HTML Tabular layout) org.apache.log4j.PatternLayout((layout mode can be specified flexibly) org.apache.log4j.SimpleLayout(Level and information string containing log information) org.apache.log4j.TTCCLayout((including log generation time, thread, category and other information)
- HTMLLayout options
LocationInfo=true: output java File name and line number. The default value is false. Title=My Logging: The default value is Log4J Log Messages.
- PatternLayout options
ConversionPattern=%m%n: Sets the format in which messages are displayed. Format symbol description: %p: Priority of output log information, i.e DEBUG,INFO,WARN,ERROR,FATAL. %d: Output the date or time of the log time point. The default format is ISO8601,You can also specify a format after it, such as:%d{yyyy/MM/dd HH:mm:ss,SSS}. %r: Output from application startup to log The number of milliseconds the message took. %t: Output the name of the thread that generated the log event. %l: The location of the output log event, equivalent to%c.%M(%F:%L)The combination of, including the full name of the class, method, file name and the number of lines in the code. For example: test.TestLog4j.main(TestLog4j.java:10). %c: The category to which the output log information belongs is usually the full name of the class. %M: Output the name of the method that generates log information. %F: The name of the file where the output log message is generated. %L:: The line number in the output code. %m:: Output the specific log information specified in the code. %n: Output a carriage return line feed, Windows "Platform is" rn",Unix "Platform is" n". %x: Outputs the associated with the current thread NDC(Nested diagnostic environment),Especially when it comes to images java servlets Such a multi client multi-threaded application. %%: "Output a"%"Character.
In addition, you can add modifiers between% and format characters to control their minimum length, maximum length, and text alignment. For example:
- c: Specify the name of the output category. The minimum length is 20. If the name length of the category is less than 20, it is aligned to the right by default.
- %-20c "-" indicates left alignment.
- %. 30c: specify the name of the output category. The maximum length is 30. If the name length of the category is greater than 30, the extra characters on the left will be truncated, but if it is less than 30, no spaces will be filled.
2.5 Log4j configuration file example
log4j. The properties configuration is as follows:
log4j.rootLogger=INFO,M,C,E log4j.additivity.monitorLogger=false # INFO level file output configuration log4j.appender.M=org.apache.log4j.DailyRollingFileAppender log4j.appender.M.File=/logs/log/log4j_info.log log4j.appender.M.ImmediateFlush=false log4j.appender.M.BufferedIO=true log4j.appender.M.BufferSize=16384 log4j.appender.M.Append=true log4j.appender.M.Threshold=INFO log4j.appender.M.DatePattern='.'yyyy-MM-dd log4j.appender.M.layout=org.apache.log4j.PatternLayout log4j.appender.M.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} %p %l %m %n # ERROR level file output configuration log4j.appender.E=org.apache.log4j.DailyRollingFileAppender log4j.appender.E.File=/logs/log/log4j_error.log log4j.appender.E.ImmediateFlush=true log4j.appender.E.Append=true log4j.appender.E.Threshold=ERROR log4j.appender.E.DatePattern='.'yyyy-MM-dd log4j.appender.E.layout=org.apache.log4j.PatternLayout log4j.appender.E.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} %p %l %m %n # Console output configuration log4j.appender.C=org.apache.log4j.ConsoleAppender log4j.appender.C.Threshold=INFO log4j.appender.C.layout=org.apache.log4j.PatternLayout log4j.appender.C.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %l %m %n
log4j. The XML configuration is as follows:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <!-- Console output configuration --> <appender name="console" class="org.apache.log4j.ConsoleAppender"> <!-- Target console --> <param name="Target" value="System.out" /> <layout class="org.apache.log4j.PatternLayout"> <!-- Output format --> <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %l %m%n" /> </layout> </appender> <!-- File output configuration --> <appender name="log_file" class="org.apache.log4j.DailyRollingFileAppender"> <!-- Target is file --> <param name="File" value="/logs/log/log4j-demo.log" /> <!-- Append output to file --> <param name="Append" value="true" /> <!-- Generate one every hour log --> <param name="DatePattern" value="'.'yyyy-MM-dd-HH" /> <layout class="org.apache.log4j.PatternLayout"> <!-- Output format --> <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %l %m%n" /> </layout> </appender> <!-- Application Loggers --> <logger name="com.demo"> <level value="info" /> </logger> <!-- root directory --> <!-- Root Logger --> <root> <priority value="info" /> <appender-ref ref="console" /> <appender-ref ref="log_file" /> </root> </log4j:configuration>
3,Log4j2
Log4j2 is log4j 1 The upgraded version of X refers to some excellent designs of logback, fixes some problems and brings significant improvements:
- Exception handling: in logback, exceptions in the Appender will not be perceived by the application, but in log4j 2, some exception handling mechanisms are provided.
- Performance improvement: compared with log4j 1 and logback, log4j2 has obvious performance improvement. There will be official test data later.
- Automatic reload configuration: referring to the design of logback, automatic refresh parameter configuration will be provided. The most practical thing is that we can dynamically modify the log level in production without restarting the application - which is very sensitive to monitoring.
- Garbage free mechanism: in most cases, log4j2 can use its designed garbage free mechanism to avoid jvm gc caused by frequent log collection.
3.1 Log4j2 configuration file example
- Synchronous output log
<?xml version="1.0" encoding="UTF-8"?> <!--status:Log4j2 Output level of internal log,Set to TRACE Research on Log4j2 Very useful --> <!--monitorInterval:Regularly detect the modification of configuration file,If there is any change, the configuration will be automatically reloaded,The unit of time is seconds,The minimum interval is 5 s --> <Configuration status="WARN" monitorInterval="600"> <!--properties:Set global variables --> <properties> <!--LOG_HOME:Specify the directory where the current log is stored --> <property name="LOG_HOME">logs</property> <!--FILE_NAME:Specifies the name of the log file --> <property name="FILE_NAME">springboot-log4j2</property> </properties> <!--Appenders:Define the destination, content and format of log output --> <Appenders> <!--Console:Log output to console standard output --> <Console name="Console" target="SYSTEM_OUT"> <!--pattern:date,Thread name,log level,Log name,log information,Line feed --> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level [%L] - %msg%n" /> </Console> <!--RollingFile:Log output to file,The following files use relative paths --> <!--fileName:The file name of the current log output --> <!--filePattern:Backup log file name, backup directory is logs The following directory named by month and year is used for backup gz Format compression --> <RollingFile name="RollingFile" fileName="${LOG_HOME}/${FILE_NAME}.log" filePattern="${LOG_HOME}/$${date:yyyy-MM}/${FILE_NAME}-%d{yyyy-MM-dd}-%i.log.gz"> <!-- Output the fully qualified name, source file name and line number of the log event caller. Note that it may affect performance. Please use it with caution. --> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level [%l] - %msg%n" /> <!--Policies:The trigger policy determines when to perform a backup --> <Policies> <!--TimeBasedTriggeringPolicy:Log files are backed up according to time --> <!--interval:A new file is generated every minute of a day, which needs to be combined filePattern time%d{yyyy-MM-dd} --> <!--Similarly, if you want to generate a new file every hour, change to%d{yyyy-MM-ddHH} --> <!--modulate:Correct the generation time of backup log based on 0,"0+interval"Determine the first backup time after startup --> <TimeBasedTriggeringPolicy interval="1" modulate="true" /> <!--SizeBasedTriggeringPolicy:Log files are backed up by size --> <!--size:Specify a maximum of 100 log files MB,The unit can be KB,MB or GB --> <SizeBasedTriggeringPolicy size="100MB" /> </Policies> <!--DefaultRolloverStrategy:The flip strategy determines how backups are performed --> <!--max:Save up to 5 log backup files. When combined with time, there will be up to 5 backups in each time period, and the extra will be overwritten --> <!--compressionLevel:Configure log compression level, range 0-9,0 No compression, 1 has the fastest compression speed and 9 has the best compression rate. At present, it is only for zip The compressed file type is valid --> <DefaultRolloverStrategy max="5" compressionLevel="1"> <!--Delete:Delete matching expired backup log files --> <!--maxDepth:Because the backup log is saved in ${LOG_HOME}/$${date:yyyy-MM},So the directory depth is set to 2 --> <Delete basePath="${LOG_HOME}" maxDepth="2"> <!--IfFileName:Match file name --> <!--glob:To match the level 2 directory depth.log.gz End of backup file --> <IfFileName glob="*/*.log.gz" /> <!--IfLastModified:Modification time of matching file --> <!--age:Match files over 180 days, unit D,H,M,S Represents day, hour, minute and second respectively--> <IfLastModified age="180D" /> </Delete> </DefaultRolloverStrategy> </RollingFile> </Appenders> <!--Loggers:Define log levels and used Appenders --> <Loggers> <!--name: Package path of the class that prints the log --> <!--additivity: true Current Logger Print log attached to Root,false Print only to RollingFile --> <Logger name="com.demo" level="DEBUG" additivity="true"> <AppenderRef ref="RollingFile" /> </Logger> <!--Root:Logs are printed to the console by default --> <!--level log level: ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF --> <Root level="INFO"> <AppenderRef ref="Console" /> </Root> </Loggers> </Configuration>
- Asynchronous output log
<?xml version="1.0" encoding="UTF-8"?> <!--status:Log4j2 Output level of internal log,Set to TRACE Research on Log4j2 Very useful --> <!--monitorInterval:Regularly detect the modification of configuration file,If there is any change, the configuration will be automatically reloaded,The unit of time is seconds,The minimum interval is 5 s --> <Configuration status="WARN" monitorInterval="600"> <!--properties:Set global variables --> <properties> <!--LOG_HOME:Specify the directory where the current log is stored --> <property name="LOG_HOME">logs</property> <!--FILE_NAME:Specifies the name of the log file --> <property name="FILE_NAME">springboot-log4j2</property> </properties> <!--Appenders:Define the destination, content and format of log output --> <Appenders> <!--Console:Log output to console standard output --> <Console name="Console" target="SYSTEM_OUT"> <!--pattern:date,Thread name,log level,Log name,log information,Line feed --> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level [%L] - %msg%n" /> </Console> <!--RollingFile:Log output to file,The following files use relative paths --> <!--fileName:The file name of the current log output --> <!--filePattern:Backup log file name, backup directory is logs The following directory named by month and year is used for backup gz Format compression --> <RollingFile name="RollingFile" fileName="${LOG_HOME}/${FILE_NAME}.log" filePattern="${LOG_HOME}/$${date:yyyy-MM}/${FILE_NAME}-%d{yyyy-MM-dd}-%i.log.gz"> <!-- Note that the use of fully qualified log file names and event source names may affect the performance of the caller. --> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level [%l] - %msg%n" /> <!--Policies:The trigger policy determines when to perform a backup --> <Policies> <!--TimeBasedTriggeringPolicy:Log files are backed up according to time --> <!--interval:A new file is generated every minute of a day, which needs to be combined filePattern time%d{yyyy-MM-dd} --> <!--Similarly, if you want to generate a new file every hour, change to%d{yyyy-MM-ddHH} --> <!--modulate:Correct the generation time of backup log based on 0,"0+interval"Determine the first backup time after startup --> <TimeBasedTriggeringPolicy interval="1" modulate="true" /> <!--SizeBasedTriggeringPolicy:Log files are backed up by size --> <!--size:Specify a maximum of 100 log files MB,The unit can be KB,MB or GB --> <SizeBasedTriggeringPolicy size="100MB" /> </Policies> <!--DefaultRolloverStrategy:The flip strategy determines how backups are performed --> <!--max:Save up to 5 log backup files. When combined with time, there will be up to 5 backups in each time period, and the extra will be overwritten --> <!--compressionLevel:Configure log compression level, range 0-9,0 No compression, 1 has the fastest compression speed and 9 has the best compression rate. At present, it is only for zip The compressed file type is valid --> <DefaultRolloverStrategy max="5" compressionLevel="1"> <!--Delete:Delete matching expired backup log files --> <!--maxDepth:Because the backup log is saved in ${LOG_HOME}/$${date:yyyy-MM},So the directory depth is set to 2 --> <Delete basePath="${LOG_HOME}" maxDepth="2"> <!--IfFileName:Match file name --> <!--glob:To match the level 2 directory depth.log.gz End of backup file --> <IfFileName glob="*/*.log.gz" /> <!--IfLastModified:Modification time of matching file --> <!--age:Match files over 180 days, unit D,H,M,S Represents day, hour, minute and second respectively--> <IfLastModified age="180D" /> </Delete> </DefaultRolloverStrategy> </RollingFile> </Appenders> <!--Loggers:Define log levels and used Appenders --> <Loggers> <!--name: Package path of the class that prints the log --> <!--additivity: true Current Logger Print log attached to Root,false Print only to RollingFile --> <!-- <Logger name="com.demo" level="DEBUG" additivity="true">--> <!-- <AppenderRef ref="RollingFile" />--> <!-- </Logger>--> <!--Root:Logs are printed to the console by default --> <!--level log level: ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF --> <!-- <Root level="INFO">--> <!-- <AppenderRef ref="Console" />--> <!-- </Root>--> <!--Fully asynchronous output info Log information above level--> <asyncRoot level="INFO" includeLocation="true"> <appender-ref ref="Console" /> <appender-ref ref="RollingFile" /> </asyncRoot> </Loggers> </Configuration>
4,Logback
Logback is a log open source framework upgraded by the founder of log4j on the basis of log4j. Logback is mainly divided into three modules:
- Logback core: core code module
- Logback classic: an improved version of log4j, which also implements the interface of slf4j, so it's easy for you to switch other log components later
- Logback access: the access module is integrated with the Servlet container and provides the function of accessing logs through Http
4.1 example of logback configuration file
- Synchronous output log
<?xml version="1.0" encoding="UTF-8"?> <configuration> <include resource="org/springframework/boot/logging/logback/base.xml"/> <include resource="com/zyc/datamonitor/logback/monitor.xml" optional="true"/> <property name="FILE_PATH_ERROR" value="/logs/log/logback-error.log"/> <property name="FILE_PATH_WARN" value="/logs/log/logback-warn.log"/> <property name="FILE_PATH_INFO" value="/logs/log/logback-info.log"/> <property name="FILE_PATH_DEBUG" value="/logs/log/logback-debug.log"/> <!-- console output --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <!--Format output:%d Indicates the date,%thread Represents the thread name,%-5level: The level is displayed 5 characters wide from the left%msg: Log messages,%n Is a newline character --> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%thread] %logger{50} - %msg%n </pattern> <charset>UTF-8</charset> </encoder> </appender> <!-- Generate log files on a daily basis --> <appender name="FILE-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!--The file name of the log file output --> <File>${FILE_PATH_ERROR}</File> <!--Rolling logs are based on time and file size--> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <!-- Save format of rolling log file --> <FileNamePattern>${FILE_PATH_ERROR}.%d{yyyy-MM-dd}.%i.log</FileNamePattern> <MaxFileSize>60MB</MaxFileSize> <totalSizeCap>5GB</totalSizeCap> <MaxHistory>10</MaxHistory> </rollingPolicy> <!-- Filter logs by threshold: below ERROR The following levels are abandoned --> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>ERROR</level> </filter> <encoder> <!--Format output:%d Indicates the date,%thread Represents the thread name,%-5level: The level is displayed 5 characters wide from the left%msg: Log messages,%n Is a newline character --> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%thread] %logger{50} - %msg%n </pattern> <charset>UTF-8</charset> </encoder> </appender> <appender name="FILE-INFO" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!--The file name of the log file output --> <File>${FILE_PATH_INFO}</File> <!--Rolling logs are based on time and file size--> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <!-- Save format of rolling log file --> <FileNamePattern>${FILE_PATH_INFO}.%d{yyyy-MM-dd}.%i.log</FileNamePattern> <MaxFileSize>60MB</MaxFileSize> <totalSizeCap>5GB</totalSizeCap> <MaxHistory>10</MaxHistory> </rollingPolicy> <!-- Filter logs by threshold: below INFO The following levels are abandoned --> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>INFO</level> </filter> <encoder> <!--Format output:%d Indicates the date,%thread Represents the thread name,%-5level: The level is displayed 5 characters wide from the left%msg: Log messages,%n Is a newline character --> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%thread] %logger{50} - %msg%n </pattern> <charset>UTF-8</charset> </encoder> </appender> <appender name="FILE-WARN" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!--The file name of the log file output --> <File>${FILE_PATH_WARN}</File> <!--Rolling logs are based on time and file size--> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <!-- Save format of rolling log file --> <FileNamePattern>${FILE_PATH_WARN}.%d{yyyy-MM-dd}.%i.log</FileNamePattern> <MaxFileSize>60MB</MaxFileSize> <totalSizeCap>5GB</totalSizeCap> <MaxHistory>10</MaxHistory> </rollingPolicy> <!-- Filter logs by threshold: below WARN The following levels are abandoned --> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>WARN</level> </filter> <!-- Filter logs according to specified rules --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>DENY</onMatch><!-- ERROR Level abandoned --> <onMismatch>NEUTRAL</onMismatch><!-- Continue processing at other levels --> </filter> <encoder> <!--Format output:%d Indicates the date,%thread Represents the thread name,%-5level: The level is displayed 5 characters wide from the left%msg: Log messages,%n Is a newline character --> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%thread] %logger{50} - %msg%n </pattern> <charset>UTF-8</charset> </encoder> </appender> <appender name="FILE-DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!--The file name of the log file output --> <File>${FILE_PATH_DEBUG}</File> <!--Rolling logs are based on time and file size--> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <!-- Save format of rolling log file --> <FileNamePattern>${FILE_PATH_DEBUG}.%d{yyyy-MM-dd}.%i.log</FileNamePattern> <MaxFileSize>60MB</MaxFileSize> <totalSizeCap>5GB</totalSizeCap> <MaxHistory>10</MaxHistory> </rollingPolicy> <!-- Filter logs by threshold: below INFO The following levels are abandoned --> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>DEBUG</level> </filter> <!-- Do not filter logs --> <encoder> <!--Format output:%d Indicates the date,%thread Represents the thread name,%-5level: The level is displayed 5 characters wide from the left%msg: Log messages,%n Is a newline character --> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%thread] %logger{50} - %msg%n </pattern> <charset>UTF-8</charset> </encoder> </appender> <!-- If additivity Set as true,Zezi Logger Not just on your own appender Output in, but also in root of logger of appender Inner output --> <springProfile name="test,dev"> <logger name="org.springframework" level="INFO" additivity="false"> <appender-ref ref="STDOUT"/> <appender-ref ref="FILE-ERROR"/> <appender-ref ref="FILE-WARN"/> <appender-ref ref="FILE-INFO"/> <appender-ref ref="FILE-DEBUG"/> </logger> <logger name="org.springframework" level="INFO" additivity="false"> <appender-ref ref="STDOUT"/> <appender-ref ref="FILE-ERROR"/> <appender-ref ref="FILE-WARN"/> <appender-ref ref="FILE-INFO"/> <appender-ref ref="FILE-DEBUG"/> </logger> <logger name="com.netflix" level="INFO" additivity="false"> <appender-ref ref="STDOUT"/> <appender-ref ref="FILE-ERROR"/> <appender-ref ref="FILE-WARN"/> <appender-ref ref="FILE-INFO"/> <appender-ref ref="FILE-DEBUG"/> </logger> <logger name="com.demo" level="INFO" additivity="false"> <appender-ref ref="STDOUT"/> <appender-ref ref="FILE-ERROR"/> <appender-ref ref="FILE-WARN"/> <appender-ref ref="FILE-INFO"/> <appender-ref ref="FILE-DEBUG"/> </logger> <logger name="java.sql" level="DEBUG" additivity="false"> <appender-ref ref="STDOUT"/> <appender-ref ref="FILE-ERROR"/> <appender-ref ref="FILE-WARN"/> <appender-ref ref="FILE-INFO"/> <appender-ref ref="FILE-DEBUG"/> </logger> <!-- Log output level --> <root level="INFO"> <appender-ref ref="STDOUT"/> <appender-ref ref="FILE-ERROR"/> <appender-ref ref="FILE-WARN"/> <appender-ref ref="FILE-INFO"/> <appender-ref ref="FILE-DEBUG"/> </root> </springProfile> <springProfile name="prod,default"> <logger name="org.springframework" level="WARN" additivity="false"> <appender-ref ref="FILE-ERROR"/> <appender-ref ref="FILE-WARN"/> <appender-ref ref="FILE-INFO"/> </logger> <logger name="com.netflix" level="WARN" additivity="false"> <appender-ref ref="FILE-ERROR"/> <appender-ref ref="FILE-WARN"/> <appender-ref ref="FILE-INFO"/> </logger> <logger name="com.demo" level="INFO" additivity="false"> <appender-ref ref="STDOUT"/> <appender-ref ref="FILE-ERROR"/> <appender-ref ref="FILE-WARN"/> <appender-ref ref="FILE-INFO"/> </logger> <logger name="java.sql" level="INFO" additivity="false"> <appender-ref ref="STDOUT"/> <appender-ref ref="FILE-ERROR"/> <appender-ref ref="FILE-WARN"/> <appender-ref ref="FILE-INFO"/> </logger> <!-- Log output level --> <root level="WARN"> <!-- Remove screen printing in production environment to improve performance --> <appender-ref ref="FILE-ERROR"/> <appender-ref ref="FILE-WARN"/> <appender-ref ref="FILE-INFO"/> <appender-ref ref="FILE-INFO"/> </root> </springProfile> </configuration>
- Asynchronous output log
<?xml version="1.0" encoding="UTF-8"?> <configuration scan="true" scanPeriod="120 seconds" debug="false"> <!-- scan: When this property is set to true If the configuration file changes, it 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 This property takes effect when. The default interval is 1 minute. debug: When this property is set to true When, it will be printed out logback Internal log information, real-time viewing logback Operation status. The default value is false. --> <include resource="com/zyc/log/base/logback.xml" optional="true"/> <include resource="com/zyc/log/base/zyc-monitor-logback.xml" optional="true"/> <include resource="com/zyc/log/base/zyc-commons-logback.xml" optional="true"/> <!-- root The log will be output to catalina In the log, the default application does not need to be set. --> <!-- Error log path --> <property name="FILE_PATH_ERROR" value="/logs/log/logback-error.log"/> <property name="FILE_PATH_WARN" value="/logs/log/logback-warn.log"/> <property name="FILE_PATH_INFO" value="/logs/log/logback-info.log"/> <property name="FILE_PATH_DEBUG" value="/logs/log/logback-debug.log"/> <!-- Asynchronous log extraction caller data ID true/false --> <property name="includeCallerData" value="true"/> <!-- Queue capacity of asynchronous logs --> <property name="queueSize" value="256"/> <!--Format output:%d Indicates the date,%thread Represents the thread name,%-5level: The level is displayed 5 characters wide from the left%msg: Log messages,%n Is a newline character --> <property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%thread] [%c][%M][%L] - %msg%n"/> <!-- Color log --> <!-- Rendering classes dependent on color logs --> <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/> <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/> <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/> <!-- Color log format --> <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%thread]){faint} %clr(%-40.40logger{39}){cyan} %L %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/> <!-- console output --> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>${CONSOLE_LOG_PATTERN}</pattern> <charset>UTF-8</charset> </encoder> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>${CONSOLE_LOG_PATTERN}</pattern> </layout> </appender> <appender name="CONSOLE-ASYNC" class="ch.qos.logback.classic.AsyncAppender"> <discardingThreshold>0</discardingThreshold> <queueSize>${queueSize}</queueSize> <includeCallerData>${includeCallerData}</includeCallerData> <appender-ref ref="CONSOLE"/> </appender> <!-- Generate log files on a daily basis --> <appender name="FILE-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!--The file name of the log file output --> <File>${FILE_PATH_ERROR}</File> <!--Rolling logs are based on time and file size--> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <!-- Save format of rolling log file --> <FileNamePattern>${FILE_PATH_ERROR}.%d{yyyy-MM-dd}.%i.log</FileNamePattern> <!--Compression format--> <!--<FileNamePattern>${FILE_PATH_ERROR}.%d{yyyy-MM-dd}.%i.log.gz</FileNamePattern>--> <MaxFileSize>60MB</MaxFileSize> <totalSizeCap>2GB</totalSizeCap> <MaxHistory>10</MaxHistory> </rollingPolicy> <!-- Filter logs by threshold: below ERROR The following levels are abandoned --> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>ERROR</level> </filter> <encoder> <pattern>${LOG_PATTERN}</pattern> <charset>UTF-8</charset> </encoder> </appender> <appender name="FILE-ERROR-ASYNC" class="ch.qos.logback.classic.AsyncAppender"> <!-- Do not lose logs.default,If 80 of the queue%already expired,Will be discarded TRACT,DEBUG,INFO Level log --> <discardingThreshold>0</discardingThreshold> <!-- Change the depth of the default queue,This value affects performance.The default value is 256 --> <queueSize>${queueSize}</queueSize> <includeCallerData>${includeCallerData}</includeCallerData> <appender-ref ref="FILE-ERROR"/> </appender> <appender name="FILE-INFO" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!--The file name of the log file output --> <File>${FILE_PATH_INFO}</File> <!--Rolling logs are based on time and file size--> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <!-- Save format of rolling log file --> <FileNamePattern>${FILE_PATH_INFO}.%d{yyyy-MM-dd}.%i.log</FileNamePattern> <MaxFileSize>60MB</MaxFileSize> <totalSizeCap>2GB</totalSizeCap> <MaxHistory>10</MaxHistory> </rollingPolicy> <!-- Filter logs by threshold: below INFO The following levels are abandoned --> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>INFO</level> </filter> <encoder> <pattern>${LOG_PATTERN}</pattern> <charset>UTF-8</charset> </encoder> </appender> <appender name="FILE-INFO-ASYNC" class="ch.qos.logback.classic.AsyncAppender"> <!-- Do not lose logs.default,If 80 of the queue%already expired,Will be discarded TRACT,DEBUG,INFO Level log --> <discardingThreshold>0</discardingThreshold> <!-- Change the depth of the default queue,This value affects performance.The default value is 256 --> <queueSize>${queueSize}</queueSize> <includeCallerData>${includeCallerData}</includeCallerData> <appender-ref ref="FILE-INFO"/> </appender> <appender name="FILE-DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!--The file name of the log file output --> <File>${FILE_PATH_DEBUG}</File> <!--Rolling logs are based on time and file size--> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <!-- Save format of rolling log file --> <FileNamePattern>${FILE_PATH_DEBUG}.%d{yyyy-MM-dd}.%i.log</FileNamePattern> <MaxFileSize>60MB</MaxFileSize> <totalSizeCap>2GB</totalSizeCap> <MaxHistory>10</MaxHistory> </rollingPolicy> <!-- Filter logs by threshold: below INFO The following levels are abandoned --> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>DEBUG</level> </filter> <!-- Do not filter logs --> <encoder> <pattern>${LOG_PATTERN}</pattern> <charset>UTF-8</charset> </encoder> </appender> <appender name="FILE-DEBUG-ASYNC" class="ch.qos.logback.classic.AsyncAppender"> <!-- Do not lose logs.default,If 80 of the queue%already expired,Will be discarded TRACT,DEBUG,INFO Level log --> <discardingThreshold>0</discardingThreshold> <!-- Change the depth of the default queue,This value affects performance.The default value is 256 --> <queueSize>${queueSize}</queueSize> <includeCallerData>${includeCallerData}</includeCallerData> <appender-ref ref="FILE-DEBUG"/> </appender> <!-- spring Multi environment deployment can be used separately--> <springProfile name="test,dev"> <logger name="org.springframework" level="INFO" additivity="false"> <appender-ref ref="CONSOLE-ASYNC"/> <appender-ref ref="FILE-ERROR-ASYNC"/> <appender-ref ref="FILE-INFO-ASYNC"/> <appender-ref ref="FILE-DEBUG-ASYNC"/> </logger> <logger name="o.springframework" level="INFO" additivity="false"> <appender-ref ref="CONSOLE-ASYNC"/> <appender-ref ref="FILE-ERROR-ASYNC"/> <appender-ref ref="FILE-INFO-ASYNC"/> <appender-ref ref="FILE-DEBUG-ASYNC"/> </logger> <logger name="com.netflix" level="INFO" additivity="false"> <appender-ref ref="CONSOLE-ASYNC"/> <appender-ref ref="FILE-ERROR-ASYNC"/> <appender-ref ref="FILE-INFO-ASYNC"/> <appender-ref ref="FILE-DEBUG-ASYNC"/> </logger> <logger name="java.sql" level="DEBUG" additivity="false"> <appender-ref ref="CONSOLE-ASYNC"/> <appender-ref ref="FILE-ERROR-ASYNC"/> <appender-ref ref="FILE-INFO-ASYNC"/> <appender-ref ref="FILE-DEBUG-ASYNC"/> </logger> <logger name="com.demo" level="DEBUG" additivity="false"> <appender-ref ref="FILE-DEBUG-ASYNC"/> <appender-ref ref="CONSOLE-ASYNC"/> </logger> <logger name="com.demo" level="INFO" additivity="false"> <appender-ref ref="FILE-ERROR-ASYNC"/> <appender-ref ref="FILE-INFO-ASYNC"/> <appender-ref ref="FILE-DEBUG-ASYNC"/> </logger> <!-- Log output level --> <root level="INFO"> <appender-ref ref="CONSOLE-ASYNC"/> <appender-ref ref="FILE-ERROR-ASYNC"/> <appender-ref ref="FILE-INFO-ASYNC"/> <appender-ref ref="FILE-DEBUG-ASYNC"/> </root> </springProfile> <springProfile name="prod,default"> <logger name="org.springframework" level="WARN" additivity="false"> <appender-ref ref="CONSOLE-ASYNC"/> <appender-ref ref="FILE-ERROR-ASYNC"/> <appender-ref ref="FILE-INFO-ASYNC"/> </logger> <logger name="com.netflix" level="WARN" additivity="false"> <appender-ref ref="FILE-ERROR-ASYNC"/> <appender-ref ref="FILE-INFO-ASYNC"/> </logger> <logger name="java.sql" level="INFO" additivity="false"> <appender-ref ref="FILE-ERROR-ASYNC"/> <appender-ref ref="FILE-INFO-ASYNC"/> <appender-ref ref="CONSOLE-ASYNC"/> </logger> <logger name="com.demo" level="INFO" additivity="false"> <appender-ref ref="CONSOLE-ASYNC"/> <appender-ref ref="FILE-ERROR-ASYNC"/> <appender-ref ref="FILE-INFO-ASYNC"/> </logger> <!-- Log output level --> <root level="INFO"> <appender-ref ref="FILE-ERROR-ASYNC"/> <appender-ref ref="FILE-INFO-ASYNC"/> </root> </springProfile> </configuration>
5. Springboot integrated logging component
The default integration of springboot is the logback log component. Of course, you can change it to other components according to your needs. It is recommended to use lombok here. You can instantiate the log component with a simple annotation @Slf4j.
5.1 Springboot integration Log4j
- Add maven dependency
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <!-- exclude logback assembly --> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <!-- exclude logback assembly --> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <!-- add to log4j Dependence of,It's the latest version. No one has maintained it since September 2016 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j</artifactId> <version>1.3.8.RELEASE</version> </dependency>
- Add log4j Properties configuration file
- Test code
package com.demo.log4j; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @Slf4j @RestController public class TestController { /** * Get a log component, or use lombok's @ Slf4j annotation */ private static final Logger logger = LoggerFactory.getLogger(TestController.class); @GetMapping("/helloLog4j") public String testDemo() { log.trace("hello trace"); log.debug("hello debug"); log.info("hello info"); log.warn("hello warn"); log.error("hello error"); return "Hello Log4j!"; } }
5.2 Springboot integration Log4j2
- Add maven dependency
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <!-- exclude logback assembly --> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <!-- exclude logback assembly --> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <!-- add to log4j2 of starter --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> <!--log4j2 Asynchronous output log dependency,If asynchronous log output is not used, this dependency can be omitted--> <dependency> <groupId>com.lmax</groupId> <artifactId>disruptor</artifactId> <version>3.4.2</version> </dependency>
- Add log4j Properties configuration file
- Test code
package com.demo.log4j2; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController @Slf4j public class TestController { /** * Get a log component, or use lombok's @ Slf4j annotation */ private static final Logger logger = LoggerFactory.getLogger(TestController.class); @GetMapping("/helloLog4j2") public String testDemo() { log.trace("hello trace"); log.debug("hello debug"); log.info("hello info"); log.warn("hello warn"); log.error("hello error"); return "Hello Log4j2!"; } }
5.3 Springboot integration Logback
The default integration of springboot is logback. There is no need to add the dependency of logback.
- Customize the logback configuration file. Note that the file name is logback spring xml
- Test code
package com.demo.logback; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @Slf4j @RestController public class TestController { /** * Get a log component, or use lombok's @ Slf4j annotation */ private static final Logger logger = LoggerFactory.getLogger(TestController.class); @GetMapping("/helloLogback") public String testDemo() { log.trace("hello trace"); log.debug("hello debug"); log.info("hello info"); log.warn("hello warn"); log.error("hello error"); return "Hello Logback!"; } }
6. Performance test
-
Test host configuration
-
Test code
@GetMapping("/testCostTime") public String testCostTime() { long sum = 0; for (int i = 0; i < 5; i++) { sum += costTime(); } return "log4j cost time " + (sum / 5) + " ms"; } /** * Time consuming of single test * * @return */ private long costTime() { long start = System.currentTimeMillis(); for (int i = 0; i < 50000; i++) { log.info("hello info"); } long end = System.currentTimeMillis(); return end - start; }
- test result
Under the condition of synchronization, 5000 logs in 5 cycles take an average time
project | log4j | log4j2 | logback |
---|---|---|---|
Plain text time (ms) | 2548 | 2448 | 141 |
Plain text + console time (ms) | 3112 | 2778 | 256 |
Under asynchronous conditions, 5000 logs in 5 cycles take an average time
project | log4j | log4j2 | logback |
---|---|---|---|
Plain text time (ms) | Not tested | 2227 | 2458 |
Plain text + console time (ms) | Not tested | 2403 | 2713 |
The test results show that:
- Console output in production environment is not recommended;
- In the environment of pure file output, the output of logback is better than log4j2, and log4j2 is better than log4j. If the production environment is to be deployed, logback is recommended. If log4j2 is used, asynchronous output is recommended, and the output result is basically real-time output;