Springboot change log4j2 write log source code analysis (2024)

Previous article (Springboot default log frame selection analysisThe SpringBoot's default log frame is analyzed from the source phase to logback, Spring-boot package, Logging.logback has the default log configuration XML; if you use LogBack as a log frame, add relevant configurations; so how Log4J2 comes as a log framework for SpringBoot? Why choose Log4J2 as a log framework, you can find it;

Still starting with Loggingsystem, as shown below, we need to add parameters before the program starts (second code block); so that SpringBoot is started, you will use the configuration log4j2loggingsystem; of course, you need to introduce LOG4J2 related packages in Grdle. Otherwise, the exception of Class will not be found; Compile "org.apache.logging.log4j: log4j-API: 2.14.0"; Compile "Org.apache.logging.log4j: log4j-core: 2.14.0" quote grdle

public static LoggingSystem get(ClassLoader classLoader) {String loggingSystemClassName = System.getProperty(SYSTEM_PROPERTY);if (StringUtils.hasLength(loggingSystemClassName)) {if (NONE.equals(loggingSystemClassName)) {return new NoOpLoggingSystem();}return get(classLoader, loggingSystemClassName);}LoggingSystem loggingSystem = SYSTEM_FACTORY.getLoggingSystem(classLoader);Assert.state(loggingSystem != null, "No suitable logging system located");return loggingSystem;}

1, start function to add System Property

 public static void main(String[] args) { System.setProperty("org.springframework.boot.logging.LoggingSystem", "org.springframework.boot.logging.log4j2.Log4J2LoggingSystem"); SpringApplication.run(Bootstrap.class, args); }

2, add log4j2.xml to the resources directory, the name of the log4j2 cannot be changed:Note setting logpath, logfile

<?xml version="1.0" encoding="UTF-8"?><Configuration status="WARN"> <Properties> <property name="logPath">/Users/dengyouhua/logs</property> <property name="logFile">com-fenghua-util</property> </Properties> <Appenders> <Console name="console_log" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </Console> <RollingFile name="file_log" fileName="${logPath}/${logFile}.log" append="true" filePattern="${logPath}/${logFile}-%d{yyyy-MM-dd}-%i.log"> <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/> <Policies> <TimeBasedTriggeringPolicy/> <SizeBasedTriggeringPolicy size="500MB"/> </Policies> </RollingFile> </Appenders> <Loggers> <Root level="debug"> <AppenderRef ref="file_log"/> <AppenderRef ref="console_log"/> </Root> </Loggers></Configuration>

3. The following packages need to be discharged, the way is Gradle directly to discharge the package; separately go to the package, will leak the row, especially when using the Spring family

configurations { compile.exclude module: "spring-boot-starter-logging"}

At this point, your log is really printed using log4j2.

Next, we will explain from the source level, and you need to have more step more; in the first step, add the system parameters, this is in the previous and the beginning, to manually set the Springboot log frame; Will get the default logback option; the second step is to add log4j2.xml configuration, this is not good to say, configure the relevant parameters of log printing.

The third step is why you need to discharge the package, org.apache.commons.logging.logadapter This class determines the spring-boot-starter-logging package to be discharged; because the package will automatically introduce LogBack, SLF4J-related packages;

The focus is logical in the state of logadapter; if you don't discharge the top bag, ispresent (log4j_slf4j_provider && ispresent (SLF4J_SPI) must true, then logapi, logapi.slf4j_lal

private static final String LOG4J_SPI = "org.apache.logging.log4j.spi.ExtendedLogger";private static final String LOG4J_SLF4J_PROVIDER = "org.apache.logging.slf4j.SLF4JProvider";private static final String SLF4J_SPI = "org.slf4j.spi.LocationAwareLogger";private static final String SLF4J_API = "org.slf4j.Logger";private static final LogApi logApi;static {if (isPresent(LOG4J_SPI)) {if (isPresent(LOG4J_SLF4J_PROVIDER) && isPresent(SLF4J_SPI)) {// log4j-to-slf4j bridge -> we'll rather go with the SLF4J SPI;// however, we still prefer Log4j over the plain SLF4J API since// the latter does not have location awareness support.logApi = LogApi.SLF4J_LAL;}else {// Use Log4j 2.x directly, including location awareness supportlogApi = LogApi.LOG4J;}}else if (isPresent(SLF4J_SPI)) {// Full SLF4J SPI including location awareness supportlogApi = LogApi.SLF4J_LAL;}else if (isPresent(SLF4J_API)) {// Minimal SLF4J API without location awareness supportlogApi = LogApi.SLF4J;}else {// java.util.logging as defaultlogApi = LogApi.JUL;}}private LogAdapter() {}/** * Create an actual {@link Log} instance for the selected API. * @param name the logger name */public static Log createLog(String name) {switch (logApi) {case LOG4J:return Log4jAdapter.createLog(name);case SLF4J_LAL:return Slf4jAdapter.createLocationAwareLog(name);case SLF4J:return Slf4jAdapter.createLog(name);default:return JavaUtilAdapter.createLog(name);}}

This is called SLF4JADAPTER.CREATELOCATIONAWARELOG when Createlog, which is an internal class of LogAdapter, as shown below:

private static class Slf4jAdapter {public static Log createLocationAwareLog(String name) {Logger logger = LoggerFactory.getLogger(name);return (logger instanceof LocationAwareLogger ?new Slf4jLocationAwareLog((LocationAwareLogger) logger) : new Slf4jLog<>(logger));}public static Log createLog(String name) {return new Slf4jLog<>(LoggerFactory.getLogger(name));}}

The FindPossibleSticLoggerBinderPathSet method in LoggerFactory will eventually call, which loads a specified class ORG / SLF4J / IMPL / StaticLoggerBinder.class; as follows:

 private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class"; static Set<URL> findPossibleStaticLoggerBinderPathSet() { // use Set instead of list in order to deal with bug #138 // LinkedHashSet appropriate here because it preserves insertion order // during iteration Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<URL>(); try { ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader(); Enumeration<URL> paths; if (loggerFactoryClassLoader == null) { paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH); } else { paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH); } while (paths.hasMoreElements()) { URL path = paths.nextElement(); staticLoggerBinderPathSet.add(path); } } catch (IOException ioe) { Util.report("Error getting resources from path", ioe); } return staticLoggerBinderPathSet; }

The StaticLoggerBinder class specifies that loggerContext is Ch.QoS.logback.classic.loggerContext, so logback is used as a component of the write log; this class is in org.slf4j.impl, logback-classic package;

So the third step is dropped off the package as the necessary steps, otherwise it will take the default Logback log frame;

Summarize:

SpringBoot Sets log4j2 to the log frame, you need to complete the above three steps; simple summary is as follows:

1. Start function Add System.SetProperty ("Org.SpringFramework.boot.logging.loggingsystem", "Org.SpringFramework.boot.logging.log4j2.log4j2loggingsystem");

2, add log4j2.xml configuration

3, add log4j2 compile "org.apache.logging.log4j: log4j-API: 2.14.0"; Compile "org.apache.logging.log4j: log4j-core: 2.4.0" dependent package, and globally eliminates Spring- Boot-star-logging

Springboot change log4j2 write log source code analysis (2024)

References

Top Articles
Latest Posts
Article information

Author: Carmelo Roob

Last Updated:

Views: 5834

Rating: 4.4 / 5 (65 voted)

Reviews: 88% of readers found this page helpful

Author information

Name: Carmelo Roob

Birthday: 1995-01-09

Address: Apt. 915 481 Sipes Cliff, New Gonzalobury, CO 80176

Phone: +6773780339780

Job: Sales Executive

Hobby: Gaming, Jogging, Rugby, Video gaming, Handball, Ice skating, Web surfing

Introduction: My name is Carmelo Roob, I am a modern, handsome, delightful, comfortable, attractive, vast, good person who loves writing and wants to share my knowledge and understanding with you.