spring boot 源码解析29-LogbackLoggingSystem

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】
免费领取10G资料包与项目实战视频资料

前言

现在我们来分析一下LogbackLoggingSystem,spring boot 中默认生效的,该类也是继承自Slf4JLoggingSystem.

解析

LogbackLoggingSystem

  1. 字段,构造器如下:

        // 初始化中如果在环境变量配置有logback.configurationFile,则打印警告日志,提示其使用logging.config进行替代
        private static final String CONFIGURATION_FILE_PROPERTY = "logback.configurationFile";
    
        // 配置LogLevel与Logback的对应关系
        private static final LogLevels 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);
        }
    
        // 用于在beforeInitialize方法中,向LoggerContext中的TurboFilterList 添加1个TurboFilter,目的是在LoggerContext没有初始化之前对应打印的日志的请求全部拒绝
        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);
        }
    
  2. 方法如下:

    1. getStandardConfigLocations–> 用于指定默认支持的配置文件.代码如下:

          protected String[] getStandardConfigLocations() {
              return new String[] { "logback-test.groovy", "logback-test.xml", "logback.groovy",
                      "logback.xml" };
          }
    2. beforeInitialize,代码如下:

          public void beforeInitialize() {
              // 1. 获得LoggerContext
              LoggerContext loggerContext = getLoggerContext();
              // 2. 如果LoggerContext中已经配置有org.springframework.boot.logging.LoggingSystem对应的logger,则return
              if (isAlreadyInitialized(loggerContext)) {
                  return;
              }
              // 3. 调用父类的初始化方法
              super.beforeInitialize();
              // 4, 向LoggerContext中的TurboFilterList 添加1个TurboFilter,目的是在LoggerContext没有初始化之前对应打印的日志的请求全部拒绝
              loggerContext.getTurboFilterList().add(FILTER);
              // 5. 增加系统属性 : org.jboss.logging.provider-->slf4j
              configureJBossLoggingToUseSlf4j();
          }
      1. 获得LoggerContext
      2. 如果LoggerContext中已经配置有org.springframework.boot.logging.LoggingSystem对应的logger,则return
      3. 调用父类的初始化方法
      4. 向LoggerContext中的TurboFilterList 添加1个TurboFilter,目的是在LoggerContext没有初始化之前对应打印的日志的请求全部拒绝
      5. 增加系统属性 : org.jboss.logging.provider–>slf4j,代码如下:

            private void configureJBossLoggingToUseSlf4j() {
                System.setProperty("org.jboss.logging.provider", "slf4j");
            }
    3. initialize,代码如下:

          public void initialize(LoggingInitializationContext initializationContext,
                  String configLocation, LogFile logFile) {
              // 1. 如果LoggerContext中已经配置有org.springframework.boot.logging.LoggingSystem对应的logger,则return
              LoggerContext loggerContext = getLoggerContext();
              if (isAlreadyInitialized(loggerContext)) {
                  return;
              }
              // 2. 删除TurboFilter,并调用父类的初始化方法
              loggerContext.getTurboFilterList().remove(FILTER);
              super.initialize(initializationContext, configLocation, logFile);
              // 3. 向loggerContext 添加属性,key为org.springframework.boot.logging.LoggingSystem,value --> object, 意味着已经初始化成功
              markAsInitialized(loggerContext);
              // 4. 如果环境变量配置有logback.configurationFile,则打印警告日志,提示其使用logging.config进行替代
              if (StringUtils.hasText(System.getProperty(CONFIGURATION_FILE_PROPERTY))) {
                  getLogger(LogbackLoggingSystem.class.getName()).warn(
                          "Ignoring '" + CONFIGURATION_FILE_PROPERTY + "' system property. "
                                  + "Please use 'logging.config' instead.");
              }
          }
      
      1. 如果LoggerContext中已经配置有org.springframework.boot.logging.LoggingSystem对应的logger,则return
      2. 删除TurboFilter,并调用父类的初始化方法
      3. 向loggerContext 添加属性,key为org.springframework.boot.logging.LoggingSystem,value –> object, 意味着已经初始化成功,代码如下:

            private void markAsInitialized(LoggerContext loggerContext) {
                loggerContext.putObject(LoggingSystem.class.getName(), new Object());
            }
      4. 如果环境变量配置有logback.configurationFile,则打印警告日志,提示其使用logging.config进行替代
    4. loadDefaults,该方法在初始化–>配置文件没有时调用.代码如下:

          protected void loadDefaults(LoggingInitializationContext initializationContext,
                  LogFile logFile) {
              // 1. 获得LoggerContext 并进行重置
              LoggerContext context = getLoggerContext();
              stopAndReset(context);
              // 2. 实例化LogbackConfigurator,并配置LOG_LEVEL_PATTERN,默认为%5p
              LogbackConfigurator configurator = new LogbackConfigurator(context);
              context.putProperty("LOG_LEVEL_PATTERN",
                      initializationContext.getEnvironment().resolvePlaceholders(
                              "${logging.pattern.level:${LOG_LEVEL_PATTERN:%5p}}"));
              // 3. 实例化DefaultLogbackConfiguration
              new DefaultLogbackConfiguration(initializationContext, logFile)
                      .apply(configurator);
              // 4. 
              context.setPackagingDataEnabled(true);
          }
      1. 获得LoggerContext 并进行重置.代码如下:

            private void stopAndReset(LoggerContext loggerContext) {
                loggerContext.stop();
                loggerContext.reset();
                if (isBridgeHandlerAvailable()) {
                    addLevelChangePropagator(loggerContext);
                }
            }
      2. 实例化LogbackConfigurator,并配置LOG_LEVEL_PATTERN,默认为%5p
      3. 实例化DefaultLogbackConfiguration
      4. 设置packagingDataEnabled等于true
    5. loadConfiguration,代码如下:

          protected void loadConfiguration(LoggingInitializationContext initializationContext,
                  String location, LogFile logFile) {
              // 1. 
              super.loadConfiguration(initializationContext, location, logFile);
              // 2. 获得LoggerContext 并进行重置
              LoggerContext loggerContext = getLoggerContext();
              stopAndReset(loggerContext);
              try {
                  // 3. 进行配置
                  configureByResourceUrl(initializationContext, loggerContext,
                          ResourceUtils.getURL(location));
              }
              catch (Exception ex) {
                  throw new IllegalStateException(
                          "Could not initialize Logback logging from " + location, ex);
              }
              // 4. 如果存在异常,则抛出IllegalStateException
              List 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));
              }
          }
      1. 调用父类的loadConfiguration,设置系统的环境变量
      2. 获得LoggerContext 并进行重置
      3. 进行配置,代码如下:

            private void configureByResourceUrl(
                    LoggingInitializationContext initializationContext,
                    LoggerContext loggerContext, URL url) throws JoranException {
                // 1. 如果是xml文件
                if (url.toString().endsWith("xml")) {
                    // 1.1 实例化JoranConfigurator
                    JoranConfigurator configurator = new SpringBootJoranConfigurator(
                            initializationContext);
                    configurator.setContext(loggerContext);
                    // 1.2 配置
                    configurator.doConfigure(url);
                }
                else {
                    // 2. 否则
                    new ContextInitializer(loggerContext).configureByResource(url);
                }
            }
        1. 如果是xml文件,

          1. 实例化JoranConfigurator
          2. 配置

          在JoranConfigurator中,最终会回调addInstanceRules,用来处理对xml中的节点的处理,关于这点,我们会在后面进行阐述

        2. 否则,实例化ContextInitializer进行处理,该类是logback自带的
      4. 如果存在异常,则抛出IllegalStateException
    6. cleanUp,代码如下:

          public void cleanUp() {
              // 1. 获得LoggerContext 并从LoggerContext删除org.springframework.boot.logging.LoggingSystem的属性
              LoggerContext context = getLoggerContext();
              markAsUninitialized(context);
              // 2. 
              super.cleanUp();
              // 3. 清空StatusManager中的状态
              context.getStatusManager().clear();
              // 4. 删除FILTER
              context.getTurboFilterList().remove(FILTER);
          }
      1. 获得LoggerContext 并从LoggerContext删除org.springframework.boot.logging.LoggingSystem的属性
      2. 调用父类的cleanUp,删除slf4j 中root logger 配置的所有handler.
      3. 清空StatusManager中的状态
      4. 删除FILTER
    7. reinitialize,代码如下:

          protected void reinitialize(LoggingInitializationContext initializationContext) {
              getLoggerContext().reset();
              getLoggerContext().getStatusManager().clear();
              loadConfiguration(initializationContext, getSelfInitializationConfig(), null);
          }
    8. getLoggerConfigurations,获得所有的LoggerConfiguration.代码如下:

          public List getLoggerConfigurations() {
              List result = new ArrayList();
              // 1. 获得LoggerContext中所有的logger,遍历之
              for (ch.qos.logback.classic.Logger logger : getLoggerContext().getLoggerList()) {
                  // 2.获得对应的配置添加到result中
                  result.add(getLoggerConfiguration(logger));
              }
              // 3. 排序,将root logger 排在第1位,其他的按照字典顺序排序
              Collections.sort(result, CONFIGURATION_COMPARATOR);
              return result;
          }
      1. 获得LoggerContext中所有的logger,遍历之
      2. 获得对应的配置添加到result中.代码如下:

            public LoggerConfiguration getLoggerConfiguration(String loggerName) {
                return getLoggerConfiguration(getLogger(loggerName));
            }
        1. 根据名字获得对应的Logger,代码如下:

              private ch.qos.logback.classic.Logger getLogger(String name) {
                      LoggerContext factory = getLoggerContext();
                      if (StringUtils.isEmpty(name) || ROOT_LOGGER_NAME.equals(name)) {
                          name = Logger.ROOT_LOGGER_NAME;
                      }
                      return factory.getLogger(name);
                  }
          1. 获得LoggerContext
          2. 如果name等于null,空字符串或者等于ROOT,则将其设置为ROOT
          3. 根据name获得对应的Logger
        2. 将logger封装为LoggerConfiguration,代码如下:

              private LoggerConfiguration getLoggerConfiguration(
                      ch.qos.logback.classic.Logger logger) {
                  // 1. 如果logger等于null,返回null
                  if (logger == null) {
                      return null;
                  }
                  // 2. 根据logger对应的level,影响的Level分别获得LogLevel,
                  LogLevel level = LEVELS.convertNativeToSystem(logger.getLevel());
                  LogLevel effectiveLevel = LEVELS
                          .convertNativeToSystem(logger.getEffectiveLevel());
                  // 3. 获得logger对应的name,如果name等于null,或者等于root,则将其赋值为root
                  String name = logger.getName();
                  if (!StringUtils.hasLength(name) || Logger.ROOT_LOGGER_NAME.equals(name)) {
                      name = ROOT_LOGGER_NAME;
                  }
                  // 4. 实例化LoggerConfiguration进行返回
                  return new LoggerConfiguration(name, level, effectiveLevel);
              }
          1. 如果logger等于null,返回null
          2. 根据logger对应的level,影响的Level分别获得LogLevel,
          3. 获得logger对应的name,如果name等于null,或者等于root,则将其赋值为root
          4. 实例化LoggerConfiguration进行返回
      3. 排序,将root logger 排在第1位,其他的按照字典顺序排序
    9. setLogLevel–> 根据给定的loggerName 设置指定的log级别,代码如下:

          public void setLogLevel(String loggerName, LogLevel level) {
              ch.qos.logback.classic.Logger logger = getLogger(loggerName);
              if (logger != null) {
                  logger.setLevel(LEVELS.convertSystemToNative(level));
              }
          }
      1. 根据loggerName 获得对应的Logger
      2. 如果Logger不等于null,则首先将LogLevel 转换为logback的对应的级别,然后进行设置即可
    10. getShutdownHandler–> 在run方法中调用了LoggerContext#stop,代码如下:

          public Runnable getShutdownHandler() {
              return new ShutdownHandler(); // 在run方法中调用了LoggerContext#stop
          }

      ShutdownHandler代码如下:

          private final class ShutdownHandler implements Runnable {
      
              @Override
              public void run() {
                  getLoggerContext().stop();
              }
          }

