Skip to content

Latest commit

History

History
445 lines (369 loc) · 14.4 KB

File metadata and controls

445 lines (369 loc) · 14.4 KB

SpringBoot 日志系统

日志级别

  • 日志级别: org.springframework.boot.logging.LogLevel

    publicenumLogLevel {
    TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF
    }

Java 日志实现

  • org.springframework.boot.logging.java.JavaLoggingSystem

    image-20200323144523848

    static {
    // KEY : springBoot 定义的日志级别, value: jdk 定义的日志级别LEVELS.map(LogLevel.TRACE, Level.FINEST);
    LEVELS.map(LogLevel.DEBUG, Level.FINE);
    LEVELS.map(LogLevel.INFO, Level.INFO);
    LEVELS.map(LogLevel.WARN, Level.WARNING);
    LEVELS.map(LogLevel.ERROR, Level.SEVERE);
    LEVELS.map(LogLevel.FATAL, Level.SEVERE);
    LEVELS.map(LogLevel.OFF, Level.OFF);
    }
  • LEVELS 对象

    protectedstaticclassLogLevels<T> {
    /** * key : SpringBoot 中定义的日志级别, value: 其他日志框架的日志级别 */privatefinalMap<LogLevel, T> systemToNative;
    /** * key : 其他日志框架的日志级别 , value: springBoot 中定义中定义的日志级别 */privatefinalMap<T, LogLevel> nativeToSystem;
    }

LoggingSystem

  • 抽象类

  • org.springframework.boot.logging.LoggingSystem

  • 一个 map 对象: SYSTEMS

    /** * key: 第三方日志框架的类 value: springBoot 中的处理类 */privatestaticfinalMap<String, String> SYSTEMS;
    static {
    Map<String, String> systems = newLinkedHashMap<>();
    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);
    }
  • 各个抽象方法

    方法名称作用
    beforeInitialize初始化之前调用,目的是减少日志输出
    initialize初始化日志
    cleanUp清除日志
    getShutdownHandler
    getSupportedLogLevels获取支持的日志级别
    setLogLevel设置日志级别
    getLoggerConfigurations获取日志配置

get

publicstaticLoggingSystemget(ClassLoaderclassLoader) {
// 获取系统属性StringloggingSystem = System.getProperty(SYSTEM_PROPERTY);
if (StringUtils.hasLength(loggingSystem)) {
// 是不是NONEif (NONE.equals(loggingSystem)) {
// 空的日志系统returnnewNoOpLoggingSystem();
}
returnget(classLoader, loggingSystem);
}
// 循环所有日志,returnSYSTEMS.entrySet().stream().filter((entry) -> ClassUtils.isPresent(entry.getKey(), classLoader))
.map((entry) ->
// 实例化具体日志get(classLoader, entry.getValue())).findFirst()
.orElseThrow(() -> newIllegalStateException("No suitable logging system located"));
}
  • 实例化日志系统
privatestaticLoggingSystemget(ClassLoaderclassLoader, StringloggingSystemClass) {
try {
Class<?> systemClass = ClassUtils.forName(loggingSystemClass, classLoader);
Constructor<?> constructor = systemClass.getDeclaredConstructor(ClassLoader.class);
constructor.setAccessible(true);
return (LoggingSystem) constructor.newInstance(classLoader);
}
catch (Exceptionex) {
thrownewIllegalStateException(ex);
}
}

image-20200323151409473

  • 默认日志: org.springframework.boot.logging.logback.LogbackLoggingSystem

beforeInitialize

  • 初始化之前

    image-20200323154205484

  • 链路

    1. org.springframework.boot.context.logging.LoggingApplicationListener#onApplicationEvent
    2. org.springframework.boot.context.logging.LoggingApplicationListener#onApplicationStartingEvent
    3. org.springframework.boot.logging.LoggingSystem#beforeInitialize
  • 因为前文中我们已知对象是:org.springframework.boot.logging.logback.LogbackLoggingSystem 直接看这个类的 beforeInitialize 方法

    @OverridepublicvoidbeforeInitialize() {
    // 日志上下文LoggerContextloggerContext = getLoggerContext();
    // 是否初始化if (isAlreadyInitialized(loggerContext)) {
    return;
    }
    // 父类方法super.beforeInitialize();
    // 添加过滤器loggerContext.getTurboFilterList().add(FILTER);
    }
  • 初始化之前的的操作完成了初始化方法开始

