preamble
in the pipelinelog systemis essential , the more popular logging frameworks are log4j, logback , etc., you may not know , the author of these two frameworks is the same person , Logback is intended to be the successor version of the popular log4j project , so as to restore log4j left the position.
In addition, slf4j (Simple Logging Facade for Java) is a logging facade framework that provides commonly used interfaces in logging systems, logback andlog4j The implementation of slf4j is done on the other hand.
In this article we will talk about how to apply in SpringBoot logback + slf4j to achieve logging .
Why use logback
- Logback is a log4j framework developed by the authors of a new generation of logging framework , it is more efficient , able to adapt to a number of operating environments , while naturally supporting SLF4J.
- Logback's customization is more flexible , but also SpringBoot's built-in logging framework .
start using
I. Adding dependencies
In practice, we introduce thespring-boot-starter-web
dependency will suffice, sincespring-boot-starter-web
incorporatesspring-boot-starter
。
(indicates contrast)spring-boot-starter
incorporatesspring-boot-starter-logging
So we just need to introduce the web component.
-
<dependency>
-
<groupId></groupId>
-
<artifactId>spring-boot-starter-web</artifactId>
-
</dependency>
II. Default configuration
By default SpringBoot outputs logs to the console and does not write to the log file.
If you want to write log files other than console output, you need to set the or property in.
Note: They cannot be used at the same time; if they are used at the same time, only one will take effect.
- = filename (sets the file, either as an absolute or relative path. Example: =)
- = path to log file (sets the directory where the file will be created and the contents of the log will be written. Example: = /var/log)
- . Package name = log level under the specified package
- = Log printing rules
You can see that this approach is simple to configure, but the functionality that can be achieved is also very limited, if you want more complex needs, you need the following customized configuration.
III. Detailed explanations
SpringBoot's official recommendation is to prioritize the use of the-spring
file name as your logging configuration (e.g., using theInstead of
), named
logging configuration file, put the xml into the
src/main/resource
Below.
It is also possible to use a customized name, such asYou only need to use the
=classpath:
Just specify.
Before we get to that, let's look at three words:
- Logger
- Appenders
- Layouts
Logback is based on three main classes: Logger, Appender and Layout.
These three types of components work in tandem to enable developers to log messages based on message type and level, and to control the formatting of those messages and where they are reported at runtime.
A basic xml configuration is first given below:
-
<configuration>
-
-
<appender name="STDOUT" class="">
-
<!-- encoders are assigned the type
-
ch. by default -->
-
<encoder>
-
<pattern>%d{HH:mm:} [%thread] %-5level %logger{36} - %msg%n</pattern>
-
</encoder>
-
</appender>
-
-
<logger name="" level="INFO"/>
-
-
<!-- Strictly speaking, the level attribute is not necessary since -->
-
<!-- the level of the root level is set to DEBUG by default. -->
-
<root level="DEBUG">
-
<appender-ref ref="STDOUT" />
-
</root>
-
-
</configuration>
3.1、<configuration>
elemental
The basic structure of a configuration file can be described as<configuration>
element containing zero or more<appender>
element, followed by zero or more<logger>
element, followed by up to one<root>
element (or none at all).
The figure below illustrates this basic structure:
Configuration element
3.2、<logger>
elemental
<logger>
element accepts only a required name attribute, an optional level attribute, and an optional additivity attribute, which is allowed to be either true or false.
The value of the level attribute allows a case-insensitive string value of TRACE, DEBUG, INFO, WARN, ERROR, ALL, or OFF.
<logger>
element can contain zero or more<appender-ref>
Elements.
Each appender referenced in this way is added to the specified logger, with inheritance at the logger element level.
Example 1: A level has been assigned to the root logger only. The level value DEBUG is inherited by the other loggers X, and.
Succession - Example 1
Example 2: All loggers have a specified level value. Level inheritance does not work.
Succession - Example 2
Example 3: Loggers root, X, and are assigned DEBUG, INFO, and ERROR levels, respectively, and the logger inherits its level values from its parent, X. The loggers are assigned DEBUG, INFO, and ERROR levels.
Succession - Example 3
Example 4: Loggers root and X are assigned DEBUG and INFO levels, respectively. The loggers and inherit their level values from their nearest parent, X, which has the specified level.
Succession - Example 4
3.3、<root>
elemental
<root>
element configures the root logger.
It supports a single attribute, the level attribute.
It does not allow any other attributes because the additivity flag does not apply to the root logger.
In addition, since the root logger has been named ROOT, it is also not allowed to use the name attribute.
The value of the level attribute can be one of the case-insensitive strings TRACE, DEBUG, INFO, WARN, ERROR, ALL, or OFF.
<root>
element can contain zero or more<appender-ref>
Elements.
Each appender referenced in this way is added to the root logger.
3.4、<appender>
elemental
appender uses<appender>
element configuration, which takes the two required attributes name and class.
The name attribute specifies the name of the appender, while the class attribute specifies the fully qualified name of the appender class to be instantiated.
<appender>
element can contain zero or one<layout>
Element, zero or more<encoder>
elements and zero or more<filter>
Elements.
The diagram below illustrates common structures:
appender element
Important: In logback, the output target is called an appender, and the addAppender method adds the appender to the given logger logger.
Each enabled logging request for a given logger will be forwarded to all appenders in that logger, as well as to appenders higher in the hierarchy. In other words, appenders are additionally inherited from the logger hierarchy.
For example, if the console appender is added to the root logger, all enabled logging requests will be printed at least on the console.
If a file appender is additionally added to the logger (e.g., L), logging requests enabled for L and children of L will be printed on the file and console.
This default behavior can be overridden by setting the logger's additivity flag to false so that no more appender accumulations are added.
Appender is an interface that has a number of subinterfaces and implementation classes, as shown below:
Appender
The two most important Appenders are: ConsoleAppender, RollingFileAppender.
3.4.1、ConsoleAppender
ConsoleAppender, as the name suggests, outputs logs to the console.
3.4.2、RollingFileAppender
RollingFileAppender, a subclass of FileAppender, extends FileAppender with the ability to flip log files.
For example, RollingFileAppender can log to a file named file and change its logging destination to another file once a certain condition is met.
There are two important subcomponents that interact with RollingFileAppender.
- RollingPolicy: responsible for performing the operations required for the rollover.
- TriggeringPolicy: will determine if and when a rollover occurs.
So RollingPolicy is responsible for what and TriggeringPolicy is responsible for when.
As any use, RollingFileAppender must set both RollingPolicy and TriggeringPolicy.
However, if its RollingPolicy also implements the TriggeringPolicy interface, only the former needs to be explicitly specified.
3.4.3. Rolling strategy
TimeBasedRollingPolicy: probably the most popular rollover policy. It defines the rollover policy based on time, e.g. by day or by month.
TimeBasedRollingPolicy takes responsibility for rolling and triggering said rollover. In fact, TimeBasedTriggeringPolicy implements the RollingPolicy and TriggeringPolicy interfaces.
SizeAndTimeBasedRollingPolicy: Sometimes you may want to archive files by date, but at the same time limit the size of each log file, especially if the post-processing tool imposes a size limit on the log file.
To fulfill this requirement, logback provides SizeAndTimeBasedRollingPolicy, which is a subclass of TimeBasedRollingPolicy that implements a roll policy based on time and log file size.
3.5、<encoder>
elemental
The most important attribute in the encoder is the pattern attribute, which is responsible for controlling the format of the output log, here is an example I wrote myself:
%d{yyyy-MM-dd HH:mm:} %highlight(%-5level) --- [%15.15(%thread)] %cyan(%-40.40(%logger{40})) : %msg%n
output format
-
%d{yyyy-MM-dd HH:mm:}: date
-
%-5level: log level
-
%highlight(): color, info is blue, warn is light red, error is bold red, and debug is black.
-
%thread: the thread that prints the logs
-
%15.15(): if the length of the recorded thread characters is less than 15 (the first) then fill in the left side with a space, if the length of the characters is greater than 15 (the second), then start from the beginning of the truncation of the excess characters
-
%logger: class name for logging outputs
-
%-40.40(): if the length of the logger characters recorded is less than 40 (the first), then fill in the right side with a space, if the length of the characters is greater than 40 (the second), then start from the beginning of the truncation of redundant characters
-
%cyan: color
-
%msg: log output content
-
%n: line breaks
3.6、<filter>
elemental
The two most important filters are LevelFilter and ThresholdFilter.
LevelFilter filters events based on an exact level match.
If the level of the event is equal to the configured level, the filter accepts or rejects the event, depending on the configuration of the onMatch and onMismatch properties.
For example, the following configuration will print only the INFO level logs, and disable printouts for the rest:
-
<configuration>
-
<appender name="CONSOLE" class="">
-
<filter class="">
-
<level>INFO</level>
-
<onMatch>ACCEPT</onMatch>
-
<onMismatch>DENY</onMismatch>
-
</filter>
-
<encoder>
-
<pattern>
-
%-4relative [%thread] %-5level %logger{30} - %msg%n
-
</pattern>
-
</encoder>
-
</appender>
-
<root level="DEBUG">
-
<appender-ref ref="CONSOLE" />
-
</root>
-
</configuration>
ThresholdFilter Filters events below the specified threshold.
For events equal to or above the threshold, the ThresholdFilter will respond NEUTRAL when its decision method is called.
However, events with a level below the threshold will be rejected. For example, the following configuration rejects all logs below the INFO level and only outputs logs at the INFO level and above:
-
<configuration>
-
<appender name="CONSOLE"
-
class="">
-
<!-- deny all events with a level below INFO, that is TRACE and DEBUG -->
-
<filter class="">
-
<level>INFO</level>
-
</filter>
-
<encoder>
-
<pattern>
-
%-4relative [%thread] %-5level %logger{30} - %msg%n
-
</pattern>
-
</encoder>
-
</appender>
-
<root level="DEBUG">
-
<appender-ref ref="CONSOLE" />
-
</root>
-
</configuration>
IV. Detailed examples
The above describes a few important elements in the xml, and I'll post my configured xml for reference (which implements date and size-based rollover policies, differentiates between INFO and ERROR logs, and standardizes the log output format, etc.).
-
<?xml version="1.0" encoding="UTF-8"?>
-
<configuration debug="true">
-
-
<! -- appender is a child node of configuration, the component responsible for writing logs. -->
-
<! -- ConsoleAppender: outputs logs to the console -- >.
-
<appender name="STDOUT" class="">
-
<! -- By default, each log event is immediately flushed to the base output stream. This default method is safer because log events are not lost if the application exits without properly closing the appender.
-
However, to significantly increase logging throughput, you may wish to set the immediateFlush property to false -->
-
<!--<immediateFlush>true</immediateFlush>-->
-
<encoder>
-
<! -- %37(): if the character is not 37 characters long, the left side is completed with a space -->.
-
<! -- %-37(): if the character is not 37 characters long, the right-hand side is completed with a space -->.
-
<! -- %15.15(): if the recorded thread character length is less than 15 (the first one) then fill in the left side with a space, if the character length is greater than 15 (the second one) then truncate the extra character from the beginning -->.
-
<! -- %-40.40(): if the length of the logger characters recorded is less than 40 (the first) then fill in the right-hand side with a space, if the length of the characters is greater than 40 (the second) then truncate the extra characters from the beginning -->.
-
<! -- %msg: log print details -->.
-
<! -- %n:newline character -->.
-
<! -- %highlight():The conversion descriptor displays events whose level is ERROR in bold red, WARN in red, INFO in BLUE, and the default colors for other levels. -->
-
<pattern>%d{yyyy-MM-dd HH:mm:} %highlight(%-5level) --- [%15.15(%thread)] %cyan(%-40.40(%logger{40})) : %msg%n</pattern>
-
<! -- Console should also use UTF-8, do not use GBK, otherwise the Chinese will be garbled -- >!
-
<charset>UTF-8</charset>
-
</encoder>
-
</appender>
-
-
<! -- info log -- >.
-
<! -- RollingFileAppender: rolls the logging file, logs to a specified file first, and then logs to other files when a certain condition is met -->.
-
<! -- The approximate meaning of the following is: 1. First save the log by date, the date changes, rename the previous day's log filename to XXX%date%index, and the new log is still project_info.log -->!
-
<! -- 2. If the date has not changed, but the file size of the current log exceeds 10MB, split the current log Rename -- >.
-
<appender name="info_log" class="">
-
<! -- log file path and name -- >.
-
<File>logs/project_info.log</File>
-
<! --Whether to append to the end of the file, defaults to true -->.
-
<append>true</append>
-
<filter class="">
-
<level>ERROR</level>
-
<onMatch>DENY</onMatch><! -- Disable this log if ERROR is hit -- <!
-
<onMismatch>ACCEPT</onMismatch><! -- Use this rule if there are no hits -- <!
-
</filter>
-
<! --There are two important subcomponents that interact with RollingFileAppender. The first RollingFileAppender subcomponent, the RollingPolicy: is responsible for performing the operations required for rollover.
-
The second subcomponent of RollingFileAppender, TriggeringPolicy: will determine if and when a rollover occurs. Thus, RollingPolicy is responsible for what and TriggeringPolicy is responsible for when .
-
As any use, a RollingFileAppender must set both RollingPolicy and TriggeringPolicy, however, if its RollingPolicy also implements the TriggeringPolicy interface, only the former needs to be explicitly specified. -->
-
<rollingPolicy class="">
-
<! -- The name of the log file is changed at regular intervals, depending on the value of fileNamePattern -->.
-
<! -- filename: logs/project_info.2017-12-05. -->
-
<! -- Note: The %i and %d tokens in the SizeAndTimeBasedRollingPolicy are mandatory and must be present in order to not report an error -->!
-
<fileNamePattern>logs/project_info.%d.%</fileNamePattern>
-
<! -- Each generated log file, the log file retention period of 30 days, ps: maxHistory unit is based on the fileNamePattern in the rollover policy is automatically deduced, for example, the above selection of the yyyy-MM-dd, then the unit of the day!
-
If yyyy-MM is selected above, the unit is month, and the unit above defaults to yyyy-MM-dd-->.
-
<maxHistory>30</maxHistory>
-
<! -- Start slicing each log file when it reaches 10mb, keep it for up to 30 days, but max out to 20GB, delete excess logs even if they don't reach 30 days -- >!
-
<totalSizeCap>20GB</totalSizeCap>
-
<! -- maxFileSize: this is the size of the active file, the default value is 10MB, you can change it to 5KB to see the effect when testing -->.
-
<maxFileSize>10MB</maxFileSize>
-
</rollingPolicy>
-
<! --encoder-->
-
<encoder>
-
<! -- pattern node, used to set the input format of the log ps: log file is not set in the color, otherwise the color part will have ESC [0:39em and other messy code -- >.
-
<pattern>%d{yyyy-MM-dd HH:mm:} %-5level --- [%15.15(%thread)] %-40.40(%logger{40}) : %msg%n</pattern>
-
<! -- Encoding for logging: set the character set here -- -->.
-
<charset>UTF-8</charset>
-
</encoder>
-
</appender>
-
-
<! -- error log -- >!
-
<! -- RollingFileAppender: rolls the logging file, logs to a specified file first, and then logs to other files when a certain condition is met -->.
-
<! -- The approximate meaning of the following is: 1. First save the log by date, the date changes, rename the previous day's log filename to XXX%date%index, and the new log is still project_error.log -->!
-
<! -- 2. If the date has not changed, but the file size of the current log exceeds 10MB, split the current log Rename -- >.
-
<appender name="error_log" class="">
-
<! -- log file path and name -- >!
-
<File>logs/project_error.log</File>
-
<! --Whether to append to the end of the file, defaults to true -->.
-
<append>true</append>
-
<! -- ThresholdFilter filters events below the specified threshold. For events equal to or above the threshold, ThresholdFilter will respond NEUTRAL to calls to its DECISION() method. However, events with levels below the threshold will be rejected -->.
-
<filter class="">
-
<level>ERROR</level><! -- Logs below the ERROR level (debug,info) will be rejected, levels equal to or above ERROR will be NEUTRAL accordingly -->.
-
</filter>
-
<! --There are two important subcomponents that interact with the RollingFileAppender. The first RollingFileAppender subcomponent, the RollingPolicy: is responsible for performing the operations required for rollover.
-
The second subcomponent of RollingFileAppender, TriggeringPolicy: will determine if and when a rollover occurs. Thus, RollingPolicy is responsible for what and TriggeringPolicy is responsible for when .
-
As any use, a RollingFileAppender must set both RollingPolicy and TriggeringPolicy, however, if its RollingPolicy also implements the TriggeringPolicy interface, only the former needs to be explicitly specified. -->
-
<rollingPolicy class="">
-
<! -- The name of the active file is changed at intervals based on the value of fileNamePattern -->.
-
<! -- filename: logs/project_error.2017-12-05. -->
-
<! -- Note: The %i and %d tokens in the SizeAndTimeBasedRollingPolicy are mandatory and must be present in order to not report an error -->!
-
<fileNamePattern>logs/project_error.%d.%</fileNamePattern>
-
<! -- Each generated log file, the log file retention period of 30 days, ps: maxHistory unit is based on the fileNamePattern in the rollover policy is automatically deduced, for example, the above selection of the yyyy-MM-dd, then the unit of the day!
-
If yyyy-MM is selected above, the unit is month, and the unit above defaults to yyyy-MM-dd-->.
-
<maxHistory>30</maxHistory>
-
<! -- Start slicing each log file when it reaches 10mb, keep it for up to 30 days, but max out to 20GB, delete excess logs even if they don't reach 30 days -- >!
-
<totalSizeCap>20GB</totalSizeCap>
-
<! -- maxFileSize: this is the size of the active file, the default value is 10MB, you can change it to 5KB to see the effect when testing -->.
-
<maxFileSize>10MB</maxFileSize>
-
</rollingPolicy>
-
<! --encoder-->
-
<encoder>
-
<! -- pattern node, used to set the input format of the log ps: log file is not set in the color, otherwise the color part will have ESC [0:39em and other messy code -- >.
-
<pattern>%d{yyyy-MM-dd HH:mm:} %-5level --- [%15.15(%thread)] %-40.40(%logger{40}) : %msg%n</pattern>
-
<! -- Encoding for logging: set the character set here -- -->.
-
<charset>UTF-8</charset>
-
</encoder>
-
</appender>
-
-
<! --Each enabled logging request for a given logger will be forwarded to all appenders in that logger, as well as to appenders higher in the hierarchy (don't care about the level value).
-
In other words, appender is inherited additionally from the logger hierarchy.
-
For example, if the console appender is added to the root logger, all enabled logging requests will be printed at least on the console.
-
If a file appender is additionally added to the logger (e.g., L), logging requests enabled for the L and L' subsections will be printed on the file and console.
-
This default behavior can be overridden by setting the logger's additivity flag to false so that no more appender accumulations are added -->.
-
<! -- A maximum of one root is allowed in the configuration, other loggers inherit from the parent root if no level is set -->.
-
<root level="INFO">
-
<appender-ref ref="STDOUT" />
-
</root>
-
-
<! -- Specify the logging level for a package in the project when there is a logging action behavior -- >.
-
<! -- The levels are in order [from highest to lowest]: FATAL > ERROR > WARN > INFO > DEBUG > TRACE -->.
-
<logger name="" level="INFO">
-
<appender-ref ref="info_log" />
-
<appender-ref ref="error_log" />
-
</logger>
-
-
<! -- Inputting mybatis sql logs using logback.
-
Note: If you don't add additivity="false" then this logger will forward the output to itself as well as to the ancestor logger, and there will be duplicate sql printing in the log file -->.
-
<logger name="" level="DEBUG" additivity="false">
-
<appender-ref ref="info_log" />
-
<appender-ref ref="error_log" />
-
</logger>
-
-
<! -- additivity=false means that the default cumulative behavior is disabled, i.e., logs in will only be logged to the log file and will not be output to any appenders higher up in the hierarchy -- >.
-
<logger name="" level="INFO" additivity="false">
-
<appender-ref ref="info_log" />
-
<appender-ref ref="error_log" />
-
</logger>
-
-
</configuration>
V. Additional elements
Error log output method:
-
Object entry = new SomeObject();
-
("The entry is " + entry);
The above doesn't seem to be a problem, but there is the cost of constructing the message parameter, i.e. converting the entry to a string sum.
And this is true regardless of whether the message is logged or not, i.e.: that even if the log level is INFO, the operation inside the parentheses will be performed, but the log will not be output.
Optimized writing method: the first writing method is improved by first judging the set logging level, and only constructing the parameters if it is debug mode.
-
if(()) {
-
Object entry = new SomeObject();
-
("The entry is " + entry);
-
}
But there's also the best way to write it, using placeholders:
-
Object entry = new SomeObject();
-
logger.debug("The entry is {}.", entry);
Only after evaluating whether to log or not, and only if the decision is positive, does the logger implementation format the message and replace the "{}" pair with the string value of the entry.
In other words, this form does not incur the cost of parameter construction when logging statements are disabled.
Tests conducted by the logback authors concluded that the first and third ways of writing will produce exactly the same output.
However, with logging statements disabled, the third variant will outperform the first variant by a factor of at least 30.
If there is more than one parameter, it is written as follows:
("The new entry is {}. It replaces {}.", entry, oldEntry);
If you need to pass three or more parameters, you can also use the Object [] variant:
-
Object[] paramArray = {newVal, below, above};
-
("Value {} was inserted between {} and {}.", paramArray);
When logging we may need to record the stack information of the exception in the file, after testing, (e) will not print the stack information, the correct way to write it is:
("Program Exception, Detailed Information:{}", () , e);