Spring Boot 与 Logback 日志配置

本文记录 SpringBoot 与 Logback 是如何工作的,即观察 SpringBoot 中 Logback  是怎么一步一步初始化的。用以测试的 SpringBoot 版本是 1.5.16, 而非最新的 SpringBoot 2。关于 SpringBoot 日志的官方文档在 Logging, 但不太详细或透彻。本文也不承诺说就理解得更有深度,只是为官方文档提供更多方面的参考。

SpringBoot 默认使用 Slf4J + Logback 来记录日志,对于一个基本的依赖于

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>

的 Spring Boot 项目,上面组件依赖了 spring-boot-starter-logging 组件,而该组件又引入了以下几个依赖

  1. logback-classic:   依赖了 Slf4J
  2. jcl-over-slf4j
  3. jul-to-slf4j
  4. log4j-over-slf4j

相当于把其他的日志框架全桥接到了 Slf4J + Logback 上去了。

那么  Spring Boot Web 项目是怎么样子的呢?spring-boot-starter-web 依赖于  spring-boot-starter,所以日志框架选用上就没有一点区别了。

Spring Boot 应用默认日志输出

从一个最简单的 Spring Boot 应用程序来感受它的配置日志输出,一个 Maven 项目,最基本的配置是

注意:spring-boot-starter-parent 的 pom.xml 文件值得瞧一瞧的。

当 application.properties 文件内容为空,并且没有任何的 Logback 配置文件在 resources 目录中时,

来个最简单的程序

在 SpringApplication.run(...) 前后各调用  logger.info(...) 输出信息

前面 logger.info("aaa") 和 logger.info("bbb") 的输出用红线标示出来了,可以非常感性的认识到

  1. 它们输出样式不同,所以使用了不同的日志配置
  2. logger.info("aaa") 发生在 Spring 上下文初始化之前,以 Logback 的默认行为初始化的 LoggerFactory
  3. logger.info("bbb") 发生在  Spring 上下文初始化之后,因此 Spring Boot 又重新配置了 Logback 的 LoggerFactory
  4. #2 不是我们这里探讨的范畴,它和普通 Java 应用使用 Logback 是一致的,主要看 #3 怎么来的,并且默认的 Log 是怎么样的配置

Spring Boot 是如何初始化 Logback 的

在 Logging 一文中提到了 Spring Boot 有一个 LoggingSystem 抽象来负责配置日志系统,并且 Logback 是首选。LoggingSystem 是一个抽象类,它的实现层次如下

既然说 Logback 是首选,那么 Spring Boot 最终是要用到 LogbackLoggingSystem 这个类的,那我们从源代码跟踪一下 Spring Boot 的 Spring 上下文是如何与 Logback 衔接起来的。

能与 Spring 上下文进行交互的一般来说是 ApplicationEvent, 这里是 org.springframework.boot.logging.LoggingApplicationListener, 它实现了 ApplicationListener, 看 LoggingApplicationListener 的事件方法

#1 找到 LoggingSystem 的实现类,在 LoggingSystem.get(classloader) 方法中,如果配置了系统属性 org.springframework.boot.logging.LoggingSystem 对应的实现类的话,就用它,指定为 none 值就用 NoOpLogginSystem 实现,即没有任何日志输出。如果没有指定 org.springframework.boot.logging.LoggingSystem 系统属性,LoggingSystem 则尝试以下的顺序找实现类

  1. ch.qos.logback.core.Appender => org.springframework.boot.logging.logback.LogbackLoggingSystem
  2. ora.apache.logging.log4j.core.impl.Log4jContextFactory => org.springframework.boot.logging.log4j2.Log4J2LoggingSystem
  3. java.util.logging.LogManager => org.springframework.boot.logging.java.JavaLoggingSystem

而显然 LogbackLoggingSystem 对应的类 ch.qos.logback.core.Appender 是存在于 springboot starter 中的,所以在 #1 中可以确定是用 LogbackLoggingSystem 实现

#3 先说这最后一步,如果初始化好,把 LoggingSystem 的实例(此处为 LogbackLoggingSystem 实例) 注册名为 springBootLogginSystem 的 Spring Bean

#2 对日志进行配置,具体实现在 LoggingApplicationListener.initialize(environment, classLoader) 和 LogbackLoggingSystem.initialize(...) 方法中。不列出实际代码来了,只解翻译一下过程

  1. 试图从 Spring 属性(包括配置在 Spring 属性文件,--logging.file= 或 -Dlogging.file= 这样的配置)读出配置的 logging.file 和  logging.path 值,如果有的话,分别映射为 LOG_FILE 和 LOG_PATH 系统属性值,这可以在 logback.xml 的配置中用 ${LOG_FILE} 引用到
  2. 初始日志级别的设置,如果 Spring 属性中配置了  debug=true 则为 LogLevel.DEBUG, 如果配置了 trace=true 则为 LogLevel.TRACE。后面还会专为某些包预设一些日志级别,并且最后的日志级别可在 Spring 属性中用 logging.level.logger_name=DEBUG 来一一配置,如 logging.level.org.springframework=DEBUG
  3. 如果用 Spring 属性 logging.config 指定了配置文件,则使用该配置文件初始化 Logback 的 LoggerFactory,否则 LogbackLoggingSystem 将会以下面的顺序来查找 Logback 配置文件

    logback-test.groovy, logback-test.xml, logback.groovy, logback.xml
    logback-test-spring.xml, logback-test-spring.xml, logback-spring.groovy, logback-spring.xml (AbstractLoggingSystem.getSpringConfigLocations() 方法)

    注意:SpringBoot 会忽略掉普通 Logback 应用的系统属性 logback.configurationFile 设定配置文件的方法

  4. 如果检查了以上八个文件都不存在的话,就要调用 LogbackLoggingSystem.loadDefaults(initializationContext, logFile) 来配置默认的日志。

