关于Springboot配置logback.xml不生效问题

2,054 阅读3分钟

一、前言

  • 在公司项目中在本地启动调试项目的时候,控制台打印不了sql日志,只能打印一些基本的 INFO 或者 ERROR日志。由于一直忙于迭代,没有时间研究。今天刚有空好记一笔,排查的流程。
  • 首先 application.properties 和 logback.xml 都没有直接放在 resource文件夹中,如下:

image.png

    application.properties 中配置 logback.xml 地址不生效。
    

image.png

二、问题分析:

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() 为抽象方法,不用日志插件有不用的实现。

Snipaste_2022-02-23_12-45-54.png

  • 以 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);

三、总结:

  1. 第一可以通过在 application.yml 文件中指定 logging.file = 指定文件路径。
  2. 通过加 logback.xml 文件放入到 resource 目录下。
  3. 通过断点的方式,查看配置文件有没有生效