当前位置: 首页 > news >正文

聊聊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 {@Overridepublic void beforeInitialize() {}@Overridepublic void setLogLevel(String loggerName, LogLevel level) {}@Overridepublic List<LoggerConfiguration> getLoggerConfigurations() {return Collections.emptyList();}@Overridepublic 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;}@Overridepublic void beforeInitialize() {}@Overridepublic 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);}@Overridepublic void beforeInitialize() {super.beforeInitialize();configureJdkLoggingBridgeHandler();}@Overridepublic void cleanUp() {if (isBridgeHandlerAvailable()) {removeJdkLoggingBridgeHandler();}}@Overrideprotected 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() {@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);}@Overrideprotected 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

	@Overridepublic void beforeInitialize() {LoggerContext loggerContext = getLoggerContext();if (isAlreadyInitialized(loggerContext)) {return;}super.beforeInitialize();loggerContext.getTurboFilterList().add(FILTER);}

beforeInitialize方法主要是添加了TurboFilter

initialize

	@Overridepublic 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

	@Overrideprotected 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

	@Overrideprotected 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。

相关文章:

  • 【Kubernetes】初识k8s--扫盲阶段
  • Git 的基本操作 ——命令行
  • LLaMA-Adapter源码解析
  • 【数据结构】树家族
  • Linux背景介绍与环境搭建
  • 你的编程能力从什么时候开始突飞猛进?
  • 2014年亚太杯APMCM数学建模大赛A题无人机创造安全环境求解全过程文档及程序
  • 京东大数据平台-第三方京东平台数据查询分析软件系统
  • 【Ubuntu】安装chrome之后无法启动
  • ChatGLM3设置角色和工具调用的解决方案
  • SkyWalking官方文档-1-概述
  • 程序员笔记本电脑选 windows 还是 MAC
  • Spring Boot 面试题——常用注解
  • uniapp原生插件之安卓文字转拼音原生插件
  • VMware 虚拟机安装 CentOS 7
  • 《Java编程思想》读书笔记-对象导论
  • 【译】React性能工程(下) -- 深入研究React性能调试
  • C++回声服务器_9-epoll边缘触发模式版本服务器
  • Cookie 在前端中的实践
  • egg(89)--egg之redis的发布和订阅
  • If…else
  • Java到底能干嘛?
  • java中具有继承关系的类及其对象初始化顺序
  • k8s 面向应用开发者的基础命令
  • nginx 配置多 域名 + 多 https
  • PHP 7 修改了什么呢 -- 2
  • React-生命周期杂记
  • webpack4 一点通
  • windows下如何用phpstorm同步测试服务器
  • 悄悄地说一个bug
  • 容器服务kubernetes弹性伸缩高级用法
  • Java性能优化之JVM GC(垃圾回收机制)
  • 测评:对于写作的人来说,Markdown是你最好的朋友 ...
  • 东超科技获得千万级Pre-A轮融资,投资方为中科创星 ...
  • 函数计算新功能-----支持C#函数
  • ​Base64转换成图片,android studio build乱码,找不到okio.ByteString接腾讯人脸识别
  • ​人工智能之父图灵诞辰纪念日,一起来看最受读者欢迎的AI技术好书
  • ###C语言程序设计-----C语言学习(6)#
  • #预处理和函数的对比以及条件编译
  • $(document).ready(function(){}), $().ready(function(){})和$(function(){})三者区别
  • $forceUpdate()函数
  • ()、[]、{}、(())、[[]]命令替换
  • (react踩过的坑)antd 如何同时获取一个select 的value和 label值
  • (附源码)ssm经济信息门户网站 毕业设计 141634
  • (更新)A股上市公司华证ESG评级得分稳健性校验ESG得分年均值中位数(2009-2023年.12)
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (十六)一篇文章学会Java的常用API
  • (五)关系数据库标准语言SQL
  • (五)网络优化与超参数选择--九五小庞
  • (原創) X61用戶,小心你的上蓋!! (NB) (ThinkPad) (X61)
  • (转) SpringBoot:使用spring-boot-devtools进行热部署以及不生效的问题解决
  • (转)C#开发微信门户及应用(1)--开始使用微信接口
  • (转)socket Aio demo
  • (转)视频码率,帧率和分辨率的联系与区别
  • ***测试-HTTP方法