spring boot 源码解析29-LogbackLoggingSystem
前言
现在我们来分析一下LogbackLoggingSystem,spring boot 中默认生效的,该类也是继承自Slf4JLoggingSystem.
解析
LogbackLoggingSystem
字段,构造器如下:
// 初始化中如果在环境变量配置有logback.configurationFile,则打印警告日志,提示其使用logging.config进行替代 private static final String CONFIGURATION_FILE_PROPERTY = "logback.configurationFile";// 配置LogLevel与Logback的对应关系 private static final LogLevels<Level> LEVELS = new LogLevels<Level>();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() {@Overridepublic 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); }
方法如下:
getStandardConfigLocations–> 用于指定默认支持的配置文件.代码如下:
protected String[] getStandardConfigLocations() {return new String[] { "logback-test.groovy", "logback-test.xml", "logback.groovy","logback.xml" }; }
beforeInitialize,代码如下:
public void beforeInitialize() {// 1. 获得LoggerContextLoggerContext loggerContext = getLoggerContext();// 2. 如果LoggerContext中已经配置有org.springframework.boot.logging.LoggingSystem对应的logger,则returnif (isAlreadyInitialized(loggerContext)) {return;}// 3. 调用父类的初始化方法super.beforeInitialize();// 4, 向LoggerContext中的TurboFilterList 添加1个TurboFilter,目的是在LoggerContext没有初始化之前对应打印的日志的请求全部拒绝loggerContext.getTurboFilterList().add(FILTER);// 5. 增加系统属性 : org.jboss.logging.provider-->slf4jconfigureJBossLoggingToUseSlf4j(); }
- 获得LoggerContext
- 如果LoggerContext中已经配置有org.springframework.boot.logging.LoggingSystem对应的logger,则return
- 调用父类的初始化方法
- 向LoggerContext中的TurboFilterList 添加1个TurboFilter,目的是在LoggerContext没有初始化之前对应打印的日志的请求全部拒绝
增加系统属性 : org.jboss.logging.provider–>slf4j,代码如下:
private void configureJBossLoggingToUseSlf4j() {System.setProperty("org.jboss.logging.provider", "slf4j"); }
initialize,代码如下:
public void initialize(LoggingInitializationContext initializationContext,String configLocation, LogFile logFile) {// 1. 如果LoggerContext中已经配置有org.springframework.boot.logging.LoggingSystem对应的logger,则returnLoggerContext 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.");} }
- 如果LoggerContext中已经配置有org.springframework.boot.logging.LoggingSystem对应的logger,则return
- 删除TurboFilter,并调用父类的初始化方法
向loggerContext 添加属性,key为org.springframework.boot.logging.LoggingSystem,value –> object, 意味着已经初始化成功,代码如下:
private void markAsInitialized(LoggerContext loggerContext) {loggerContext.putObject(LoggingSystem.class.getName(), new Object()); }
如果环境变量配置有logback.configurationFile,则打印警告日志,提示其使用logging.config进行替代
loadDefaults,该方法在初始化–>配置文件没有时调用.代码如下:
protected void loadDefaults(LoggingInitializationContext initializationContext,LogFile logFile) {// 1. 获得LoggerContext 并进行重置LoggerContext context = getLoggerContext();stopAndReset(context);// 2. 实例化LogbackConfigurator,并配置LOG_LEVEL_PATTERN,默认为%5pLogbackConfigurator configurator = new LogbackConfigurator(context);context.putProperty("LOG_LEVEL_PATTERN",initializationContext.getEnvironment().resolvePlaceholders("${logging.pattern.level:${LOG_LEVEL_PATTERN:%5p}}"));// 3. 实例化DefaultLogbackConfigurationnew DefaultLogbackConfiguration(initializationContext, logFile).apply(configurator);// 4. context.setPackagingDataEnabled(true); }
获得LoggerContext 并进行重置.代码如下:
private void stopAndReset(LoggerContext loggerContext) {loggerContext.stop();loggerContext.reset();if (isBridgeHandlerAvailable()) {addLevelChangePropagator(loggerContext);} }
- 实例化LogbackConfigurator,并配置LOG_LEVEL_PATTERN,默认为%5p
- 实例化DefaultLogbackConfiguration
- 设置packagingDataEnabled等于true
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. 如果存在异常,则抛出IllegalStateExceptionList<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));} }
- 调用父类的loadConfiguration,设置系统的环境变量
- 获得LoggerContext 并进行重置
进行配置,代码如下:
private void configureByResourceUrl(LoggingInitializationContext initializationContext,LoggerContext loggerContext, URL url) throws JoranException {// 1. 如果是xml文件if (url.toString().endsWith("xml")) {// 1.1 实例化JoranConfiguratorJoranConfigurator configurator = new SpringBootJoranConfigurator(initializationContext);configurator.setContext(loggerContext);// 1.2 配置configurator.doConfigure(url);}else {// 2. 否则new ContextInitializer(loggerContext).configureByResource(url);} }
如果是xml文件,
- 实例化JoranConfigurator
- 配置
在JoranConfigurator中,最终会回调addInstanceRules,用来处理对xml中的节点的处理,关于这点,我们会在后面进行阐述
- 否则,实例化ContextInitializer进行处理,该类是logback自带的
- 如果存在异常,则抛出IllegalStateException
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. 删除FILTERcontext.getTurboFilterList().remove(FILTER); }
- 获得LoggerContext 并从LoggerContext删除org.springframework.boot.logging.LoggingSystem的属性
- 调用父类的cleanUp,删除slf4j 中root logger 配置的所有handler.
- 清空StatusManager中的状态
- 删除FILTER
reinitialize,代码如下:
protected void reinitialize(LoggingInitializationContext initializationContext) {getLoggerContext().reset();getLoggerContext().getStatusManager().clear();loadConfiguration(initializationContext, getSelfInitializationConfig(), null); }
getLoggerConfigurations,获得所有的LoggerConfiguration.代码如下:
public List<LoggerConfiguration> getLoggerConfigurations() {List<LoggerConfiguration> result = new ArrayList<LoggerConfiguration>();// 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; }
- 获得LoggerContext中所有的logger,遍历之
获得对应的配置添加到result中.代码如下:
public LoggerConfiguration getLoggerConfiguration(String loggerName) {return getLoggerConfiguration(getLogger(loggerName)); }
根据名字获得对应的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);}
- 获得LoggerContext
- 如果name等于null,空字符串或者等于ROOT,则将其设置为ROOT
- 根据name获得对应的Logger
将logger封装为LoggerConfiguration,代码如下:
private LoggerConfiguration getLoggerConfiguration(ch.qos.logback.classic.Logger logger) {// 1. 如果logger等于null,返回nullif (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,则将其赋值为rootString 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); }
- 如果logger等于null,返回null
- 根据logger对应的level,影响的Level分别获得LogLevel,
- 获得logger对应的name,如果name等于null,或者等于root,则将其赋值为root
- 实例化LoggerConfiguration进行返回
- 排序,将root logger 排在第1位,其他的按照字典顺序排序
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));} }
- 根据loggerName 获得对应的Logger
- 如果Logger不等于null,则首先将LogLevel 转换为logback的对应的级别,然后进行设置即可
getShutdownHandler–> 在run方法中调用了LoggerContext#stop,代码如下:
public Runnable getShutdownHandler() {return new ShutdownHandler(); // 在run方法中调用了LoggerContext#stop }
ShutdownHandler代码如下:
private final class ShutdownHandler implements Runnable {@Overridepublic void run() {getLoggerContext().stop();} }
LogbackLoggingSystem生命周期
ApplicationStartingEvent事件处理 执行Log4J2LoggingSystem#beforeInitialize方法.在该方法中会调用LogbackLoggingSystem#configureJdkLoggingBridgeHandler,会判断org.slf4j.bridge.SLF4JBridgeHandler是否存在,此时由于加入了spring-boot-starter-logging,因此加入了jul-to-slf4 jar 包,因此会为root logger添加SLF4JBridgeHandler.然后执行后续操作:
- 向LoggerContext中的TurboFilterList 添加1个TurboFilter,目的是在LoggerContext没有初始化之前对应打印的日志的请求全部拒绝
- 增加系统属性 : org.jboss.logging.provider–>slf4j
ApplicationEnvironmentPreparedEvent 最终会执行LogbackLoggingSystem#initialize,在该方法中会调用AbstractLoggingSystem#initialize , 此时由于默认情况下没有配置logging.config 属性,因此最终会回调LogbackLoggingSystem#loadDefaults,在该方法中进行配置.
ApplicationPreparedEvent 和其他的LoggingSystem一样,都是进行注册
ContextClosedEvent 最终会调用LogbackLoggingSystem#cleanUp,处理逻辑如下:
- 获得LoggerContext 并从LoggerContext删除org.springframework.boot.logging.LoggingSystem的属性
- 调用父类的cleanUp方法,最终会调用SLF4JBridgeHandler#removeHandlersForRootLogger方法,删除root loger 的hanler
- 清空StatusManager中的状态
- 删除FILTER
这步要是生效,需要配置logging.register-shutdown-hook=true.默认不生效.如果配置的话,就会执行LogbackLoggingSystem 中声明的ShutdownHandler的run方法,调用LoggerContext#stop.
DefaultLogbackConfiguration
该类是在spring boot中对logback的默认配置.没有使用常规的xml文件的方式来实现,而是通过该类进行api的配置,目的是改善启动时间.
该类的字段如下:
// 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. 实例化PropertyResolverthis.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."); }
- 如果Environment等null,则直接返回PropertySourcesPropertyResolver
- 返回RelaxedPropertyResolver,读取Environment中以logging.pattern. 开头的配置.默认是在第2步返回的
apply方法如下:
public void apply(LogbackConfigurator config) {synchronized (config.getConfigurationLock()) {// 1. 设置conversionRule,loggerbase(config);// 2. 实例化consoleAppenderAppender<ILoggingEvent> consoleAppender = consoleAppender(config);// 3. 如果logFile 不等于null,if (this.logFile != null) {// 3.1 则创建fileAppender,添加到rootLogger中Appender<ILoggingEvent> fileAppender = fileAppender(config,this.logFile.toString());config.root(Level.INFO, consoleAppender, fileAppender);}else {// 否则,只添加consoleAppender到rootLogger中config.root(Level.INFO, consoleAppender);}} }
设置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); }
设置conversionRule.相当于在spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml 中的如下配置:
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" /> <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" /> <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
实例化LevelRemappingAppender,并启动LevelRemappingAppender–>只是将LevelRemappingAppender的父类中(AppenderBase)的started 设置为true.添加appender.相当于在spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml 中的如下配置 :
<appender name="DEBUG_LEVEL_REMAPPER" class="org.springframework.boot.logging.logback.LevelRemappingAppender"> <destinationLogger>org.springframework.boot</destinationLogger> </appender>
添加1系列的logger.相当于在spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml 中的如下配置:
<logger name="org.apache.catalina.startup.DigesterFactory" level="ERROR"/> <logger name="org.apache.catalina.util.LifecycleBase" level="ERROR"/> <logger name="org.apache.coyote.http11.Http11NioProtocol" level="WARN"/> <logger name="org.apache.sshd.common.util.SecurityUtils" level="WARN"/> <logger name="org.apache.tomcat.util.net.NioSelectorPool" level="WARN"/> <logger name="org.crsh.plugin" level="WARN"/> <logger name="org.crsh.ssh" level="WARN"/> <logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="ERROR"/> <logger name="org.hibernate.validator.internal.util.Version" level="WARN"/> <logger name="org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration" level="WARN"/> <logger name="org.springframework.boot.actuate.endpoint.jmx" additivity="false"><appender-ref ref="DEBUG_LEVEL_REMAPPER"/> </logger> <logger name="org.thymeleaf" additivity="false"><appender-ref ref="DEBUG_LEVEL_REMAPPER"/> </logger>
实例化consoleAppender,代码如下:
private Appender<ILoggingEvent> consoleAppender(LogbackConfigurator config) {// 1. 实例化ConsoleAppender和PatternLayoutEncoderConsoleAppender<ILoggingEvent> appender = new ConsoleAppender<ILoggingEvent>();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. 启动ConsoleAppenderappender.setEncoder(encoder);// 4. 设置appender的名字为CONSOLEconfig.appender("CONSOLE", appender);return appender; }
- 实例化ConsoleAppender和PatternLayoutEncoder
- 获取logging.pattern.console的配置,如果获取不到则使用CONSOLE_LOG_PATTERN,然后设置到ConsoleAppender 输出格式中
- 启动ConsoleAppender
- 设置appender的名字为CONSOLE
相当于spring-boot/src/main/resources/org/springframework/boot/logging/logback/console-appender.xml,如下:
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>${CONSOLE_LOG_PATTERN}</pattern><charset>utf8</charset></encoder> </appender>
如果logFile 不等于null
则创建fileAppender,添加到rootLogger中.相当于如下配置:
<root level="INFO"><appender-ref ref="CONSOLE" /><appender-ref ref="FILE" /> </root>
否则只添加consoleAppender到rootLogger中.相当于如下配置:
<root level="INFO"><appender-ref ref="CONSOLE" /> </root>
ColorConverter
该类用来处理颜色
字段如下:
// key --> logback.xml 中配置的颜色,value --> AnsiElement private static final Map<String, AnsiElement> elements;static {Map<String, AnsiElement> ansiElements = new HashMap<String, AnsiElement>();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<Integer, AnsiElement> levels;static {Map<Integer, AnsiElement> ansiLevels = new HashMap<Integer, AnsiElement>();ansiLevels.put(Level.ERROR_INTEGER, AnsiColor.RED);ansiLevels.put(Level.WARN_INTEGER, AnsiColor.YELLOW);levels = Collections.unmodifiableMap(ansiLevels); }
transform,该方法会再打印日志时回调,代码如下:
protected String transform(ILoggingEvent event, String in) {// getFirstOption--> 返回第1个选项,等于null,意味这里没有进行配置// 1. 通过elements根据Option 获得AnsiElementAnsiElement element = elements.get(getFirstOption());if (element == null) {// 2. 如果没有对应的Element,则根据日志级别获得,如果还是获取不到,则返回GREEN// Assume highlightingelement = levels.get(event.getLevel().toInteger());element = (element == null ? AnsiColor.GREEN : element);}// 3. 转成string return toAnsiString(in, element); }
- 通过elements根据Option 获得AnsiElement
- 如果没有对应的Element,则根据日志级别获得,如果还是获取不到,则返回GREEN
转成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
- 由于 2018-01-22 16:38:41.812 属于默认配置的日志格式中的%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} 因此会在transform方法的第1步获得AnsiStyle.FAINT
- 由于 INFO 属于默认配置的日志格式中的%clr(${LOG_LEVEL_PATTERN:-%5p}) 由于没有配置颜色,同时在ColorConverter中也没有配置info级别所对应的颜色,因此返回的是AnsiColor.GREEN
- 由于 55134 属于默认配置的日志格式中的%clr(${PID:- }){magenta} 因此会在transform方法返回AnsiColor.MAGENTA
- 由于 — 属于默认配置的日志格式中的%clr(—){faint} 因此会在transform方法返回AnsiStyle.FAIN
- 由于 [ main] 属于默认配置的日志格式中的%clr([%15.15t]){faint} 因此会在transform方法返回AnsiStyle.FAIN
- 由于 com.example.demo.DemoApplication 属于默认配置的日志格式中的%clr(%-40.40logger{39}){cyan} 因此会在transform方法返回AnsiColor.CYAN
- 由于 : 属于默认配置的日志格式中的%clr(:){faint} 因此会在transform方法返回AnsiStyle.FAIN
ExtendedWhitespaceThrowableProxyConverter
该类是在异常堆栈的打印过程中添加一些空格.
throwableProxyToString–> 在打印日志的过程中会调用.代码如下:
protected String throwableProxyToString(IThrowableProxy tp) {return CoreConstants.LINE_SEPARATOR + super.throwableProxyToString(tp)+ CoreConstants.LINE_SEPARATOR; }
其实就是在堆栈的日志前后加上换行符
spring boot 源码解析29-LogbackLoggingSystem相关推荐
- spring boot 源码解析23-actuate使用及EndPoint解析
前言 spring boot 中有个很诱人的组件–actuator,可以对spring boot应用做监控,只需在pom文件中加入如下配置即可: <dependency><group ...
- spring boot 源码解析52-actuate中MVCEndPoint解析
前言 之前的几篇文章分析了spring boot 中有关endpoint的实现,细心的朋友可以发现,在org.springframework.boot.actuate.endpoint.mvc 包下也 ...
- spring boot 源码解析15-spring mvc零配置
前言 spring boot 是基于spring 4 的基础上的一个框架,spring 4 有一个新特效–>基于java config 实现零配置.而在企业的实际工作中,spring 都是和sp ...
- spring boot 源码解析43-JmxMetricWriter详解
前言 本文我们来介绍JmxMetricWriter, JmxMetricWriter是依赖于spring jmx 来实现的. 因此本文的开头先介绍一下spring boot 与jmx的集成,然后分析J ...
- spring boot 源码解析8-SpringApplication#run第8步
前言 这篇文章我们分析SpringApplication#run第8步.执行prepareContext方法.该方法的内容比较多.我们慢慢来. 分析 SpringApplication#run 第8步 ...
- spring boot 源码解析31-AuthenticationAuditListener,AuthorizationAuditListener
前言 这篇文章我们来分析一下org.springframework.boot.actuate.security,org.springframework.boot.actuate.audit中的代码,这 ...
- Spring Boot源码简析 @EnableTransactionManagement
相关阅读 Spring Boot源码简析 事务管理 Spring Boot源码简析 @EnableAspectJAutoProxy Spring Boot源码简析 @EnableAsync Sprin ...
- 【细读Spring Boot源码】重中之重refresh()
前言 版本:spring-boot-2.7.3 | spring-context-5.3.22 在Spring Boot启动过程中[细读Spring Boot源码]启动步骤 主流程详情7中applic ...
- spring事务源码解析
前言 在spring jdbcTemplate 事务,各种诡异,包你醍醐灌顶!最后遗留了一个问题:spring是怎么样保证事务一致性的? 当然,spring事务内容挺多的,如果都要讲的话要花很长时间, ...
最新文章
- 自然语言处理(NLP)之依存句法分析的可视化及图分析
- 英语计算机单词mp3,计算机英语会话(MP3+中英字幕) 第1期:计算机系统(1)
- 专家:教育等领域将成为人工智能“用武之地”
- 数字图像处理与机器视觉——Visual C++与Matlab实现书中代码勘误
- 华为简易压缩算法python_Python(9) --实现一个简单的压缩软件/解压软件的功能
- matlab 动态分配内存,[Matlab科学计算之高效编程] 1. 预分配内存
- 计算机太卡了怎么解决,电脑太慢太卡怎么办,电脑太慢太卡解决方法
- java真实面试题(2)
- 文献笔记(7)(2017ISSCC 14.3)
- arcgis属性字段fid修改 修改出现bad value
- 怎么免费注册微信小程序-微信小程序开发-视频教程1
- electron start之后index.html页面不显示
- timed out waiting for to be synced
- 最近很火火火火的 GitHub 项目
- 跨数据中心场景下,kafka集群部署模式
- FastDfs与ElasticSearch和Mysql完成海量数据存储搜索功能
- Vue+Element 实现订单列表【管理端】02
- Zookeeper-3.4.5安装步骤及异常处理
- Tomcat网页乱码、控制台乱码
- 如何快速的把图片转换为PDF文件格式