An overview of the

Logs are indispensable to a system. They record the running details of the system and help us understand the running status of the system. When we use Spring Boot, the log function is provided by default, and Logback is used as the default log framework. So, let’s look at how Spring Boot initializes the logging system. Spring knowledge summarized an atlas, share with you:

Why is the default Logging framework for Spring Boot Logbasck?

Because the spring-boot-starter-logging module is introduced in the spring-boot-starter module, the starter introduces the logback-classic dependency.

Log System

In your daily work, you might see a bewilderingly large number of log-related JARS that your project relies on, such as Commons-logging, log4j, log4j2, SL4J, and Logback. Often encounter a variety of dependency flushing problems, very annoying, such as these questions:

(1) Failed to load the class org. Slf4j. Impl. StaticLoggerBinder, couldn’t find the log, if you think you have been added to the corresponding logging implementation depend on, it should check the version is compatible

If you want to use them correctly, it is necessary to clarify the relationship between them. We can take a look at the history of Log. Let’s start with the history of Java Log:

1.1. Log4j (by Ceki Gulcu) has been widely used by developers (note that it is directly used here), was originally the de facto standard for Java logging, and became an Apache project

2.2.Apache requested that log4j be incorporated into the JDK. SUN refused and added JUL (java.util.logging) after JDK 1.4;

3.3. After all, it comes with the JDK, and JUL is widely used. There are other log components, such as SimpleLog. At this point, if someone wants to switch to another logging component, such as log4j to JUL, because the API is completely different, they need to change the code, of course, many people do not want to;

Apache developed JCL (Jakarta Commons Logging), also known as commons-logging-xx.jar. It only provides a set of generic logging interface apis and does not provide an implementation of logging. It’s a good design principle to rely on abstraction rather than implementation. This way, our application can choose the logging implementation component it wants at run time;

5.5. This is all very nice, but the authors of Log4j decided that JCL wasn’t working and developed slF4J, which is similar to JCL in that it doesn’t implement logging itself, but provides an interface or a facade. The goal is to replace JCL. At the same time, logBack, a component with higher performance than Log4J, was developed to replace log4j;

Apache took a look at Logback and made a number of optimizations to create a log4J2 logging framework. If you want to use log4j2, please refer to my “MyBatis User Manual” article, which has been mentioned.

review

Back in SpringApplication#run(String.. Args).

In the start of Spring applications throughout the process, will be released in different stages of different types of events, such as the beginning will release an application for the event, for different types of events are released through EventPublishingRunListener event publishing, There is an event announcer that encapsulates several ApplicationListener event listeners as follows:

#Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
Copy the code

One LoggingApplicationListener object, after listening to different events, will be related to log system initialization

Note: Spring Boot LoggingSystem initialization process is a little round, a little nested methods, please refer to the serial number patience check

LoggingApplicationListener

Org. Springframework. Boot. Context. Logging. LoggingApplicationListener, Spring boot event listener, is used to initialize the logging system

OnApplicationEvent method

