springboot的LogbackLoggingSystem配置加载流程解析
作者:codecraft
这篇文章主要介绍了springboot的LogbackLoggingSystem配置加载流程源码分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
序
本文主要研究一下springboot的LogbackLoggingSystem
LoggingSystem
org/springframework/boot/logging/LoggingSystem.java
public abstract class LoggingSystem { public abstract void beforeInitialize(); public void initialize(LoggingInitializationContext initializationContext, String configLocation, LogFile logFile) { } public void cleanUp() { } public Runnable getShutdownHandler() { return null; } public Set<LogLevel> getSupportedLogLevels() { return EnumSet.allOf(LogLevel.class); } public void setLogLevel(String loggerName, LogLevel level) { throw new UnsupportedOperationException("Unable to set log level"); } public List<LoggerConfiguration> getLoggerConfigurations() { throw new UnsupportedOperationException("Unable to get logger configurations"); } public LoggerConfiguration getLoggerConfiguration(String loggerName) { throw new UnsupportedOperationException("Unable to get logger configuration"); } }
LoggingSystem定义了beforeInitialize抽象方法,需要子类实现,,同时还提供了setLogLevel、getLoggerConfigurations、getLoggerConfiguration,默认是抛出UnsupportedOperationException
NoOpLoggingSystem
static class NoOpLoggingSystem extends LoggingSystem { @Override public void beforeInitialize() { } @Override public void setLogLevel(String loggerName, LogLevel level) { } @Override public List<LoggerConfiguration> getLoggerConfigurations() { return Collections.emptyList(); } @Override public LoggerConfiguration getLoggerConfiguration(String loggerName) { return null; } }
NoOpLoggingSystem继承了LoggingSystem,其方法都是空操作
AbstractLoggingSystem
org/springframework/boot/logging/AbstractLoggingSystem.java
public abstract class AbstractLoggingSystem extends LoggingSystem { protected static final Comparator<LoggerConfiguration> CONFIGURATION_COMPARATOR = new LoggerConfigurationComparator( ROOT_LOGGER_NAME); private final ClassLoader classLoader; public AbstractLoggingSystem(ClassLoader classLoader) { this.classLoader = classLoader; } @Override public void beforeInitialize() { } @Override public void initialize(LoggingInitializationContext initializationContext, String configLocation, LogFile logFile) { if (StringUtils.hasLength(configLocation)) { initializeWithSpecificConfig(initializationContext, configLocation, logFile); return; } initializeWithConventions(initializationContext, logFile); } /** * Load sensible defaults for the logging system. * @param initializationContext the logging initialization context * @param logFile the file to load or {@code null} if no log file is to be written */ protected abstract void loadDefaults(LoggingInitializationContext initializationContext, LogFile logFile); /** * 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); /** * Reinitialize the logging system if required. Called when * {@link #getSelfInitializationConfig()} is used and the log file hasn't changed. May * be used to reload configuration (for example to pick up additional System * properties). * @param initializationContext the logging initialization context */ protected void reinitialize(LoggingInitializationContext initializationContext) { } //...... }
AbstractLoggingSystem继承了LoggingSystem,它主要是重写了initialize方法,若存在configLocation配置则执行initializeWithSpecificConfig,否则执行initializeWithConventions;它同时还定义了loadDefaults、loadConfiguration抽象方法需要子类实现
Slf4JLoggingSystem
org/springframework/boot/logging/Slf4JLoggingSystem.java
public abstract class Slf4JLoggingSystem extends AbstractLoggingSystem { private static final String BRIDGE_HANDLER = "org.slf4j.bridge.SLF4JBridgeHandler"; public Slf4JLoggingSystem(ClassLoader classLoader) { super(classLoader); } @Override public void beforeInitialize() { super.beforeInitialize(); configureJdkLoggingBridgeHandler(); } @Override public void cleanUp() { if (isBridgeHandlerAvailable()) { removeJdkLoggingBridgeHandler(); } } @Override protected void loadConfiguration(LoggingInitializationContext initializationContext, String location, LogFile logFile) { Assert.notNull(location, "Location must not be null"); if (initializationContext != null) { applySystemProperties(initializationContext.getEnvironment(), logFile); } } //...... }
Slf4JLoggingSystem继承了AbstractLoggingSystem,它覆盖了beforeInitialize,新增configureJdkLoggingBridgeHandler;其cleanUp方法在isBridgeHandlerAvailable的时候执行removeJdkLoggingBridgeHandler;其loadConfiguration在initializationContext不为null的时候执行applySystemProperties
configureJdkLoggingBridgeHandler
private void configureJdkLoggingBridgeHandler() { try { if (isBridgeJulIntoSlf4j()) { removeJdkLoggingBridgeHandler(); SLF4JBridgeHandler.install(); } } catch (Throwable ex) { // Ignore. No java.util.logging bridge is installed. } }
configureJdkLoggingBridgeHandler主要是判断是否将JUL绑定到SLF4J,是的话则removeJdkLoggingBridgeHandler,然后执行SLF4JBridgeHandler.install()
removeJdkLoggingBridgeHandler
private void removeJdkLoggingBridgeHandler() { try { removeDefaultRootHandler(); 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 } }
removeJdkLoggingBridgeHandler主要是执行removeDefaultRootHandler,以及SLF4JBridgeHandler.uninstall()
applySystemProperties
protected final void applySystemProperties(Environment environment, LogFile logFile) { new LoggingSystemProperties(environment).apply(logFile); } public void apply(LogFile logFile) { PropertyResolver resolver = getPropertyResolver(); setSystemProperty(resolver, EXCEPTION_CONVERSION_WORD, "exception-conversion-word"); setSystemProperty(PID_KEY, new ApplicationPid().toString()); setSystemProperty(resolver, CONSOLE_LOG_PATTERN, "pattern.console"); setSystemProperty(resolver, FILE_LOG_PATTERN, "pattern.file"); setSystemProperty(resolver, FILE_CLEAN_HISTORY_ON_START, "file.clean-history-on-start"); setSystemProperty(resolver, FILE_MAX_HISTORY, "file.max-history"); setSystemProperty(resolver, FILE_MAX_SIZE, "file.max-size"); setSystemProperty(resolver, FILE_TOTAL_SIZE_CAP, "file.total-size-cap"); setSystemProperty(resolver, LOG_LEVEL_PATTERN, "pattern.level"); setSystemProperty(resolver, LOG_DATEFORMAT_PATTERN, "pattern.dateformat"); setSystemProperty(resolver, ROLLING_FILE_NAME_PATTERN, "pattern.rolling-file-name"); if (logFile != null) { logFile.applyToSystemProperties(); } }
applySystemProperties通过LoggingSystemProperties设置了系统属性方便后续log配置文件使用
LogbackLoggingSystem
org/springframework/boot/logging/logback/LogbackLoggingSystem.java
public class LogbackLoggingSystem extends Slf4JLoggingSystem { private static final String CONFIGURATION_FILE_PROPERTY = "logback.configurationFile"; private static final LogLevels<Level> LEVELS = new LogLevels<>(); static { LEVELS.map(LogLevel.TRACE, Level.TRACE); LEVELS.map(LogLevel.TRACE, Level.ALL); LEVELS.map(LogLevel.DEBUG, Level.DEBUG); LEVELS.map(LogLevel.INFO, Level.INFO); LEVELS.map(LogLevel.WARN, Level.WARN); LEVELS.map(LogLevel.ERROR, Level.ERROR); LEVELS.map(LogLevel.FATAL, Level.ERROR); LEVELS.map(LogLevel.OFF, Level.OFF); } 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; } }; public LogbackLoggingSystem(ClassLoader classLoader) { super(classLoader); } @Override protected String[] getStandardConfigLocations() { return new String[] { "logback-test.groovy", "logback-test.xml", "logback.groovy", "logback.xml" }; } //...... }
LogbackLoggingSystem继承了Slf4JLoggingSystem,其getStandardConfigLocations返回logback-test.groovy, logback-test.xml, logback.groovy, logback.xml
beforeInitialize
@Override public void beforeInitialize() { LoggerContext loggerContext = getLoggerContext(); if (isAlreadyInitialized(loggerContext)) { return; } super.beforeInitialize(); loggerContext.getTurboFilterList().add(FILTER); }
beforeInitialize方法主要是添加了TurboFilter
initialize
@Override public void initialize(LoggingInitializationContext initializationContext, String configLocation, LogFile logFile) { LoggerContext loggerContext = getLoggerContext(); if (isAlreadyInitialized(loggerContext)) { return; } super.initialize(initializationContext, configLocation, logFile); loggerContext.getTurboFilterList().remove(FILTER); markAsInitialized(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."); } }
initialize方法执行super.initialize(initializationContext, configLocation, logFile),然后markAsInitialized(loggerContext)
loadDefaults
@Override protected void loadDefaults(LoggingInitializationContext initializationContext, LogFile logFile) { LoggerContext context = getLoggerContext(); stopAndReset(context); boolean debug = Boolean.getBoolean("logback.debug"); if (debug) { StatusListenerConfigHelper.addOnConsoleListenerInstance(context, new OnConsoleStatusListener()); } 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}")); new DefaultLogbackConfiguration(initializationContext, logFile).apply(configurator); context.setPackagingDataEnabled(true); }
loadDefaults方法通过LOG_LEVEL_PATTERN、LOG_DATEFORMAT_PATTERN、ROLLING_FILE_NAME_PATTERN以及LogbackConfigurator来初始化DefaultLogbackConfiguration
loadConfiguration
@Override protected void loadConfiguration(LoggingInitializationContext initializationContext, String location, LogFile logFile) { super.loadConfiguration(initializationContext, location, logFile); LoggerContext loggerContext = getLoggerContext(); stopAndReset(loggerContext); try { configureByResourceUrl(initializationContext, loggerContext, ResourceUtils.getURL(location)); } catch (Exception ex) { throw new IllegalStateException("Could not initialize Logback logging from " + location, ex); } 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)); } } 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); } }
loadConfiguration方法主要是执行configureByResourceUrl,该方法通过SpringBootJoranConfigurator或者ContextInitializer的configureByResource进行配置
小结
springboot定义了LoggingSystem、AbstractLoggingSystem、Slf4JLoggingSystem,依次继承,而LogbackLoggingSystem则继承Slf4JLoggingSystem,它主要是定义了要加载的默认的配置文件logback-test.groovy, logback-test.xml, logback.groovy, logback.xml
,以及loadDefaults方法,通过LOG_LEVEL_PATTERN、LOG_DATEFORMAT_PATTERN、ROLLING_FILE_NAME_PATTERN以及LogbackConfigurator来初始化DefaultLogbackConfiguration。
以上就是springboot的LogbackLoggingSystem配置加载流程解析的详细内容,更多关于springboot LogbackLoggingSystem的资料请关注脚本之家其它相关文章!