LogbackLoggingSystem生命周期

  1. ApplicationStartingEvent事件处理 执行Log4J2LoggingSystem#beforeInitialize方法.在该方法中会调用LogbackLoggingSystem#configureJdkLoggingBridgeHandler,会判断org.slf4j.bridge.SLF4JBridgeHandler是否存在,此时由于加入了spring-boot-starter-logging,因此加入了jul-to-slf4 jar 包,因此会为root logger添加SLF4JBridgeHandler.然后执行后续操作:

    1. 向LoggerContext中的TurboFilterList 添加1个TurboFilter,目的是在LoggerContext没有初始化之前对应打印的日志的请求全部拒绝
    2. 增加系统属性 : org.jboss.logging.provider–>slf4j
  2. ApplicationEnvironmentPreparedEvent 最终会执行LogbackLoggingSystem#initialize,在该方法中会调用AbstractLoggingSystem#initialize , 此时由于默认情况下没有配置logging.config 属性,因此最终会回调LogbackLoggingSystem#loadDefaults,在该方法中进行配置.
  3. ApplicationPreparedEvent 和其他的LoggingSystem一样,都是进行注册
  4. ContextClosedEvent 最终会调用LogbackLoggingSystem#cleanUp,处理逻辑如下:

    1. 获得LoggerContext 并从LoggerContext删除org.springframework.boot.logging.LoggingSystem的属性
    2. 调用父类的cleanUp方法,最终会调用SLF4JBridgeHandler#removeHandlersForRootLogger方法,删除root loger 的hanler
    3. 清空StatusManager中的状态
    4. 删除FILTER
  5. 这步要是生效,需要配置logging.register-shutdown-hook=true.默认不生效.如果配置的话,就会执行LogbackLoggingSystem 中声明的ShutdownHandler的run方法,调用LoggerContext#stop.