initialize

  • org.springframework.boot.context.logging.LoggingApplicationListener#onApplicationEnvironmentPreparedEvent

    privatevoidonApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEventevent) {
    if (this.loggingSystem == null) {
    this.loggingSystem = LoggingSystem.get(event.getSpringApplication().getClassLoader());
    }
    initialize(event.getEnvironment(), event.getSpringApplication().getClassLoader());
    }
  • org.springframework.boot.context.logging.LoggingApplicationListener#initializeSystem

    protectedvoidinitialize(ConfigurableEnvironmentenvironment, ClassLoaderclassLoader) {
    newLoggingSystemProperties(environment).apply();
    this.logFile = LogFile.get(environment);
    if (this.logFile != null) {
    this.logFile.applyToSystemProperties();
    }
    this.loggerGroups = newLoggerGroups(DEFAULT_GROUP_LOGGERS);
    // 早期 的日志级别initializeEarlyLoggingLevel(environment);
    // 初始化日志系统initializeSystem(environment, this.loggingSystem, this.logFile);
    // 初始化日志级别initializeFinalLoggingLevels(environment, this.loggingSystem);
    registerShutdownHookIfNecessary(environment, this.loggingSystem);
    }
    privatevoidinitializeSystem(ConfigurableEnvironmentenvironment, LoggingSystemsystem, LogFilelogFile) {
    LoggingInitializationContextinitializationContext = newLoggingInitializationContext(environment);
    StringlogConfig = environment.getProperty(CONFIG_PROPERTY);
    if (ignoreLogConfig(logConfig)) {
    // 日志系统初始化system.initialize(initializationContext, null, logFile);
    }
    else {
    try {
    ResourceUtils.getURL(logConfig).openStream().close();
    system.initialize(initializationContext, logConfig, logFile);
    }
    catch (Exceptionex) {
    // NOTE: We can't use the logger here to report the problemSystem.err.println("Logging system failed to initialize using configuration from '" + logConfig + "'");
    ex.printStackTrace(System.err);
    thrownewIllegalStateException(ex);
    }
    }
    }
  • org.springframework.boot.logging.logback.LogbackLoggingSystem#initialize

    @Overridepublicvoidinitialize(LoggingInitializationContextinitializationContext, StringconfigLocation, LogFilelogFile) {
    LoggerContextloggerContext = 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.");
    }
    }
  • org.springframework.boot.logging.AbstractLoggingSystem#initializeWithConventions

    privatevoidinitializeWithConventions(LoggingInitializationContextinitializationContext, LogFilelogFile) {
    Stringconfig = getSelfInitializationConfig();
    if (config != null && logFile == null) {
    // self initialization has occurred, reinitialize in case of property changesreinitialize(initializationContext);
    return;
    }
    if (config == null) {
    config = getSpringInitializationConfig();
    }
    if (config != null) {
    loadConfiguration(initializationContext, config, logFile);
    return;
    }
    // 加载默认配置loadDefaults(initializationContext, logFile);
    }
  • org.springframework.boot.logging.logback.LogbackLoggingSystem#loadDefaults

    @OverrideprotectedvoidloadDefaults(LoggingInitializationContextinitializationContext, LogFilelogFile) {
    LoggerContextcontext = getLoggerContext();
    stopAndReset(context);
    booleandebug = Boolean.getBoolean("logback.debug");
    if (debug) {
    StatusListenerConfigHelper.addOnConsoleListenerInstance(context, newOnConsoleStatusListener());
    }
    LogbackConfiguratorconfigurator = debug ? newDebugLogbackConfigurator(context)
    : newLogbackConfigurator(context);
    Environmentenvironment = 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}"));
    newDefaultLogbackConfiguration(initializationContext, logFile).apply(configurator);
    context.setPackagingDataEnabled(true);
    }
    @Overridepublicvoidinitialize(LoggingInitializationContextinitializationContext, StringconfigLocation, LogFilelogFile) {
    LoggerContextloggerContext = getLoggerContext();
    // 是否加载过if (isAlreadyInitialized(loggerContext)) {
    return;
    }
    // 日志初始化super.initialize(initializationContext, configLocation, logFile);
    // 删除 FILTERloggerContext.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.");
    }
    }
  • 标记 markAsInitialized

    privatevoidmarkAsInitialized(LoggerContextloggerContext) {
    loggerContext.putObject(LoggingSystem.class.getName(), newObject());
    }

此时日志初始化完成。

默认配置文件

  • getStandardConfigLocations 这个方法定义了默认配置文件有哪些。

    @OverrideprotectedString[] getStandardConfigLocations() {
    returnnewString[] { "logback-test.groovy", "logback-test.xml", "logback.groovy", "logback.xml" };
    }
  • 切回 org.springframework.boot.logging.AbstractLoggingSystem#initializeWithConventions 方法

  • 添加依赖

    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-logging</artifactId>
    <version>${revision}</version>
    </dependency>
    
  • 添加配置文件

    image-20200323161442058

    image-20200323161522570

  • 此时配置文件地址出现了

    protectedStringgetSelfInitializationConfig() {
    // 寻找配置文件returnfindConfig(getStandardConfigLocations());
    }
    @OverrideprotectedString[] getStandardConfigLocations() {
    returnnewString[] { "logback-test.groovy", "logback-test.xml", "logback.groovy", "logback.xml" };
    }
    privateStringfindConfig(String[] locations) {
    for (Stringlocation : locations) {
    ClassPathResourceresource = newClassPathResource(location, this.classLoader);
    if (resource.exists()) {
    return"classpath:" + location;
    }
    }
    returnnull;
    }
  • 此时自定义配置文件如何获取的已经明了。

reinitialize

@Overrideprotectedvoidreinitialize(LoggingInitializationContextinitializationContext) {
// 日志上下文重新设置getLoggerContext().reset();
getLoggerContext().getStatusManager().clear();
// 加载配置文件loadConfiguration(initializationContext, getSelfInitializationConfig(), null);
}
@OverrideprotectedvoidloadConfiguration(LoggingInitializationContextinitializationContext, Stringlocation,
LogFilelogFile) {
// 父类方法super.loadConfiguration(initializationContext, location, logFile);
// 获取上下文LoggerContextloggerContext = getLoggerContext();
// 停止并且重启stopAndReset(loggerContext);
try {
// 配置文件加载configureByResourceUrl(initializationContext, loggerContext, ResourceUtils.getURL(location));
}
catch (Exceptionex) {
thrownewIllegalStateException("Could not initialize Logback logging from " + location, ex);
}
List<Status> statuses = loggerContext.getStatusManager().getCopyOfStatusList();
StringBuildererrors = newStringBuilder();
for (Statusstatus : statuses) {
if (status.getLevel() == Status.ERROR) {
errors.append((errors.length() > 0) ? String.format("%n") : "");
errors.append(status.toString());
}
}
if (errors.length() > 0) {
thrownewIllegalStateException(String.format("Logback configuration error detected: %n%s", errors));
}
}
privatevoidconfigureByResourceUrl(LoggingInitializationContextinitializationContext, LoggerContextloggerContext,
URLurl) throwsJoranException {
if (url.toString().endsWith("xml")) {
// logback 日志操作JoranConfiguratorconfigurator = newSpringBootJoranConfigurator(initializationContext);
// 设置上下文configurator.setContext(loggerContext);
// 执行配置configurator.doConfigure(url);
}
else {
newContextInitializer(loggerContext).configureByResource(url);
}
}

执行配置属于 logback 操作源码不在此进行分析。