Personal blog: Glmapepr- Digging gold out of the world of applications: Glmapper
Thank you for your attention, likes and comments. There is a personal qr code at the end of the article. If you are interested, you can follow it or add my personal wechat to exchange and study together.
Recommended reading
- SpringBoot series -FatJar technology analysis
- SpringBoot series – Boot process parsing
- SpringBoot series – Event mechanism parsing
- SpringBoot series – Life cycle and extension of beans
- SpringBoot series – Logging framework parsing
- SpringBoot series – Resource access parsing
- SpringBoot Series – Embedded Web container resolution
directory
Log Format Console Output Color code Output file Output Log Level Log Groups Custom log configuration springProfile Configuration Log initialization entry ApplicationStartingEvent Stage of processing ApplicationEnvironmentPreparedEvent ContextClosedEvent and processing ApplicationPreparedEvent phase AbstractLoggingSystem ApplicationFailedEventLoggingSystem analysis processing logic Log4J2LoggingSystem beforeInitialize in processing logic Log4J2LoggingSystem implementation initialize Log4J2LoggingSystem implementation Log4J2LoggingSystem cleanup logic Some scenario analysis does not have any configuration files in the Resources directory to configure log4j2.xml in Log4j2-glmapper.xml: log4j2-glmapper.xml: log4j2-glmapper.xml
Spring Boot uses Commons Logging for all internal Logging, but retains the underlying Logging implementation. Default configurations are provided for Java Util Logging, Log4J2, and Logback. In each case, loggers are pre-configured to use console output and also provide optional file output.
By default, if “Starters” is used, Logback is used for logging. Appropriate Logback routing is also included to ensure that libraries that rely on Java Util logging, Commons logging, Log4J, or SLF4J all work.
Below first look at a simple SpringBoot demo project log output, in order to expand the log format, console output, log color, log file configuration, log system parsing and other aspects of the introduction.
Create a new SpringBoot project and start it without adding anything by default.
2019- 12- 24 20:41:31.866 INFO 87851 --- [ main] com.glmapper.bridge.boot.BootStrap : No active profile set, falling back to default profiles: default
2019- 12- 24 20:41:32.003 INFO 87851 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@314c508a: startup date [Tue Dec 24 20:41:31 CST 2019]; root of context hierarchy
2019- 12- 24 20:41:32.556 INFO 87851 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2019- 12- 24 20:41:32.568 INFO 87851 --- [ main] com.glmapper.bridge.boot.BootStrap : Started BootStrap in 1.035 seconds (JVM running for 2.13)
2019- 12- 24 20:41:32.569 INFO 87851 --- [ Thread4 -] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@314c508a: startup date [Tue Dec 24 20:41:31 CST 2019]; root of context hierarchy
2019- 12- 24 20:41:32.571 INFO 87851 --- [ Thread4 -] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
Process finished with exit code 0
Copy the code
Log format
The following is the default log output of Spring Boot. In terms of the log format, it mainly includes the following:
- Time: for example 2019-12-24 20:41:31.866 (ms precision)
- Log levels: for example, INFO (ERROR, WARN, INFO, DEBUG, or TRACE.)
- Current process: For example, 87851
- — Delimiter, used to distinguish the beginning of the actual log message.
- Thread name: for example, Thread-4 (enclosed in square brackets (it may be truncated for console output).
- Log name: This is usually the source class name (usually abbreviated).
- Log message: indicates a log message
Like this entry:
2019- 12- 24 20:41:31.866 INFO 87851 --- [ main] com.glmapper.bridge.boot.BootStrap : No active profile set, falling back to default profiles: default
Copy the code
Is in the org. Springframework. Boot. SpringApplication# logStartupProfileInfo methods in print, log level for the INFO.
The Console output
SpringBoot logs to the Console by default and logs messages at the error, WARN, and INFO levels by default. You can also use the debug level by starting the application with the — debug parameter.
java -jar myapp.jar --debug
Copy the code
You can also enable the debug level by specifying debug=true in application.properties
When the Debug level is enabled, a series of core loggers (embedded container, Hibernate, and Spring Boot) are configured to output more information. Enabling debug mode does not configure the application to log all messages at the debug level. Similarly, you can use the — trace flag to start the trace level mode to start the application.
Color coded output
If your terminal support ANSI, you can by setting the “spring. The output. The ANSI. Enable” configuration item value to specify the color (premise is the color of official support). The color coding is configured by using the % CLR conversion word, the simplest of which is to color the output log according to the log level, as shown in the following example:
%clr(%5p)
Copy the code
The following table is the official mapping between log levels and colors:
Level | Color |
---|---|
FATAL | Red |
ERROR | Red |
WARN | Yellow |
INFO | Green |
DEBUG | Green |
TRACE | Green |
If you want to make the text yellow, use the following Settings:
%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){yellow}
Copy the code
Currently supported colors and styles include Blue, Cyan, FAINT, Green, Magenta, Red, and Yellow.
The output file
By default, Spring boot logs are only printed to the Console, not written to a log file. If you want to write to log files in addition to Console output, you need to set logging.file and logging.path properties (in application.properties). The following table shows how the logging.* attributes are used together:
logging.file | logging.path | Example | Description |
---|---|---|---|
none | none | Console log | |
The specified file | none | my.log | Writes to the specified log file, whose name can be exact location or relative to the current directory. |
none | The specified file | /var/log | Writes spring.log to the specified directory, either in a precise location or relative to the current directory. |
The log file is rolled when it reaches 10 MB and, like the Console output, logs ERROR, WARN, and INFO messages by default. You can change the size limit using the logging.file.max-size property. Files previously Rolling will be archived indefinitely unless the logging.file.max-history property is set.
Logging systems are initialized early in the application life cycle. Therefore, log properties are not found in the properties file loaded through the @propertysource annotation. In addition, the logging properties are independent of the actual logging infrastructure. So, Spring Boot the specific configuration management keys (for example, the Logback Logback. ConfigurationFile).
The level of logging
Logging systems supported in SpringBoot can be set to the logging level in the Spring environment (such as in application.properties) via logging.level.
=
. Log levels include TRACE, DEBUG, INFO, WARN, ERROR, FATAL, and OFF. In addition, you can configure the log level of the root Logger using logging.level.root. The following example shows how to configure logging levels in application.properties:
logging.level.root=warn
logging.level.org.springframework.web=debug
logging.level.org.hibernate=error
Copy the code
In addition to application.properties, you can also set the logging level using environment variables. For example, LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_WEB=DEBUG Sets the log printing level of the org.springFramework. web package to DEBUG.
The above approach applies only to package-level logging. Because the Relaxed Binding always converts environment variables to lowercase, it is not possible to configure logging for a single class in this way. If you need to configure logging for a class, you can use the SPRING_APPLICATION_JSON variable.
Log Groups
It is often useful to group related Loggers together so that they can be configured at the same time, and Spring Boot allows logging groups to be defined in a Spring environment. For example, add the tomcat group to application.properties.
logging.group.tomcat=org.apache.catalina, org.apache.coyote, org.apache.tomcat
Copy the code
Thus, we can set the log level of a set of logs with a one-line configuration:
logging.level.tomcat=TRACE
Copy the code
Spring Boot includes the following predefined logging groups that you can use out of the box:
Name | Loggers |
---|---|
web | org.springframework.core.codec, org.springframework.http, org.springframework.web, org.springframework.boot.actuate.endpoint.web, org.springframework.boot.web.servlet.ServletContextInitializerBeans |
sql | org.springframework.jdbc.core, org.hibernate.SQL |
Custom log configuration
You can activate various logging systems by including the appropriate libraries in the classpath, and you can further customize the logging system by providing the appropriate configuration files in the root of the classpath or at the location specified by the logging.config attribute in the Spring environment.
For instance you can use the org. Springframework. Boot. Logging. LoggingSystem configuration properties mandatory Spring guide using the specified log system. This value should be the fully qualified class name of the LoggingSystem implementation; If this parameter is set to None, Spring Boot logging is completely disabled. The following table describes the log configuration files corresponding to the logging system in SpringBoot:
Logging System | Customization |
---|---|
Logback | logback-spring.xml, logback-spring.groovy, logback.xml, or logback.groovy |
Log4j2 | org.springframework.jdbc.core, org.hibernate.SQL |
JDK (Java Util Logging) | logging.properties |
SpringBoot officially recommends using -spring for logging configuration (for example, using logback-spring. XML instead of logback.xml). If you use standard configuration locations, Spring does not have full control over log initialization.
In addition, it is explicitly mentioned in the official documentation that JUL(Ava Util Logging) has some known classloading problems in FATJAR scenarios, so it is important to avoid using JUL in FATJAR scenarios.
To aid in logging system customization, Spring sets environment variable properties to system properties, as shown in the following table:
Spring Environment | System Property | Comments |
---|---|---|
logging.exception-conversion-word | LOG_EXCEPTION_CONVERSION_WORD | Conversion Word used to record exceptions |
logging.file | LOG_FILE | If defined, it is used in the default logging configuration. |
logging.file.max-size | LOG_FILE_MAX_SIZE | Maximum log file size (if LOG_FILE is enabled). (Only the default Logback setting is supported) |
logging.file.max-history | LOG_FILE_MAX_HISTORY | The maximum number of archive log files to keep (if LOG_FILE is enabled). (Only the default Logback setting is supported.) |
logging.path | LOG_PATH | If defined, it is used in the default logging configuration. |
logging.pattern.console | CONSOLE_LOG_PATTERN | The logging mode to use on the console (STDout). (Only the default Logback setting is supported.) |
logging.pattern.dateformat | LOG_DATEFORMAT_PATTERN | Additional mode for log date format. (Only the default Logback setting is supported.) |
logging.pattern.file | FILE_LOG_PATTERN | Maximum log file size (if LOG_FILE is enabled). (Only the default Logback setting is supported) |
logging.pattern.level | LOG_LEVEL_PATTERN | Format to use when rendering log levels (default %5p). (Only the default Logback setting is supported.) |
PID | PID | Current Process ID |
All supported log systems can parse configuration files by referring to system properties.
If you want to use placeholders in logging properties, you should use SpringBoot’s syntax, not the syntax of the underlying framework. Note that if Logback is used, you should use: as the separator between the attribute name and its default value instead of :-.
SpringProfile configuration
Allows users to choose to include or exclude configuration parts based on the active Spring profiles. The profile part is supported anywhere in the element. You can use the name attribute to specify which profile accepts configuration. You can include a simple profile name (for example, dev) or a profile expression. Expression profile file allows some more complex profile file logic, for example: “production & (eu – central | eu – west)”. Three examples of configuration files are shown below:
xml <springProfile name="dev"> <! -- Activate the dev environment configuration --> </springProfile>
<springProfile name="dev | pre"> <! -- Activate dev and Pre's environment variables --> </springProfile>
<springProfile name="! prod"> <! -- All non-PROD environments are active --> </springProfile>
## Environment attributes
The tag allows the user to pass properties in the Spring Environment for use in Logback. Such as accessing values in the application.properties file in a Logback configuration. The mechanism of action is similar to Logback’s standard tag. However, instead of specifying a direct value, you specify the source (from the Environment) for the attribute. If you need to store a property in a location other than the local scope, you can use the scope property to control this. If you need a defaultValue (if it is not set in the Environment), you can configure it using the defaultValue property. The following example describes how to pass attributes used in Logback:
xml <springProperty scope="context" name="fluentHost" source="myapp.fluentd.host" defaultValue="localhost"/> <appender name="FLUENT" class="ch.qos.logback.more.appenders.DataFluentAppender"> <remoteHost>${fluentHost}</remoteHost> ... </appender>
Based on the official documentation of SpringBoot for Logger support description made a brief introduction, the following will be through the analysis of source code to in-depth grasp these features. This paper takes Log4j2 as an example for analysis.
The timing of logging initialization was actually mentioned in the SpringBoot series – Event mechanism details. Here’s a quick review:
# Application Listeners
org.springframework.context.ApplicationListener=\
// omit others
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
Copy the code
The two listeners of logging, main effect is LoggingApplicationListener, the listener is SpringBoot log in the entrance to the initialization.
Log initialization entry
LoggingApplicationListener inherited GenericApplicationListener this interface, the parent interface ApplicationListener, GenericApplicationListener extends support for the event types in judgment. The main concern here is the onApplicationEvent callback method. For several of the event types mentioned in this method, refer to the SpringBoot series – Event Mechanism details article.
@Override
public void onApplicationEvent(ApplicationEvent event) {
// ApplicationStartingEvent
if (event instanceof ApplicationStartingEvent) {
onApplicationStartingEvent((ApplicationStartingEvent) event);
}
// ApplicationEnvironmentPreparedEvent
else if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
}
// ApplicationPreparedEvent
else if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent((ApplicationPreparedEvent) event);
}
// ContextClosedEvent
else if (event instanceof ContextClosedEvent
&& ((ContextClosedEvent) event).getApplicationContext().getParent() == null) {
onContextClosedEvent();
}
// ApplicationFailedEvent
else if (event instanceof ApplicationFailedEvent) {
onApplicationFailedEvent();
}
}
Copy the code
Processing of the ApplicationStartingEvent stage
Upon receiving the ApplicationStartingEvent event, SpringBoot builds a loggingSystem object from the currently applied ClassLoader, and then performs some preparatory work prior to initialization.
private void onApplicationStartingEvent(ApplicationStartingEvent event) {
// Build the loggingSystem object from the classloader currently applied
this.loggingSystem = LoggingSystem.get(event.getSpringApplication().getClassLoader());
// loggingSystem is prepared before initialization
this.loggingSystem.beforeInitialize();
}
Copy the code
Here’s how loggingSystem is built. This process makes it very clear that Why by introducing a logging framework relying on or using org. Springframework. Boot. Logging. LoggingSystem configuration can automatically complete the choice of logging framework.
public static LoggingSystem get(ClassLoader classLoader) {
// SYSTEM_PROPERTY=org.springframework.boot.logging.LoggingSystem
/ / here first obtained from the system variables under org. Springframework. Boot. Logging. LoggingSystem, to see if the user specifies the LoggingSystem type
String loggingSystem = System.getProperty(SYSTEM_PROPERTY);
/ / if org. Springframework. Boot. Logging. LoggingSystem = xx configuration values
if (StringUtils.hasLength(loggingSystem)) {
// Whether none is configured
if (NONE.equals(loggingSystem)) {
// If none is configured, NoOpLoggingSystem is returned
return new NoOpLoggingSystem();
}
// Create a loggingSystem object by reflection based on the specified log type
return get(classLoader, loggingSystem);
}
return SYSTEMS.entrySet().stream().filter((entry) -> ClassUtils.isPresent(entry.getKey(), classLoader))
.map((entry) -> get(classLoader, entry.getValue())).findFirst()
.orElseThrow(() -> new IllegalStateException("No suitable logging system located"));
}
Copy the code
The last part of the above code does a series of processing based on the data in a system Map structure, mainly by determining whether entry.getKey() exists in the current classpath, and if so, by reflection building an object of type entry.getValue(). SYSTEMS is a static MAP struct variable in the LoggingSystem abstract class, whose initialization is done in a static code block:
static {
Map<String, String> systems = new LinkedHashMap<>();
// Add LoggingSystem for logBack
systems.put("ch.qos.logback.core.Appender"."org.springframework.boot.logging.logback.LogbackLoggingSystem"); ,
// Add LoggingSystem for log4j2
systems.put("org.apache.logging.log4j.core.impl.Log4jContextFactory".
"org.springframework.boot.logging.log4j2.Log4J2LoggingSystem");
// Add the LoggingSystem for JUL
systems.put("java.util.logging.LogManager"."org.springframework.boot.logging.java.JavaLoggingSystem");
SYSTEMS = Collections.unmodifiableMap(systems);
}
Copy the code
This makes it clear that if logback, Log4j2, or JUL dependencies exist in the current classpath, then the corresponding LoggingSystem object is built. The beforeInitialize method is also called after the LoggingSystem object is built. Assuming the log4J2 dependency is introduced, the final LoggingSystem built is Log4J2LoggingSystem. BeforeInitialize is an abstract method provided by LoggingSystem whose concrete implementation is implemented by subclasses. The following will be analyzed in the source code analysis section.
ApplicationEnvironmentPreparedEvent stage of processing
To receive ApplicationEnvironmentPreparedEvent events explain the Environment object has been built, the Environment variable initialization has been completed. So the main job here is to initialize the logging framework.
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
// Check again to see if loggingSystem has been created
if (this.loggingSystem == null) {
this.loggingSystem = LoggingSystem.get(event.getSpringApplication().getClassLoader());
}
// Initialize the logging system with preferences expressed in the environment and classpath.
initialize(event.getEnvironment(), event.getSpringApplication().getClassLoader());
}
// initialize
protected void initialize(ConfigurableEnvironment environment, ClassLoader classLoader) {
// The Spring environment moves to system properties
new LoggingSystemProperties(environment).apply();
// Parse to get logFile, which depends on the two configuration values logging.file and loggin.path
this.logFile = LogFile.get(environment);
if (this.logFile ! =null) {
/ / set the logging file - > LOG_FILE
// loggin.path -> LOG_PATH
this.logFile.applyToSystemProperties();
}
initializeEarlyLoggingLevel(environment);
// Initialize the log according to the configuration file of log
initializeSystem(environment, this.loggingSystem, this.logFile);
// Bind logging.group and set logging.level
initializeFinalLoggingLevels(environment, this.loggingSystem);
// Register logging.register-shutdown-hook for the hooks configured
registerShutdownHookIfNecessary(environment, this.loggingSystem);
}
Copy the code
This stage is a series of log initialization tasks based on the log related properties and configuration files that we configured, as described earlier in this article.
Processing of the ApplicationPreparedEvent phase
Receiving the ApplicationPreparedEvent event indicates that the application is ready, and two beans are registered, one springBootLoggingSystem and one pringBootLogFile.
private void onApplicationPreparedEvent(ApplicationPreparedEvent event) {
ConfigurableListableBeanFactory beanFactory = event.getApplicationContext().getBeanFactory();
// Register the springBootLoggingSystem bean
if(! beanFactory.containsBean(LOGGING_SYSTEM_BEAN_NAME)) {
beanFactory.registerSingleton(LOGGING_SYSTEM_BEAN_NAME, this.loggingSystem);
}
// Register the pringBootLogFile bean
if (this.logFile ! =null && !beanFactory.containsBean(LOGFILE_BEAN_NAME)) {
beanFactory.registerSingleton(LOGFILE_BEAN_NAME, this.logFile);
}
}
Copy the code
ContextClosedEvent and ApplicationFailedEvent
ContextClosedEvent ContextClosedEvent ContextClosedEvent ContextClosedEvent ContextClosedEvent ContextClosedEvent ContextClosedEvent ContextClosedEvent ContextClosedEvent ContextClosedEvent ContextClosedEvent ApplicationFailedEvent Is an event sent when an application fails to start. This event also clears the log system. The clearing method is implemented by each sub-LoggingSystem. Take Log4j2 as an example. Clearing log4j2 mainly includes unlogging the bridge processor (mentioned in the initialization phase), setting LogContext to NULL, and removing FILTER, which is basically the reverse process of initialization.
LoggingSystem analysis
LoggingSystem is a layer of abstract encapsulation of logging framework by SpringBoot. LoggingSystem makes it easy to use some logging framework, just need to define the corresponding logging framework configuration file, such as Logback, Log4j, Log4j2, etc. It can be used directly inside the code.
Above is the class inheritance structure of LoggingSystem. You can see that the implementation of LoggingSystem subclasses are Logback (LogbackLoggingSystem), Log4j2 (Log4J2LoggingSystem) and JDK built-in Log (JavaLoggingSystem). LoggingSystem is an abstract class that contains these methods:
- BeforeInitialize: Things that need to be handled before the log system is initialized
- Initialize: Initializes the log system
- CleanUp: cleanUp of the log system
- GetShutdownHandler: Returns a Runnable for handling operations that need to be performed after the logging system is shut down when the JVM exits, null by default
- SetLogLevel: Sets the logger level
These methods are seen above in the analysis of startup entry and log initialization. The above methods are either abstract methods or empty implementations in LoggingSystem, which require specific subclasses to complete the processing of the specific logging framework. AbstractLoggingSystem AbstractLoggingSystem AbstractLoggingSystem AbstractLoggingSystem AbstractLoggingSystem AbstractLoggingSystem AbstractLoggingSystem So let’s take a look at two classes, AbstractLoggingSystem and Log4J2LoggingSystem, which override the above methods and are the core logic of the logging framework in SpringBoot.
AbstractLoggingSystem handles logic
BeforeInitialize in AbstractLoggingSystem has no specific processing logic and is an empty method, so focus on the initialize method.
@Override
public void initialize(LoggingInitializationContext initializationContext, String configLocation, LogFile logFile) {
// If a log profile is specified, the log profile is used for initialization
if (StringUtils.hasLength(configLocation)) {
initializeWithSpecificConfig(initializationContext, configLocation, logFile);
return;
}
// If no configuration file is specified, the default method is used to find and load the configuration file
initializeWithConventions(initializationContext, logFile);
}
// Initialize with the specified configuration file
private void initializeWithSpecificConfig(LoggingInitializationContext initializationContext, String configLocation,
LogFile logFile) {
// Placeholders in the log configuration file are handled here
configLocation = SystemPropertyUtils.resolvePlaceholders(configLocation);
// Abstract methods, implemented by concrete subclasses (the way different logging frameworks handle configuration files is up to them)
loadConfiguration(initializationContext, configLocation, logFile);
}
// Find the configuration file by default and initialize it
private void initializeWithConventions(LoggingInitializationContext initializationContext, LogFile logFile) {
If log4j2 is used as an example, the default configuration file name is found in classpath
Yaml, log4j2.yml, log4j2.json, log4j2. JSN, log4j2. XML files
String config = getSelfInitializationConfig();
if(config ! =null && logFile == null) {
// A self-initialization occurs and is re-initialized when the property changes
reinitialize(initializationContext);
return;
}
if (config == null) {
// Find the Spring rule configuration,
// log4j2-spring.properties, log4j2-spring. XML, etc
config = getSpringInitializationConfig();
}
if(config ! =null) {
loadConfiguration(initializationContext, config, logFile);
return;
}
// Abstract methods implemented by concrete logging systems
loadDefaults(initializationContext, logFile);
}
Copy the code
Initialize is to find the configuration file and initialize the log system using the configuration file. If it cannot be found, initialize the log system using the default mode provided by the log system. The code above about how to load configuration files and load by default are implemented in subclasses. So let’s see how this works in the log4j2 case.
Log4J2LoggingSystem processing logic
Log4J2LoggingSystem is not a direct subclass of AbstractLoggingSystem, but a direct subclass of Slf4JLoggingSystem, Slf4JLoggingSystem is an abstract class that is designed to do some bridging from the point of view of the code.
BeforeInitialize implementation in Log4J2LoggingSystem
@Override
public void beforeInitialize(a) {
// Create and get LoggerContext
LoggerContext loggerContext = getLoggerContext();
// Determine if the current LoggerContext has been initialized, and return if it has
if (isAlreadyInitialized(loggerContext)) {
return;
}
// Calls the beforeInitialize method of Slf4JLoggingSystem, which is the bridge handler that configures JDK Logging
super.beforeInitialize();
// Add the default FILTER to loggerContext
loggerContext.getConfiguration().addFilter(FILTER);
}
Copy the code
GetLoggerContext is how log4j2 builds its own LoggerContext, so that’s where it passes.
Initialize in Log4J2LoggingSystem implementation
@Override
public void initialize(LoggingInitializationContext initializationContext, String configLocation, LogFile logFile) {
// Get the current loggerContext
LoggerContext loggerContext = getLoggerContext();
// Check if the initialization has already been done
if (isAlreadyInitialized(loggerContext)) {
return;
}
// Remove the default FILTER
loggerContext.getConfiguration().removeFilter(FILTER);
// Call the parent class Initialize to find the log configuration file and initialize it
super.initialize(initializationContext, configLocation, logFile);
// The flag is initialized
markAsInitialized(loggerContext);
}
Copy the code
The core initialize method is still using the parent’s processing logic, In front also mentioned the initialize AbstractLoggingSystem’s core is the process of the load configuration configuration file (loadConfiguration/loadDefaults), and the load is the process of the subclass. So let’s look at the load configuration file in log4j2.
- LoadConfiguration: indicates that there is a configuration file
protected void loadConfiguration(String location, LogFile logFile) {
Assert.notNull(location, "Location must not be null");
try {
LoggerContext ctx = getLoggerContext();
// Get the resource URL
URL url = ResourceUtils.getURL(location);
// Build the ConfigurationSource object
ConfigurationSource source = getConfigurationSource(url);
// Different parsers are selected to parse the configuration file depending on the type of configuration, for example
/ / XmlConfigurationFactory, PropertiesConfigurationFactory...
// Start with the specified configuration
ctx.start(ConfigurationFactory.getInstance().getConfiguration(ctx, source));
}
catch (Exception ex) {
throw new IllegalStateException("Could not initialize Log4J2 logging from " + location, ex);
}
}
Copy the code
A ConfigurationSource is constructed using the specified configuration file address. A different ConfigurationFactory is selected to parse the configuration file based on the configuration file type. Finally, the logging framework initializes the logging system from this configuration file.
- LoadDefaults: No configuration file
@Override
protected void loadDefaults(LoggingInitializationContext initializationContext, LogFile logFile) {
if(logFile ! =null) {
/ / using the classpath: org/springframework/boot/logging/log4j2 / log4j2 - file. The XML
loadConfiguration(getPackagedConfigFile("log4j2-file.xml"), logFile);
}
else {
/ / using the classpath: org/springframework/boot/logging/log4j2 / log4j2. The XML
loadConfiguration(getPackagedConfigFile("log4j2.xml"), logFile);
}
}
Copy the code
To summarize: If no logging profile is specified or no configuration file matching the specified logging system is found in classpath, the default configuration file provided by SpringBoot is used for initialization.
Clearing logic of the log system
The cleanUp method is also implemented by a specific LoggingSystem and is used to cleanUp LoggingSystem resources.
@Override
public void cleanUp(a) {
// Call the parent class to remove the bridge
super.cleanUp();
LoggerContext loggerContext = getLoggerContext();
// mark loggerContext as uninitialized and set the internal externalContext to null
markAsUninitialized(loggerContext);
// Remove the default FILTER
loggerContext.getConfiguration().removeFilter(FILTER);
}
Copy the code
Some scenario analysis
This includes some common scenarios for logging in daily development work, such as no logging configuration in the project, logging configuration files configured in the Resources directory, and log files already used that SpringBoot cannot recognize.
There are no configuration files
The initialize method does not find any resources, so the loadDefaults method is used by default. The loadDefaults method of LogbackLoggingSystem. Due to the logFile is null, so will use the classpath: org/springframework/boot/logging/log4j2 / log4j2. The XML configuration file:
<Configuration status="WARN">
<Properties>
<Property name="PID">????</Property>
<Property name="LOG_EXCEPTION_CONVERSION_WORD">%xwEx</Property>
<Property name="LOG_LEVEL_PATTERN">%5p</Property>
<Property name="LOG_DATEFORMAT_PATTERN">yyyy-MM-dd HH:mm:ss.SSS</Property>
<Property name="CONSOLE_LOG_PATTERN">%clr{%d{${LOG_DATEFORMAT_PATTERN}}}{faint} %clr{${LOG_LEVEL_PATTERN}} %clr{${sys:PID}}{magenta} %clr{---}{faint} % the CLR {[% 15.15 t]} {abbreviation} % CLR {% - 40.40 - c {1}} {cyan} % CLR {that} {abbreviation} % m % n ${sys: LOG_EXCEPTION_CONVERSION_WORD}</Property>
<Property name="FILE_LOG_PATTERN">% d {${LOG_DATEFORMAT_PATTERN}} ${LOG_LEVEL_PATTERN} ${sys: PID} [t] % % - 40.40 c {1} : %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property>
</Properties>
<Appenders>
// Call the console
<Console name="Console" target="SYSTEM_OUT" follow="true">
<PatternLayout pattern="${sys:CONSOLE_LOG_PATTERN}" />
</Console>
</Appenders>
<Loggers>
<Logger name="org.apache.catalina.startup.DigesterFactory" level="error" />
<Logger name="org.apache.catalina.util.LifecycleBase" level="error" />
<Logger name="org.apache.coyote.http11.Http11NioProtocol" level="warn" />
<logger name="org.apache.sshd.common.util.SecurityUtils" level="warn"/>
<Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="warn" />
<Logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="error" />
<Logger name="org.hibernate.validator.internal.util.Version" level="warn" />
<logger name="org.springframework.boot.actuate.endpoint.jmx" level="warn"/>
<Root level="info">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>
Copy the code
The value of this configuration file has an Appender, which is the default Console, so when no log configuration file is configured, logs will be typed to the Console.
Configure log4j2.xml in the Resources directory
This configuration file is recognized by SpringBoot, so it is used to initialize the log system. The following configuration file has an appender configured for each log level, so when used, logs are stored in different log directories based on the log level. (PS: Refer to the previous analysis for identifying log profiles)
<configuration status="OFF">
<Properties>
<Property name="logging.path">./logs</Property>
</Properties>
<appenders>
<Console name="Console" target="SYSTEM_OUT">
<! -- Only INFO level logs are accepted -->
<ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY" />
<PatternLayout pattern="[%d{HH:mm:ss.SSS}] %-5level %class{36} %L %M - %msg%xEx%n" />
</Console>
<! -- Handle DEBUG level logs and place them in logs/debug.log -->
<! -- Print DEBUG level logs. Each time the size of logs exceeds size, the size of logs will be automatically saved in the folder created by year and month and compressed for archiving.
<RollingFile name="RollingFileDebug" fileName="${logging.path}/debug.log"
filePattern="logs/? {date:yyyy-MM}/debug-%d{yyyy-MM-dd}-%i.log.gz">
<Filters>
<ThresholdFilter level="DEBUG"/>
<ThresholdFilter level="INFO" onMatch="DENY" onMismatch="NEUTRAL"/>
</Filters>
<PatternLayout
pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %class{36} %L %M - %msg%xEx%n"/>
<Policies>
<SizeBasedTriggeringPolicy size="500 MB"/>
<TimeBasedTriggeringPolicy/>
</Policies>
</RollingFile>
<! -- Process INFO level logs and place them in logs/info.log -->
<RollingFile name="RollingFileInfo" fileName="${logging.path}/info.log"
filePattern="logs/? {date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log.gz">
<Filters>
<! INFO level logs are only accepted.
<ThresholdFilter level="INFO"/>
<ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/>
</Filters>
<PatternLayout
pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %class{36} %L %M - %msg%xEx%n"/>
<Policies>
<SizeBasedTriggeringPolicy size="500 MB"/>
<TimeBasedTriggeringPolicy/>
</Policies>
</RollingFile>
<! Process WARN level logs and place the logs in the logs/warn.log file.
<RollingFile name="RollingFileWarn" fileName="${logging.path}/warn.log"
filePattern="logs/? {date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log.gz">
<Filters>
<ThresholdFilter level="WARN"/>
<ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/>
</Filters>
<PatternLayout
pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %class{36} %L %M - %msg%xEx%n"/>
<Policies>
<SizeBasedTriggeringPolicy size="500 MB"/>
<TimeBasedTriggeringPolicy/>
</Policies>
</RollingFile>
<! -- Handle error level logs and place them in logs/error.log -->
<RollingFile name="RollingFileError" fileName="${logging.path}/error.log"
filePattern="logs/? {date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log.gz">
<ThresholdFilter level="ERROR"/>
<PatternLayout
pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %class{36} %L %M - %msg%xEx%n"/>
<Policies>
<SizeBasedTriggeringPolicy size="500 MB"/>
<TimeBasedTriggeringPolicy/>
</Policies>
</RollingFile>
</appenders>
<loggers>
<root level="DEBUG">
<appender-ref ref="Console"/>
<appender-ref ref="RollingFileInfo"/>
<appender-ref ref="RollingFileWarn"/>
<appender-ref ref="RollingFileError"/>
<appender-ref ref="RollingFileDebug"/>
</root>
<! --log4j2 filter logs -->
<Logger name="org.apache.catalina.startup.DigesterFactory" level="error" />
<Logger name="org.apache.catalina.util.LifecycleBase" level="error" />
<Logger name="org.apache.coyote.http11.Http11NioProtocol" level="warn" />
<logger name="org.apache.sshd.common.util.SecurityUtils" level="warn"/>
<Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="warn" />
<Logger name="org.crsh.plugin" level="warn" />
<logger name="org.crsh.ssh" level="warn"/>
<Logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="error" />
<Logger name="org.hibernate.validator.internal.util.Version" level="warn" />
<logger name="org.thymeleaf" level="warn"/>
<Logger name="org.springframework" level="warn"/>
</loggers>
</configuration>
Copy the code
Configure a log4j2-glmapper.xml file under Resources
Rename the above configuration file to log4j2-glmapper. XML. Since this naming rule is not recognized by SpringBoot by default, the log configuration file is loaded in the same way as scenario 1. If you want the configuration file to be recognized, you can specify it using logging.config.
logging.config=classpath:log4j2-glmapper.xml
Copy the code
summary
This article on the SpringBoot log system introduction and analysis, the article is mainly to understand SpringBoot for the processing of the log system, so it will not pay too much attention to the log system itself some processing logic, interested readers can study or contact the author to communicate.