DefaultLogbackConfiguration

该类是在spring boot中对logback的默认配置.没有使用常规的xml文件的方式来实现,而是通过该类进行api的配置,目的是改善启动时间.

  1. 该类的字段如下:

        // console 日志格式
        private static final String CONSOLE_LOG_PATTERN = "%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} "
                + "%clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} "
                + "%clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} "
                + "%clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}";
    
        // 文件的 日志格式,需要配置logging.file或者logging.path 才生效
        private static final String FILE_LOG_PATTERN = "%d{yyyy-MM-dd HH:mm:ss.SSS} "
                + "${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}";
    
        // 字符集,默认utf-8
        private static final Charset UTF8 = Charset.forName("UTF-8");
    
        private final PropertyResolver patterns;
    
        // 配置有logging.file或者logging.path,才不为空
        private final LogFile logFile;

    其中CONSOLE_LOG_PATTERN 的解释如下:

        %clr:由ColorConverter 进行处理
        %d{yyyy-MM-dd HH:mm:ss.SSS}: 输出时间
        ${LOG_LEVEL_PATTERN:-%5p}: 日志级别,并且使用5个字符靠左对齐
        ${PID:- }:线程id
        %15.15t:t-->线程 %15.15 如果线程名小于15个字符,则在左边填充空格.如果大于15个字符,则进行截断
        %-40.40logger{39}: 日志输出者的名字,-40.40 : 如果线程名小于40个字符,则在右边填充空格.如果大于40个字符,则进行截断
        %m:日志
        %n:换行符
        {LOG_EXCEPTION_CONVERSION_WORD:-%wEx}: 由ExtendedWhitespaceThrowableProxyConverter 进行处理

    参考链接: Chapter 6: Layouts

    构造器如下:

        DefaultLogbackConfiguration(LoggingInitializationContext initializationContext,
                LogFile logFile) {
            // 1. 实例化PropertyResolver
            this.patterns = getPatternsResolver(initializationContext.getEnvironment());
            this.logFile = logFile;
        }

    调用getPatternsResolver方法进行实例化.代码如下:

        private PropertyResolver getPatternsResolver(Environment environment) {
            if (environment == null) {
                return new PropertySourcesPropertyResolver(null);
            }
            return RelaxedPropertyResolver.ignoringUnresolvableNestedPlaceholders(environment,
                    "logging.pattern.");
        }
    1. 如果Environment等null,则直接返回PropertySourcesPropertyResolver
    2. 返回RelaxedPropertyResolver,读取Environment中以logging.pattern. 开头的配置.默认是在第2步返回的
  2. apply方法如下:

        public void apply(LogbackConfigurator config) {
            synchronized (config.getConfigurationLock()) {
                // 1. 设置conversionRule,logger
                base(config);
                // 2. 实例化consoleAppender
                Appender consoleAppender = consoleAppender(config);
                // 3. 如果logFile 不等于null,
                if (this.logFile != null) {
                    // 3.1 则创建fileAppender,添加到rootLogger中
                    Appender fileAppender = fileAppender(config,
                            this.logFile.toString());
                    config.root(Level.INFO, consoleAppender, fileAppender);
                }
                else {
                    // 否则,只添加consoleAppender到rootLogger中
                    config.root(Level.INFO, consoleAppender);
                }
            }
        }
    
    1. 设置conversionRule,logger.代码如下:

          private void base(LogbackConfigurator config) {
              config.conversionRule("clr", ColorConverter.class);
              config.conversionRule("wex", WhitespaceThrowableProxyConverter.class);
              config.conversionRule("wEx", ExtendedWhitespaceThrowableProxyConverter.class);
              config.logger("org.apache.catalina.startup.DigesterFactory", Level.ERROR);
              config.logger("org.apache.catalina.util.LifecycleBase", Level.ERROR);
              config.logger("org.apache.coyote.http11.Http11NioProtocol", Level.WARN);
              config.logger("org.apache.sshd.common.util.SecurityUtils", Level.WARN);
              config.logger("org.apache.tomcat.util.net.NioSelectorPool", Level.WARN);
              config.logger("org.crsh.plugin", Level.WARN);
              config.logger("org.crsh.ssh", Level.WARN);
              config.logger("org.eclipse.jetty.util.component.AbstractLifeCycle", Level.ERROR);
              config.logger("org.hibernate.validator.internal.util.Version", Level.WARN);
              config.logger("org.springframework.boot.actuate.autoconfigure."
                      + "CrshAutoConfiguration", Level.WARN);
              config.logger("org.springframework.boot.actuate.endpoint.jmx", null, false,
                      debugRemapAppender);
              config.logger("org.thymeleaf", null, false, debugRemapAppender);
          }
      1. 设置conversionRule.相当于在spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml 中的如下配置:

            
            
            
      2. 实例化LevelRemappingAppender,并启动LevelRemappingAppender–>只是将LevelRemappingAppender的父类中(AppenderBase)的started 设置为true.添加appender.相当于在spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml 中的如下配置 :

            
            org.springframework.boot
            
      3. 添加1系列的logger.相当于在spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml 中的如下配置:

            
            
            
            
            
            
            
            
            
            
            
                
            
            
                
            
    2. 实例化consoleAppender,代码如下:

          private Appender consoleAppender(LogbackConfigurator config) {
              // 1. 实例化ConsoleAppender和PatternLayoutEncoder
              ConsoleAppender appender = new ConsoleAppender();
              PatternLayoutEncoder encoder = new PatternLayoutEncoder();
              // 2. 获取logging.pattern.console的配置,如果获取不到则使用CONSOLE_LOG_PATTERN,然后设置到ConsoleAppender 输出格式中
              String logPattern = this.patterns.getProperty("console", CONSOLE_LOG_PATTERN);
              encoder.setPattern(OptionHelper.substVars(logPattern, config.getContext()));
              encoder.setCharset(UTF8);
              config.start(encoder);
              // 3. 启动ConsoleAppender
              appender.setEncoder(encoder);
              // 4. 设置appender的名字为CONSOLE
              config.appender("CONSOLE", appender);
              return appender;
          }
      1. 实例化ConsoleAppender和PatternLayoutEncoder
      2. 获取logging.pattern.console的配置,如果获取不到则使用CONSOLE_LOG_PATTERN,然后设置到ConsoleAppender 输出格式中
      3. 启动ConsoleAppender
      4. 设置appender的名字为CONSOLE

      相当于spring-boot/src/main/resources/org/springframework/boot/logging/logback/console-appender.xml,如下:

          
              
                  ${CONSOLE_LOG_PATTERN}
                  utf8
              
          
    3. 如果logFile 不等于null

      1. 则创建fileAppender,添加到rootLogger中.相当于如下配置:

            
                
                
            
      2. 否则只添加consoleAppender到rootLogger中.相当于如下配置:

            
                
            