OnApplicationEvent (ApplicationEvent method, which handles listened events

@override public void onApplicationEvent(ApplicationEvent event) {// If (event instanceof) ApplicationStartingEvent) { onApplicationStartingEvent((ApplicationStartingEvent) event); } / / Environment Environment ready event else if (event instanceof ApplicationEnvironmentPreparedEvent) { onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event); } / / application is ready to event else if (event instanceof ApplicationPreparedEvent) {onApplicationPreparedEvent ((ApplicationPreparedEvent)  event); Else if (Event instanceof ContextClosedEvent && (ContextClosedEvent) event).getApplicationContext().getParent() == null) { onContextClosedEvent(); Else if (Event Instanceof ApplicationFailedEvent) {onApplicationFailedEvent(); }}Copy the code

Different methods are called for different events, and the order in which events are published is the order from top to bottom

1. OnApplicationStartingEvent method

Handles the event that the application is being started

Private void onApplicationStartingEvent (ApplicationStartingEvent event) {/ / < 1 > create LoggingSystem object / / specifies the type using the specified, If no, try to create the corresponding object. Logback > Log4j2 > Java Logging) this.loggingSystem = LoggingSystem.get(event.getSpringApplication().getClassLoader()); / / < 2 > LoggingSystem initialization pre-processing enclosing LoggingSystem. BeforeInitialize (); }Copy the code

The process is as follows:

Logback > Log4j2 > Java Logging (logBack > Log4j2 > Java Logging)

2.2. Call the beforeInitialize() method of LoggingSystem to initialize the pre-processing

2. OnApplicationEnvironmentPreparedEvent method

Process events that the environment is ready for

Private void onApplicationEnvironmentPreparedEvent (ApplicationEnvironmentPreparedEvent event) {/ / < 1 > if you are not clear LoggingSystem type, If (this. LoggingSystem == null) {this. LoggingSystem = LoggingSystem.get(event.getSpringApplication().getClassLoader()); } // <2> Initialize the LoggingSystem object, create a log file, Set the log level the initialize (event. GetEnvironment (), the event. The getSpringApplication () getClassLoader ()); }Copy the code

The process is as follows:

1.1. If the LoggingSystem type is not already specified, continue creating the LoggingSystem object here

2.2. The initialize (..) Method to initialize the LoggingSystem object, create a log file, and set the log level

3. The initialize method

protected void initialize(ConfigurableEnvironment environment, ClassLoader ClassLoader) {// <1> According to the Environment through LoggingSystemProperties to the System to configure some log new LoggingSystemProperties(environment).apply(); // <2> Create a log file based on the log name and path configured by the Environment. This. LogFile = logfile.get (environment); if (this.logFile ! = null) {/ / < 3 > added to the System log file name and path of the enclosing logFile. ApplyToSystemProperties (); } // <4> Create a log group object this.loggerGroups = new loggerGroups (DEFAULT_GROUP_LOGGERS); / / < 5 > initialized early Spring the Boot log level (Debug or Trace) initializeEarlyLoggingLevel (environment); // <6> Initialize the LoggingSystem object initializeSystem(Environment, this.loggingSystem, this.logfile); / / < 7 > initialize the final Spring the Boot log level, by setting the Environment configuration of the log level initializeFinalLoggingLevels (Environment, enclosing loggingSystem); / / < > 8 registered a hook with the JVM, used to shut down when the JVM close registerShutdownHookIfNecessary logging system (environment, enclosing loggingSystem); }Copy the code

The initial process is as follows:

1.1. Log some configuration to the System through LoggingSystemProperties according to the Environment

2.2. Create a log file based on the log name and path configured by the Environment. By default, this object is null and will be created when the first log is printed (if it does not exist).

// logfile. Java public static LogFile get(PropertyResolver PropertyResolver) {// get the LogFile name specified by 'logging.file.name', You can also specify String file = getLogFileProperty(propertyResolver, FILE_NAME_PROPERTY, FILE_PROPERTY) via 'logging.file'; // Get the log file path specified by 'logging.file.path', You can also specify String path = getLogFileProperty(propertyResolver, FILE_PATH_PROPERTY, PATH_PROPERTY) via 'logging.path'; / / create a log file if (StringUtils. HasLength (file) | | StringUtils. HasLength (path)) {return new LogFile (file path); } return null; }Copy the code

3.3. Add the name and path of the log file to the System

4.4. Create a log group object

5.5. Initialize the early Spring Boot log level (Debug or Trace)

private void initializeEarlyLoggingLevel(ConfigurableEnvironment environment) { if (this.parseArgs && this.springBootLogging == null) { if (isSet(environment, "debug")) { this.springBootLogging = LogLevel.DEBUG; } if (isSet(environment, "trace")) { this.springBootLogging = LogLevel.TRACE; }}}Copy the code

Initialize the LoggingSystem object

private void initializeSystem(ConfigurableEnvironment environment, LoggingSystem system, LogFile logFile) { LoggingInitializationContext initializationContext = new LoggingInitializationContext(environment); // <1> Find the configuration file path specified by 'logging.config' String logConfig = environment.getProperty(CONFIG_PROPERTY); // <2> If there is no configuration file, no configuration file is specified to initialize LoggingSystem object Or use the default if (ignoreLogConfig(logConfig)) {system.initialize(initializationContext, null, logFile); } // <3> Otherwise, specify the configuration file to initialize the LoggingSystem object else {try {system.initialize(initializationContext, logConfig, logFile); } catch (Exception ex) {// throw Exception}}}Copy the code

Initialize the final Spring Boot log level and set the log level for the Environment configuration one by one

Register a hook with the JVM to shut down the logging system when the JVM shuts down

You can see that it needs to be initialized with the LoggingSystem LoggingSystem object, which I’ll cover later

4. OnApplicationPreparedEvent method

Handle the event that the application is ready

Private void onApplicationPreparedEvent (ApplicationPreparedEvent event) {/ / to the underlying the IoC container register several Bean: LoggingSystem, LogFile and LoggerGroups ConfigurableListableBeanFactory the beanFactory = event.getApplicationContext().getBeanFactory(); if (! beanFactory.containsBean(LOGGING_SYSTEM_BEAN_NAME)) { beanFactory.registerSingleton(LOGGING_SYSTEM_BEAN_NAME, this.loggingSystem); } if (this.logFile ! = null && ! beanFactory.containsBean(LOG_FILE_BEAN_NAME)) { beanFactory.registerSingleton(LOG_FILE_BEAN_NAME, this.logFile); } if (this.loggerGroups ! = null && ! beanFactory.containsBean(LOGGER_GROUPS_BEAN_NAME)) { beanFactory.registerSingleton(LOGGER_GROUPS_BEAN_NAME, this.loggerGroups); }}Copy the code

LoggingSystem

Org. Springframework. Boot. Logging. LoggingSystem abstract classes, Spring the boot log system object, each log framework, there is an implementation class. As shown below:

public abstract class LoggingSystem { private static final Map<String, String> SYSTEMS; static { Map<String, String> systems = new LinkedHashMap<>(); systems.put("ch.qos.logback.core.Appender", "org.springframework.boot.logging.logback.LogbackLoggingSystem"); systems.put("org.apache.logging.log4j.core.impl.Log4jContextFactory", "org.springframework.boot.logging.log4j2.Log4J2LoggingSystem"); systems.put("java.util.logging.LogManager", "org.springframework.boot.logging.java.JavaLoggingSystem"); SYSTEMS = Collections.unmodifiableMap(systems); }}Copy the code

1.1 the get method

Create a LoggingSystem LoggingSystem object as follows:

Public static LoggingSystem get this (this) {/ / < 1 > from the system parameter ` org. Springframework. Boot. Logging. LoggingSystem ` Get the LoggingSystem type String LoggingSystem = system.getProperty (SYSTEM_PROPERTY); // <2> If it is not empty, it is configured. If (stringutils.hasLength (LoggingSystem)) {if (none.equals (LoggingSystem)) {return new NoOpLoggingSystem(); } return get(classLoader, loggingSystem); } // <3> Otherwise, no configuration, // logback > log4j2 > Java Logging 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 process is as follows:

1.1. From the system parameter org. Springframework. Boot. Logging. LoggingSystem LoggingSystem type

2.2. If it is not empty, it is configured. Create an instance object of this type

3.3. Otherwise, there is no configuration, try to create LoggingSystem instance objects of the corresponding type in sequence, i.e. the collection initialized in the static code block logback > Log4j2 > Java Logging

1.2 beforeInitialize method

Initialization precursors, abstract methods, are handed over to subclasses

/**
 * Reset the logging system to be limit output. This method may be called before
 * {@link #initialize(LoggingInitializationContext, String, LogFile)} to reduce
 * logging noise until the system has been fully initialized.
 */
public abstract void beforeInitialize();
Copy the code

2. The initialize method

Initialization operations, empty methods, overridden by subclasses

/** * Fully initialize the logging system. * @param initializationContext the logging initialization context * @param configLocation a log configuration location or {@code null} if default * initialization is required * @param logFile the  log output file that should be written or {@code null} for * console only output */ public void initialize(LoggingInitializationContext initializationContext, String configLocation, LogFile logFile) { }Copy the code

AbstractLoggingSystem

Org. Springframework. Boot. Logging. AbstractLoggingSystem abstract class, inheritance LoggingSystem abstract class, as a base class

2.1 the initialize method

Overrides initialize(..) of the parent class Method to provide templated initialization logic as follows:

@Override public void initialize(LoggingInitializationContext initializationContext, String configLocation, LogFile LogFile) {// <1> There are custom configuration files, Initialized, using the specified configuration file if (StringUtils. HasLength (configLocation)) {initializeWithSpecificConfig (initializationContext, configLocation, logFile); return; } / / < 2 > configuration file, without the custom is initialized using conventional configuration file initializeWithConventions (initializationContext, logFile); }Copy the code

With the configuration of the specified file, then call initializeWithSpecificConfig (..) Method to initialize using the specified configuration file

No custom configuration file, call the initializeWithConventions (..) Method is initialized using a convention configuration file

2.1.1 initializeWithSpecificConfig method

InitializeWithSpecificConfig (LoggingInitializationContext, String, LogFile) method, using the specified initialized configuration file

private void initializeWithSpecificConfig(LoggingInitializationContext initializationContext, String configLocation, LogFile LogFile) {/ / < 1 > get the configuration file path (there may be a placeholder) configLocation = SystemPropertyUtils. ResolvePlaceholders (configLocation); <2> loadConfiguration(initializationContext, configLocation, logFile); }Copy the code

Get the path to the configuration file (possibly with placeholders) and then call loadConfiguration(..) Abstract method to load the configuration file into the logging system

/** * Load a specific configuration. * @param initializationContext the logging initialization context * @param location  the location of the configuration to load (never {@code null}) * @param logFile the file to load or {@code null} if no log file is to be written */ protected abstract void loadConfiguration(LoggingInitializationContext initializationContext, String location, LogFile logFile);Copy the code
2.1.2 initializeWithConventions method

InitializeWithConventions (LoggingInitializationContext, LogFile) method, using conventional initialized configuration file

private void initializeWithConventions(LoggingInitializationContext initializationContext, LogFile LogFile) {/ / < 1 > attempts to gain agreement configuration files, such as log4j2 agreed is log4j2. The XML String config = getSelfInitializationConfig (); <2> If (config! = null && logFile == null) { // self initialization has occurred, Reinitialize in case of property changes // <2.1> Reinitialize (initializationContext) return; } // <3> Try to get the convention configuration file (with '-spring'), If for example log4j2 corresponding is log4j2 - spring. XML config (= = null) {config = getSpringInitializationConfig (); } // <4> get the '-spring' configuration file, then load it into the log system, abstract method, subclass implementation if (config! = null) { loadConfiguration(initializationContext, config, logFile); return; } // <5> load default configuration, abstract method, subclass loadDefaults(initializationContext, logFile); }Copy the code

The process is as follows

Call getSelfInitializationConfig () method, trying to obtain agreement configuration file, such as log4j2 agreed is log4j2. The XML

protected String getSelfInitializationConfig() {
    return findConfig(getStandardConfigLocations());
}

protected abstract String[] getStandardConfigLocations();

private String findConfig(String[] locations) {
    for (String location : locations) {
        ClassPathResource resource = new ClassPathResource(location, this.classLoader);
        if (resource.exists()) {
            return "classpath:" + location;
        }
    }
    return null;
}
Copy the code

If the convention configuration file is found, reinitialize(..) is called. Abstract method, custom initialization, subclass implementation

protected void reinitialize(LoggingInitializationContext initializationContext) { }

Call getSpringInitializationConfig (..) Method, try to get the convention configuration file (with -spring), for example log4j2 corresponds to log4j2-spring.xml

protected String getSpringInitializationConfig() { return findConfig(getSpringConfigLocations()); }protected String[] getSpringConfigLocations() { String[] locations = getStandardConfigLocations(); for (int i = 0; i < locations.length; i++) { String extension = StringUtils.getFilenameExtension(locations[i]); locations[i] = locations[i].substring(0, locations[i].length() - extension.length() - 1) + "-spring." + extension; } return locations; }private String findConfig(String[] locations) { for (String location : locations) { ClassPathResource resource = new ClassPathResource(location, this.classLoader); if (resource.exists()) { return "classpath:" + location; } } return null; }Copy the code

With the -spring configuration file, loadConfiguration(..) is called. Abstract method, load into the log system, subclass implementation

protected abstract void loadConfiguration(LoggingInitializationContext initializationContext, String location, LogFile logFile); If the specified configuration file is not found, call loadDefaults(..). Abstract method, load default configuration, subclass implementation

protected abstract void loadDefaults(LoggingInitializationContext initializationContext, LogFile logFile); The whole process is to try to get the name of the configuration file agreed by each logging framework. If the configuration file exists, load it into the logging system. Otherwise, use the default configuration

Slf4JLoggingSystem org. Springframework. Boot. Logging. Slf4JLoggingSystem, inheritance AbstractLoggingSystem abstract class, Abstract base class for LoggingSystem based on Slf4J

1.2.1 beforeInitialize method

Pre-initialization operations

@Overridepublic void beforeInitialize() { super.beforeInitialize(); / / < 1 > configuration of JUL bridge processor, bridge from slf4j configureJdkLoggingBridgeHandler (); }

To call the superclass beforeInitialize () method, and then call configureJdkLoggingBridgeHandler () method, the configuration of JUL bridge processor, bridge to slf4j

Private void configureJdkLoggingBridgeHandler () {try {/ / < 1 > received SLF4J if whether JUL bridge (isBridgeJulIntoSlf4j ()) {/ / < 2 > Remove JUL bridge processor removeJdkLoggingBridgeHandler (); / / < 3 > reinstall SLF4JBridgeHandler SLF4JBridgeHandler. Install (); } } catch (Throwable ex) { // Ignore. No java.util.logging bridge is installed. }}

The process is as follows:

1. Determine whether JUL Bridges to SLF4J

Protected final Boolean isBridgeJulIntoSlf4j() {SLF4JBridgeHandler exists, And JUL only ConsoleHandler processor is constructed return isBridgeHandlerAvailable () && isJulUsingASingleConsoleHandlerAtMost (); }

3. Remove the JUL bridge processor

Private void removeJdkLoggingBridgeHandler () {try {/ / remove JUL ConsoleHandler removeDefaultRootHandler (); / / unloading SLF4JBridgeHandler SLF4JBridgeHandler. Uninstall (); } catch (Throwable ex) { // Ignore and continue }}private void removeDefaultRootHandler() { try { Logger rootLogger = LogManager.getLogManager().getLogger(""); Handler[] handlers = rootLogger.getHandlers(); if (handlers.length == 1 && handlers[0] instanceof ConsoleHandler) { rootLogger.removeHandler(handlers[0]); } } catch (Throwable ex) { // Ignore and continue }}

3. Reinstall SLF4JBridgeHandler

2.3 the loadConfiguration method

Override methods of the AbstractLoggingSystem superclass to load the specified logging configuration file into the logging system

@Overrideprotected void loadConfiguration(LoggingInitializationContext initializationContext, String location, LogFile logFile) { Assert.notNull(location, "Location must not be null"); if (initializationContext ! = null) {/ / log configuration from the Environment to the System configuration applySystemProperties (initializationContext. GetEnvironment (), logFile); }}

In effect, the log configuration in the Environment is configured in the System

LogbackLoggingSystem

Org. Springframework. Boot. Logging. Logback. LogbackLoggingSystem, inherit Slf4JLoggingSystem abstract classes, based on the logback LoggingSystem implementation class

1.2.2 beforeInitialize method

Override the LoggingSystem method to initialize the pre-action

@overridePublic void beforeInitialize() {// <1> Get LoggerContext Log context LoggerContext = getLoggerContext(); If (isAlreadyInitialized(LoggerContext)) {return; if (isAlreadyInitialized(LoggerContext)) {return; } // <3> calls the parent method super.beforeInitialize(); / / < 4 > add a FILTER to it, because has not been initialized and does not print log loggerContext. GetTurboFilterList (). The add (FILTER); }

The process is as follows:

1. Call getLoggerContext() to obtain the log context of LoggerContext

private LoggerContext getLoggerContext() { ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory(); Return (LoggerContext) Factory; return (LoggerContext) factory; }

2. If LoggerContext already has LoggingSystem, it is initialized

private boolean isAlreadyInitialized(LoggerContext loggerContext) { return loggerContext.getObject(LoggingSystem.class.getName()) ! = null; }

3. Call the parent method

4. Add FILTER to the FILTER. Logs are not generated because the FILTER is not initialized

private static final TurboFilter FILTER = new TurboFilter() { @Override public FilterReply decide(Marker marker, ch.qos.logback.classic.Logger logger, Level level, String format, Object[] params, Throwable t) {return FilterReply.DENY; }};

GetStandardConfigLocations method

Override AbstractLoggingSystem to get the logback standard configuration file name

@Overrideprotected String[] getStandardConfigLocations() { return new String[] { "logback-test.groovy", "logback-test.xml", "logback.groovy", "logback.xml" }; }

2.2 the initialize method

Override the LoggingSystem method to initialize the operation

@Overridepublic void initialize(LoggingInitializationContext initializationContext, String configLocation, LogFile LogFile) {// <1> getLoggerContext log context LoggerContext LoggerContext = getLoggerContext(); If (isAlreadyInitialized(LoggerContext)) {return; if (isAlreadyInitialized(LoggerContext)) {return; } // <3> Call the parent method super.initialize(initializationContext, configLocation, logFile); / / < 4 > removed before adding the FILTER, you can begin to print the log loggerContext. GetTurboFilterList (). Remove (FILTER); // <5> Mark initialized, add a LoggingSystem object markAsInitialized(LoggerContext) to LoggerContext; if (StringUtils.hasText(System.getProperty(CONFIGURATION_FILE_PROPERTY))) { getLogger(LogbackLoggingSystem.class.getName()).warn("Ignoring '" + CONFIGURATION_FILE_PROPERTY + "' system property. Please use 'logging.config' instead."); }}

The process is as follows:

1. Call getLoggerContext() to obtain the log context of LoggerContext

private LoggerContext getLoggerContext() { ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory(); Return (LoggerContext) Factory; return (LoggerContext) factory; }

2. If LoggerContext already has LoggingSystem, it is initialized

private boolean isAlreadyInitialized(LoggerContext loggerContext) { return loggerContext.getObject(LoggingSystem.class.getName()) ! = null; }

3. Call the parent method

4. Remove the FILTER to start printing logs

5. Call markAsInitialized (..) Method, marked initialized, adds a LoggingSystem object to LoggerContext

2.4 the loadConfiguration method

Override AbstractLoggingSystem methods to load the specified logging configuration file into the logging system

@Overrideprotected void loadConfiguration(LoggingInitializationContext initializationContext, String location, LogFile LogFile) {// <1> Call the parent method super.loadConfiguration(initializationContext, location, LogFile); LoggerContext loggerContext = getLoggerContext(); // <2> Reset the LoggerContext object // Add a LevelChangePropagator listener, which takes effect immediately when the log level is changed, without restarting stopAndReset(LoggerContext); Try {// <3> read configuration file and parse, ConfigureByResourceUrl (initializationContext, LoggerContext, Resourceutils.geturl (location)); } catch (Exception ex) { throw new IllegalStateException("Could not initialize Logback logging from " + location, ex); } // <4> Determine if there is an error, So throw an IllegalStateException exception List < Status > statuses = loggerContext. GetStatusManager (). GetCopyOfStatusList (); StringBuilder errors = new StringBuilder(); for (Status status : statuses) { if (status.getLevel() == Status.ERROR) { errors.append((errors.length() > 0) ? String.format("%n") : ""); errors.append(status.toString()); } } if (errors.length() > 0) { throw new IllegalStateException(String.format("Logback configuration error detected: %n%s", errors)); }}

The process is as follows:

1. Call the parent method

2. Reset the LoggerContext object, which adds a LevelChangePropagator listener. Log levels are changed immediately, Private void stopAndReset(LoggerContext LoggerContext) {// Stop loggerContext.stop(); / / reset loggerContext. Reset (); AddLevelChangePropagator (loggerContext) {if (isBridgeHandlerInstalled()) {addLevelChangePropagator(loggerContext); }}private void addLevelChangePropagator(LoggerContext loggerContext) { LevelChangePropagator levelChangePropagator = new LevelChangePropagator(); levelChangePropagator.setResetJUL(true); levelChangePropagator.setContext(loggerContext); loggerContext.addListener(levelChangePropagator); }

3. Read the configuration file, parse it, and configure it in LoggerContext

private void configureByResourceUrl(LoggingInitializationContext initializationContext, LoggerContext loggerContext, URL url) throws JoranException { if (url.toString().endsWith("xml")) { JoranConfigurator configurator = new SpringBootJoranConfigurator(initializationContext); configurator.setContext(loggerContext); configurator.doConfigure(url); } else { new ContextInitializer(loggerContext).configureByResource(url); }}

4. Determine whether an error has occurred and throw an IllegalStateException if yes

Reinitialize method

Implement a method of the class AbstractLoggingSystem and reinitialize

@ Overrideprotected void reinitialize (LoggingInitializationContext initializationContext) {/ / reset getLoggerContext().reset(); GetLoggerContext ().getStatusManager().clear(); / / the specified configuration file, using the configuration file loadConfiguration (initializationContext, getSelfInitializationConfig (), null); }

LoadDefaults method

AbstractLoggingSystem implements a method with class AbstractLoggingSystem that does not specify or specify a configuration file, so load the default configuration to the logging system

@Overrideprotected void loadDefaults(LoggingInitializationContext initializationContext, LogFile logFile) { LoggerContext context = getLoggerContext(); // <1> Reset the LoggerContext object // add a LevelChangePropagator listener, which takes effect when the log level is changed without restarting stopAndReset(context); // <2> Add an OnConsoleStatusListener if debug mode is enabled Boolean debug = boolea.getBoolean (“logback.debug”); if (debug) { StatusListenerConfigHelper.addOnConsoleListenerInstance(context, new OnConsoleStatusListener()); } // <3> Add the default log configuration LogbackConfigurator configurator = debug? new DebugLogbackConfigurator(context) : new LogbackConfigurator(context); Environment environment = initializationContext.getEnvironment(); context.putProperty(LoggingSystemProperties.LOG_LEVEL_PATTERN, environment.resolvePlaceholders(“${logging.pattern.level:${LOG_LEVEL_PATTERN:%5p}}”)); context.putProperty(LoggingSystemProperties.LOG_DATEFORMAT_PATTERN, environment.resolvePlaceholders( “${logging.pattern.dateformat:${LOG_DATEFORMAT_PATTERN:yyyy-MM-dd HH:mm:ss.SSS}}”)); context.putProperty(LoggingSystemProperties.ROLLING_FILE_NAME_PATTERN, environment .resolvePlaceholders(“${logging.pattern.rolling-file-name:${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}”)); / / < 4 > create DefaultLogbackConfiguration object, set into the configurator / / set the transformation rules, such as color conversion, Space transformation new DefaultLogbackConfiguration (initializationContext, logFile). Apply (configurator); / / < 5 > set the log file, press day cutting context. SetPackagingDataEnabled (true); }

The process is as follows:

1. Reset the LoggerContext object, which adds a LevelChangePropagator listener. Log level changes take effect immediately without restarting the application

Private void stopAndReset(LoggerContext LoggerContext) {// Stop loggerContext.stop(); / / reset loggerContext. Reset (); AddLevelChangePropagator (loggerContext) {if (isBridgeHandlerInstalled()) {addLevelChangePropagator(loggerContext); }}private void addLevelChangePropagator(LoggerContext loggerContext) { LevelChangePropagator levelChangePropagator = new LevelChangePropagator(); levelChangePropagator.setResetJUL(true); levelChangePropagator.setContext(loggerContext); loggerContext.addListener(levelChangePropagator); }

2. If the debug mode is enabled, add an OnConsoleStatusListener

3. Add the default log configuration to LoggerContext

4. Create DefaultLogbackConfiguration object set into the configurator, set the transformation rules, such as color conversion and space transformation

5. Set log files and cut logs by day

Log4J2LoggingSystem

Org. Springframework. Boot. Logging. Log4j2. Log4J2LoggingSystem, inherit Slf4JLoggingSystem abstract classes, based on the log4j2 LoggingSystem implementation class

LogbackLoggingSystem and basic similar, interested partners can go to see

JavaLoggingSystem

Org. Springframework. Boot. Logging. Java. JavaLoggingSystem, inherit AbstractLoggingSystem abstract classes, based on jul LoggingSystem implementation class

Logic is relatively simple, interested partners can take a look

conclusion

Sping Boot initializes different LoggingSystem logging systems. This process is also based on Spring’s ApplicationListener event listener mechanism. , for instance, events and application of the radio application is starting to environment has been ready, and then LoggingApplicationListener listening to different events will be carried out in different initialization.

LoggingSystem log system is mainly divided into logback, log4j2 and JUL. This article mainly analyzes the initialization process of logback, because it is the default logging framework of Spring Boot. The whole initialization process is a bit convoluted, there are a lot of nested methods, and the main sections are numbered.

The general process is to configure the JUL to SLf4J bridge, and then try to find the specified configuration file to configure the logging system, which can be set through logging.config. If no configuration file is specified, the specified configuration file, such as logback. XML and log4j2.xml, is obtained. The configuration files specified by Spring, such as logback-spring. XML and log4j2-spring. XML, have not been obtained. If you haven’t found the configuration file, you can only try to load the default configuration.

The last

I here organized a SpringBoot related information documents, Spring series of family barrel, Java systematic information (including Java core knowledge points, interview topics and 21 years of the latest Internet real questions, e-books, etc.) friends who need to pay attention to the public number can be obtained.