一、前言
- 在公司项目中在本地启动调试项目的时候,控制台打印不了sql日志,只能打印一些基本的 INFO 或者 ERROR日志。由于一直忙于迭代,没有时间研究。今天刚有空好记一笔,排查的流程。
- 首先 application.properties 和 logback.xml 都没有直接放在 resource文件夹中,如下:
application.properties 中配置 logback.xml 地址不生效。
二、问题分析:
1、控制台有日志打印,说明引入的有日志打印的插件。但是不能按要求打印,应该是配置文件没有生效。所以先确定 logback.xml 有没有被加载。
-
所以通过应用程序启动的时候打断点进行排查。springboot通过org.springframework.boot.logging.logback.LogbackLoggingSystem这个类在应用启动的时候解析logback配置文件。这个类是LoggingSystem这个类的子类,而LoggingSystem类下还有其它的子类包括JavaLoggingSystem,Log4j2LoggingSystem等实现,从而实现支持不同日志模块。
-
在应用启动的时候,spring会调用org.springframework.boot.logging.AbstractLoggingSystem#initialize方法对日志系统进行初始化。如果在profile中指定了配置的位置(通过logging.file),则会按照指定的目录寻找并加载配置,否则会扫描项目并根据不同日志系统的默认配置路径寻找配置文件。
@Override
public void initialize(LoggingInitializationContext initializationContext, String configLocation, LogFile logFile) {
// 判断是否配置文件路径
if (StringUtils.hasLength(configLocation)) {
initializeWithSpecificConfig(initializationContext, configLocation, logFile);
return;
}
// 如果没有走默认的路径
initializeWithConventions(initializationContext, logFile);
}
- 然后走默认路径 initializeWithConventions(initializationContext, logFile);方法
private void initializeWithConventions(LoggingInitializationContext initializationContext, LogFile logFile) {
// 获取默认文件名称
String config = getSelfInitializationConfig();
if (config != null && logFile == null) {
// self initialization has occurred, reinitialize in case of property changes
// 直接加载
reinitialize(initializationContext);
return;
}
if (config == null) {
// 如果默认名称没有,在名称后面加 -spring 后缀
config = getSpringInitializationConfig();
}
if (config != null) {
// 加载配置
loadConfiguration(initializationContext, config, logFile);
return;
}
// 走默认逻辑
loadDefaults(initializationContext, logFile);
}
- 进入 getSelfInitializationConfig() 方法,在 classpatch 路径中查询是否有默认文件名称。
protected String getSelfInitializationConfig() {
return findConfig(getStandardConfigLocations());
}
- 其中 getStandardConfigLocations() 为抽象方法,不用日志插件有不用的实现。
- 以 logback 为例,默认的方法配置文件名称如下:
LogbackLoggingSystem.
@Override
protected String[] getStandardConfigLocations() {
return new String[] { "logback-test.groovy", "logback-test.xml", "logback.groovy", "logback.xml" };
}
- 然后进入 findConfig() 方法,判断 classpath中是否有符合要求的配置文件。
private String findConfig(String[] locations) {
// 循环遍历上看的文件名称
for (String location : locations) {
ClassPathResource resource = new ClassPathResource(location, this.classLoader);
if (resource.exists()) {
return "classpath:" + location;
}
}
return null;
}
- 如果 config 不为空,则进入加载方法 reinitialize(initializationContext),方法为空,看它子类中实现 。
@Override
protected void reinitialize(LoggingInitializationContext initializationContext) {
getLoggerContext().reset();
getLoggerContext().getStatusManager().clear();
loadConfiguration(initializationContext, getSelfInitializationConfig(), null);
}
其中 config = getSpringInitializationConfig(); 方法和上述类似,只是将上述文件名称加上 -spring 后缀,然后在重新遍历一次,在 classpath 中找新的名字。
protected String[] getSpringConfigLocations() {
String[] locations = getStandardConfigLocations();
for (int i = 0; i < locations.length; i++) {
String extension = StringUtils.getFilenameExtension(locations[i]);
locations[i] = locations[i].substring(0, locations[i].length() - extension.length() - 1) + "-spring."
+ extension;
}
return locations;
}
- 如果默认路径没有相关的,就走默认加载,抽象方法看子类具体实现。
protected abstract void loadDefaults(LoggingInitializationContext initializationContext, LogFile logFile);
三、总结:
- 第一可以通过在 application.yml 文件中指定 logging.file = 指定文件路径。
- 通过加 logback.xml 文件放入到 resource 目录下。
- 通过断点的方式,查看配置文件有没有生效