Spring Boot 没有任何日志配置文件时配置

这块其实是上面步骤 #2 中的一个子步骤,因其重要才将其单独列出,来看看 SpringBoot 在没有加载到任何的配置文件时如何配置默认 Logback 的 LoggerFactory。入口就是 LogbackLoggingSystem.loadDefaults(initializationContext, logFile)

首先,默认显示日志级别的格式是:${logging.pattern.level:${LOG_LEVEL_PATTERN:%5p}}, 可用 Spring 属性 logging.pattern.level 或系统属性 LOG_LEVEL_PATTERN,默认为  %5p

其他的默认配置就要参考类  org.springframework.boot.logging.logback.DefaultLogbackConfiguation

不管有没有配置 logging.file 或 logging.path,Spring Boot 都会初始化 consoleAppender, 并且默认的输出模式是

该模式可用 Spring 属性 logging.pattern.console 进行覆盖设置。注意,Spring Boot 还为我们定义了 clr, wEx 这两个 Converter

如果配置了 Spring 属性 logging.file 和 logging.path 其中一个或两个,就会在 consoleAppender 的基础上再加一个 fileAppender, 它的输出模式是

该模式可以用 Spring 属性 logging.pattern.file 进行覆盖。

日志文件是 10MB 大小不断滚动的,不会删除旧文件。

日志文件路径如何决定的

  1. 如果只设置了 Spring 属性 logging.file, 就是 logging.file 所指定的文件,文件名可以是绝对文件路径,或者相对路径
  2. 如果只设置了 Spring 属性 logging.path, 那么日志文件是 logging.path 下的 spring.log 文件
  3. 如果以上两个属性同时指定了,则只有 logging.file 是有用的,与 #1 同

无论是对于 consoleAppender 还是 fileAppender, 都是设置 INFO 为默认日志级别,并且预设了一些 logger 的日志输出级别。

简单的 Spring Boot 日志文件配置

理解了 SpringBoot 是如何初始化 Logback 日志配置后,我们来看一下项目中几种最简的日志配置方式。通常我们都会在项目的类路径下放置 logback.xml 或 logback-spring.xml 文件,而不是用 apprication.properties 的  loggin.aa.bb 等属性来配置日志。

日志同时输出到控制台和文件

依据 Spring Boot 加载 Logback  配置文件的顺序,我们可以在 classpath 下放 logback-spring.xml 或 logback.xml, 注意是 logback.xml 被优先选择。内容如下

设置 Spring 属性 logging.file 或系统属性 LOG_FILE 来指定日志输出文件名。或者用 Spring 属性  logging.path 或系统属性 LOG_PATH 指定 spring.log 的路径。

日志只输出到文件

用上面相同的方式指定日志文件的路径。

只输出到控制台

就更简单了,可以什么配置文件也不要,并且不要配置 logging.file 和  logging.path。而且效果与下面的配置是一样的。

小结:

  1. Spring Boot 基础的依赖于  starter  的项目默认采用 Slf4J + Logback 来输出日志
  2. 没有任何配置文件,也没有配置 Spring 属性 logging.file, logging.path 或系统属性 LOG_FILELOG_PATH 的情况下只会输出日志到控制台
  3. 没有任何配置文件,且有配置 #2 中任何一个属性的情况下将会同时输出日志到控制台与文件,文件以 10MB 大小滚动,不删除旧文件
  4. 不采用外部配置文件的情况下,可以用一些 Spring 属些来进行简单的日志配置,如 logging.pattern.file 等
  5. 可以设置 Spring 属性 logging.config 来指定外部 Logback 配置文件,Logback 默认用系统属性 logback.configurationFile 指定配置文件的方式在 Spring Boot 项目中不再生效
  6. 以上叙述的 Spring 属性,可用多种设置方式,如 Spring 属性 abc,有四种方式:1) application.properties 文件中的 abc=xxx, 2)环境变量 export abc=xxx, 3) 启动参数  --abc=xxx,4) 系统属性  -Dabc=xxx
  7. 类路径下的配置文件可以用 logback-spring.xml 或 logback.xml,但是 logback.xml 优先加载,并未遵循先特殊再普通的原则。(Logback 1.3.0 之后由于支持 Java 9,但是 Groovy 与 Java 9 未处理好关系,所以 Logback 1.3.0 不能支持 .groovy 的配置文件)
  8. 为更精细化的控制 Logback 的输出,我们通常都会在类路径下旋转 logback.xml 或 logback-spring.xml 配置文件,二选一了。我没发现这两个文件有什么不同。

链接:

  1. Configuring Logback with Spring Boot
  2. Spring Boot Logging
  3. USING LOGBACK WITH SPRING BOOT

本文链接 https://yanbin.blog/springboot-work-with-logback/, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments