SpringBoot 与 Logback 日志配置

栏目: Java · 发布时间: 6年前

内容简介:本文记录 SpringBoot 与 Logback 是如何工作的,即记录 SpringBoot 中 Logback  是怎么一步一步初始化的。用以测试的 SpringBoot 版本是 1.5.16, 而非最新的 SpringBoot 2。关于 SpringBoot 日志的官方文档在SpringBoot 默认使用 Slf4J + Logback 来记录日志,对于一个基本的依赖于的项目,它依赖了 spring-boot-starter-logging 组件,而该组件引入了以下几个依赖

本文记录 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-starter-logging 组件,而该组件引入了以下几个依赖

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

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

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

SpringBoot 应用默认日志输出

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

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.16.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
 
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
</dependencies>

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

application.properties 文件为空,并且没有任何的 logback 配置文件在 resources 目录中。

来个最简单的程序

@SpringBootApplication
public class Application {
    private static final Logger logger = LoggerFactory.getLogger(Application.class);
 
    public static void main(String[] args) {
        logger.info("aaa");
        SpringApplication.run(Application.class, args);
        logger.info("bbb");
    }
}

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

SpringBoot 与 Logback 日志配置

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

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

SpringBoot 是如何初始化 Logback 的

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

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

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

@Override
public void onApplicationEvent(ApplicationEvent event) {
    if (event instanceof ApplicationStartingEvent) {
        onApplicationStartingEvent((ApplicationStartingEvent) event);  // #1
    }
    else if (event instanceof ApplicationEnvironmentPreparedEvent) {
        onApplicationEnvironmentPreparedEvent(   // #2
            (ApplicationEnvironmentPreparedEvent) event);
    }
    else if (event instanceof ApplicationPreparedEvent) {
        onApplicationPreparedEvent((ApplicationPreparedEvent) event);  // #3
    }
......

#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 设定配置文件的方法

    if (StringUtils.hasText(System.getProperty(CONFIGURATION_FILE_PROPERTY))) {
        getLogger(LogbackLoggingSystem.class.getName()).warn(
            "Ignoring '" + CONFIGURATION_FILE_PROPERTY + "' system property. "
                + "Please use 'logging.config' instead.");
    }
    
  4. 如果检查了以上八个文件都不存在的话,就要调用 LogbackLoggingSystem.loadDefaults(initializationContext, logFile)  来配置默认的日志。

SpringBoot 没有任何日志配置文件时配置

这块其实是上面步骤 #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.filelogging.path ,SpringBoot 都会初始化 consoleAppender, 并且默认的输出模式是

private static final String CONSOLE_LOG_PATTERN = "%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} "
        + "%clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} "
        + "%clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} "
        + "%clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}";

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

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

private static final String FILE_LOG_PATTERN = "%d{yyyy-MM-dd HH:mm:ss.SSS} "
    + "${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}";

该模式可以用 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 的日志输出级别。

简单的 SpringBoot 日志文件配置

理解了 SpringBoot 是如何初始化 Logback 日志配置后,我们来看一下项目中几种最简的日志配置方式。

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

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

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/base.xml"/>
    <logger name="org.springframework.web" level="DEBUG"/>
</configuration>

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

日志只输出到文件

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/defaults.xml" />
    <property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
    <include resource="org/springframework/boot/logging/logback/file-appender.xml" />
    <root level="INFO">
        <appender-ref ref="FILE" />
    </root>
</configuration>

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

只输出到控制台

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

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/defaults.xml" />
    <include resource="org/springframework/boot/logging/logback/console-appender.xml" />
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
    </root>
</configuration>

小结:

  1. SpringBoot 基础的依赖于  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  指定配置文件的方式
  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  配置文件,二选一了。我没发现这两个文件有什么不同。

以上所述就是小编给大家介绍的《SpringBoot 与 Logback 日志配置》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

HTTP Essentials

HTTP Essentials

Stephen A. Thomas、Stephen Thomas / Wiley / 2001-03-08 / USD 34.99

The first complete reference guide to the essential Web protocol As applications and services converge and Web technologies not only assume HTTP but require developers to manipulate it, it is be......一起来看看 《HTTP Essentials》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具