logback部分
官网:http://logback.qos.ch/
这里忽略slf4j的外观模式
测试代码
测试代码:
jar版本
slfj 2.0.7
logback 1.4.7
public static void main(String[] args) {
Logger loggerFactory = LoggerFactory.getLogger("root");
loggerFactory.debug("123");
}
logback.xml
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level aaa %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
启动流程
入口:org.slf4j.LoggerFactory#getLogger(java.lang.String)
static SLF4JServiceProvider getProvider() {
if (INITIALIZATION_STATE == UNINITIALIZED) {
//当没有初始化时,进行同步初始化
synchronized (LoggerFactory.class) {
if (INITIALIZATION_STATE == UNINITIALIZED) {
INITIALIZATION_STATE = ONGOING_INITIALIZATION;
performInitialization();
}
}
}
// INITIALIZATION_STATE 记录初始化状态
}
sl4j的外观模式主要通过下面3和4的实现,重点放到3上
private final static void bind() {
try {
//1.通过classLoader加载可能存在的SLF4JServiceProvider实现类
List<SLF4JServiceProvider> providersList = findServiceProviders();
//2.sout控制台报告获取到的实现类
reportMultipleBindingAmbiguity(providersList);
if (providersList != null && !providersList.isEmpty()) {
//3.如果有组件实现SLF4JServiceProvider接口,则取第一个实现类
PROVIDER = providersList.get(0);
// SLF4JServiceProvider.initialize() is intended to be called here and nowhere else.
//3.1 子类实现进行初始化
PROVIDER.initialize();
INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
reportActualBinding(providersList);
} else {
INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
Util.report("No SLF4J providers were found.");
Util.report("Defaulting to no-operation (NOP) logger implementation");
Util.report("See " + NO_PROVIDERS_URL + " for further details.");
//4.如果没有,获取是否存在指定路径的类org/slf4j/impl/StaticLoggerBinder.class,这种将初始化将完成交由组件
Set<URL> staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
reportIgnoredStaticLoggerBinders(staticLoggerBinderPathSet);
}
postBindCleanUp();
...
}
logback中的提供服务实现类 ch.qos.logback.classic.spi.LogbackServiceProvider
@Override
public void initialize() {
...
//进行初始化
initializeLoggerContext();
...
}
上线文初始化执行类 ch.qos.logback.classic.util.ContextInitializer
public void autoConfig(ClassLoader classLoader) throws JoranException {
...
StatusListenerConfigHelper.installIfAsked(loggerContext);
//⭐获取Configurator配置实现类,这里十分重要,配置文件读取
List<Configurator> configuratorList = ClassicEnvUtil.loadFromServiceLoader(Configurator.class, classLoader);
//排序
sortByPriority(configuratorList);
...
//省略依次执行配置实现类的代码
...
// at this stage invoke basicConfigurator
fallbackOnToBasicConfigurator();
}
logback.xml、logback-test.xml配置文件读取的实现 ch.qos.logback.classic.util.DefaultJoranConfigurator
衍生一点:org.springframework.boot.logging.logback.RootLogLevelConfigurator,springboot3开始默认log级别info的实现,借鉴点可以通过实现configura来达到改变loggerContext的目的
日志打印流程
其他
springboot-logging部分
https://springdoc.cn/spring-boot/features.html#features.logging
启动加载流程
启动监听LoggingApplicationListener
org.springframework.boot.context.logging.LoggingApplicationListener#onApplicationStartingEvent
private void onApplicationStartingEvent(ApplicationStartingEvent event) {
//获取指定log组件
this.loggingSystem = LoggingSystem.get(event.getSpringApplication().getClassLoader());
//初始化
this.loggingSystem.beforeInitialize();
}
springboot中为了适配多个日志组件,设计了代理类DelegatingLoggingSystemFactory,
@Override
public LoggingSystem getLoggingSystem(ClassLoader classLoader) {
List<LoggingSystemFactory> delegates = (this.delegates != null) ? this.delegates.apply(classLoader) : null;
if (delegates != null) {
for (LoggingSystemFactory delegate : delegates) {
// 依次遍历多个组件是否存在
LoggingSystem loggingSystem = delegate.getLoggingSystem(classLoader);
if (loggingSystem != null) {
return loggingSystem;
}
}
}
return null;
}
具体初始化实现部分以LogbackLoggingSystem举例
@Override
public void beforeInitialize() {
LoggerContext loggerContext = getLoggerContext();
if (isAlreadyInitialized(loggerContext)) {
return;
}
super.beforeInitialize();
configureJdkLoggingBridgeHandler();
loggerContext.getTurboFilterList().add(FILTER);
}
最终会走到这
private void initializeWithConventions(LoggingInitializationContext initializationContext, LogFile logFile) {
//1.先加载原生配置文件 logback.xml
String config = getSelfInitializationConfig();
if (config != null && logFile == null) {
// self initialization has occurred, reinitialize in case of property changes
reinitialize(initializationContext);
return;
}
if (config == null) {
//2.取原生配置文件名+-spring的配置文件
config = getSpringInitializationConfig();
}
if (config != null) {
loadConfiguration(initializationContext, config, logFile);
return;
}
loadDefaults(initializationContext, logFile);
}