ColorConverter

该类用来处理颜色

  1. 字段如下:

        // key --> logback.xml 中配置的颜色,value --> AnsiElement
        private static final Map elements;
    
        static {
            Map ansiElements = new HashMap();
            ansiElements.put("faint", AnsiStyle.FAINT);
            ansiElements.put("red", AnsiColor.RED);
            ansiElements.put("green", AnsiColor.GREEN);
            ansiElements.put("yellow", AnsiColor.YELLOW);
            ansiElements.put("blue", AnsiColor.BLUE);
            ansiElements.put("magenta", AnsiColor.MAGENTA);
            ansiElements.put("cyan", AnsiColor.CYAN);
            elements = Collections.unmodifiableMap(ansiElements);
        }
    
        // key--> 日志级别,value-->AnsiElement
        private static final Map levels;
    
        static {
            Map ansiLevels = new HashMap();
            ansiLevels.put(Level.ERROR_INTEGER, AnsiColor.RED);
            ansiLevels.put(Level.WARN_INTEGER, AnsiColor.YELLOW);
            levels = Collections.unmodifiableMap(ansiLevels);
        }
  2. transform,该方法会再打印日志时回调,代码如下:

        protected String transform(ILoggingEvent event, String in) {
            // getFirstOption--> 返回第1个选项,等于null,意味这里没有进行配置
            // 1. 通过elements根据Option 获得AnsiElement
            AnsiElement element = elements.get(getFirstOption());
            if (element == null) {
                // 2. 如果没有对应的Element,则根据日志级别获得,如果还是获取不到,则返回GREEN
                // Assume highlighting
                element = levels.get(event.getLevel().toInteger());
                element = (element == null ? AnsiColor.GREEN : element);
            }
            // 3. 转成string 
            return toAnsiString(in, element);
        }
    1. 通过elements根据Option 获得AnsiElement
    2. 如果没有对应的Element,则根据日志级别获得,如果还是获取不到,则返回GREEN
    3. 转成string ,代码如下:

          protected String toAnsiString(String in, AnsiElement element) {
              return AnsiOutput.toString(element, in);
          }

    详细说明,以如下一条日志为例:

    2018-01-22 16:38:41.812 INFO 55134 — [ main] com.example.demo.DemoApplication : The following profiles are active: test

    1. 由于 2018-01-22 16:38:41.812 属于默认配置的日志格式中的%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} 因此会在transform方法的第1步获得AnsiStyle.FAINT
    2. 由于 INFO 属于默认配置的日志格式中的%clr(${LOG_LEVEL_PATTERN:-%5p}) 由于没有配置颜色,同时在ColorConverter中也没有配置info级别所对应的颜色,因此返回的是AnsiColor.GREEN
    3. 由于 55134 属于默认配置的日志格式中的%clr(${PID:- }){magenta} 因此会在transform方法返回AnsiColor.MAGENTA
    4. 由于 — 属于默认配置的日志格式中的%clr(—){faint} 因此会在transform方法返回AnsiStyle.FAIN
    5. 由于 [ main] 属于默认配置的日志格式中的%clr([%15.15t]){faint} 因此会在transform方法返回AnsiStyle.FAIN
    6. 由于 com.example.demo.DemoApplication 属于默认配置的日志格式中的%clr(%-40.40logger{39}){cyan} 因此会在transform方法返回AnsiColor.CYAN
    7. 由于 : 属于默认配置的日志格式中的%clr(:){faint} 因此会在transform方法返回AnsiStyle.FAIN

ExtendedWhitespaceThrowableProxyConverter

该类是在异常堆栈的打印过程中添加一些空格.

  1. throwableProxyToString–> 在打印日志的过程中会调用.代码如下:

        protected String throwableProxyToString(IThrowableProxy tp) {
            return CoreConstants.LINE_SEPARATOR + super.throwableProxyToString(tp)
                    + CoreConstants.LINE_SEPARATOR;
        }

    其实就是在堆栈的日志前后加上换行符


来源:[]()

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » spring boot 源码解析29-LogbackLoggingSystem

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