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.

My official account

Wechat official account