Spring Boot 日志配置

1、概览

本文将带你了解 Spring Boot 应用中的日志配置。

2、初始设置

通过 Spring Initializr 初始化一个 Spring Boot 应用:

创建唯一的类 LoggingController

@RestController
public class LoggingController {

    Logger logger = LoggerFactory.getLogger(LoggingController.class);

    @RequestMapping("/")
    public String index() {
        logger.trace("A TRACE Message");
        logger.debug("A DEBUG Message");
        logger.info("An INFO Message");
        logger.warn("A WARN Message");
        logger.error("An ERROR Message");

        return "Howdy! Check out the Logs to see the output...";
    }
}

启动应用后,只需访问 http://localhost:8080/,就能触发这些日志输出。

3、日志零配置

就日志记录而言,Spring Boot 唯一必须的依赖是 Apache Commons Logging。它是由 Spring 的 spring-jcl 模块提供的。

如果使用的是 Spring Boot Starter(几乎总是使用 Spring Boot Starter),就根本不用担心导入 spring-jcl 的问题。这是因为每个 Starter,比如 spring-boot-starter-web,都依赖于 spring-boot-starter-logging,它已经导入了 spring-jcl

3.1、默认使用 Logback

使用 Starter,默认使用 Logback 进行日志记录。

Spring Boot 使用 Pattern 和 ANSI 颜色对其进行了预配置,使标准输出更易读。

运行应用,并访问 http://localhost:8080/ 页面,你可以看到输出的日志如下:

logback default logging|1024x562

你可以看到,logger 的默认日志级别预设为 INFO,这意味着 TRACEDEBUG 消息不可见。

可以在命令行中传递 -debug-trace 参数,以在不更改配置的情况下修改日志级别:

java -jar target/spring-boot-logging-0.0.1-SNAPSHOT.jar --trace

3.2、日志级别

可以通过环境变量进行更细粒度的日志级别设置。

首先,可以在 VM Option(虚拟机选项)中设置日志级别:

-Dlogging.level.org.springframework=TRACE 
-Dlogging.level.com.baeldung=TRACE

另外,如果使用 Maven,也可以通过命令行定义日志级别:

mvn spring-boot:run 
  -Dspring-boot.run.arguments=--logging.level.org.springframework=TRACE,--logging.level.com.baeldung=TRACE

使用 Gradle 时,可以通过命令行传递日志设置。这需要设置 bootRun Task。

完成后,就可以运行应用了:

./gradlew bootRun -Pargs=--logging.level.org.springframework=TRACE,--logging.level.com.baeldung=TRACE

如果想永久更改日志级别,可以在 application.properties 文件中进行更改,如下:

logging.level.root=WARN
logging.level.com.baeldung=TRACE

最后,可以使用日志框架的配置文件来永久更改日志级别。

如上所述,Spring Boot Starter 默认使用 Logback。如下是 Logback 配置文件的一个片段,其中为两个不同的包设置了日志级别:

<logger name="org.springframework" level="INFO" />
<logger name="com.baeldung" level="INFO" />

注意,如果通过上述不同选项多次定义包的日志级别,但日志级别各不相同,那么将使用最低级别。

因此,如果同时使用 Logback、Spring Boot 和环境变量设置日志级别,日志级别将是 TRACE,因为它级别是最低的。

4、Logback 日志配置

尽管默认配置很有用(例如,在概念验证或快速实验期间可以立即开始),但它很可能不足以满足我们日常的需求。

来看看如何在 Logback 配置中加入不同的颜色和日志 Pattern,对 console(控制台)和 file(文件)输出进行单独规范,并采用适当的滚动策略来避免生成巨大的日志文件。

首先,应该找到一种解决方案,可以单独处日志设置,而不是污染 application.properties,后者通常用于许多其他应用设置。

当 classpath 下具有下列配置文件之一时,Spring Boot 将自动加载该文件,而不是默认配置:

  • logback-spring.xml
  • logback.xml
  • logback-spring.groovy
  • logback.groovy

Spring 建议 尽可能使用 -spring 后缀来命名日志配置文件。

示例 logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <property name="LOGS" value="./logs" />

    <appender name="Console"
        class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>
                %black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable
            </Pattern>
        </layout>
    </appender>

    <appender name="RollingFile"
        class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOGS}/spring-boot-logger.log</file>
        <encoder
            class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
        </encoder>

        <rollingPolicy
            class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每日滚动,当文件达到 10 Mb 时 -->
            <fileNamePattern>${LOGS}/archived/spring-boot-logger-%d{yyyy-MM-dd}.%i.log
            </fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy
                class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>10MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
    </appender>
    
    <!-- INFO 级别 -->
    <root level="info">
        <appender-ref ref="RollingFile" />
        <appender-ref ref="Console" />
    </root>

    <!-- L"com.baeldung*" 设置为 TRACE 级别 -->
    <logger name="com.baeldung" level="trace" additivity="false">
        <appender-ref ref="RollingFile" />
        <appender-ref ref="Console" />
    </logger>

</configuration>

运行应用,输出如下:

logback custom logging|1024x576

现在可以看到 TRACEDEBUG 日志,而且整个 Console Pattern(控制台模式)在文字和色调上都与以前不同。

它还会把日志输出到当前路径下的 /logs 文件夹中,并通过滚动策略将其存档。

5、Log4j2 日志配置

Spring Boot 可以无缝切换到 log4j2

首先将 Logback 从依赖中排除,再添加 log4j2 依赖。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

在 classpath 下定义配置件,文件名如下:

  • log4j2-spring.xml
  • log4j2.xml

代码不需要任何改动。

示例 log4j2-spring.xml 如下:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout
                pattern="%style{%d{ISO8601}}{black} %highlight{%-5level }[%style{%t}{bright,blue}] %style{%C{1.}}{bright,yellow}: %msg%n%throwable" />
        </Console>

        <RollingFile name="RollingFile"
            fileName="./logs/spring-boot-logger-log4j2.log"
            filePattern="./logs/${date:yyyy-MM}/spring-boot-logger-log4j2-%d{-dd-MMMM-yyyy}-%i.log.gz">
            <PatternLayout>
                <pattern>%d %p %C{1.} [%t] %m%n</pattern>
            </PatternLayout>
            <Policies>
                <!-- 滚动存储 -->
                <OnStartupTriggeringPolicy />
                <SizeBasedTriggeringPolicy
                    size="10 MB" />
                <TimeBasedTriggeringPolicy />
            </Policies>
        </RollingFile>
    </Appenders>

    <Loggers>
        <!-- ROOT 日志级别 -->
        <Root level="info">
            <AppenderRef ref="Console" />
            <AppenderRef ref="RollingFile" />
        </Root>

        <!-- "com.baeldung*" 日志级别 -->
        <Logger name="com.baeldung" level="trace"></Logger>
    </Loggers>

</Configuration>

运行应用,输出如下:

log4j2 custom logging|1024x562

你可以看到,输出结果与 Logback 输出结果截然不同,这证明 Log4j2 配置生效。

除 XML 配置外,Log4j2 还允许使用 YAMLJSON 配置,详情见 此处

6、直接使用 Log4j2

还可以直接使用 Log4j2,而无需通过 SLF4J。

直接使用 Log4j2 原生类即可:

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
// [...]
Logger logger = LogManager.getLogger(LoggingController.class);

无需对标准 Log4j2 Spring Boot 配置进行任何其他修改。

现在,可以利用 Log4j2 的全新功能,而不必拘泥于旧的 SLF4J 接口。但是,也被这个实现所束缚,当切换到另一个日志框架时,需要重写代码。

7、Lombok

在目前所示的示例中,必须在类中声明一个 Logger 实例。

可以使用 Lombok 引入的各种注解来避免这种烦人的模板代码。

首先,添加 Lombok 依赖:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.30</version>
    <scope>provided</scope>
</dependency>

7.1、@Slf4j 和 @CommonsLog

SLF4J 和 Apache Commons 日志 API 使我们能够在不影响代码的情况下灵活地更改日志框架。

可以使用 Lombok 的 @Slf4j@CommonsLog 注解将正确的 Logger 实例添加到类中:org.slf4j.Logger 用于 SLF4J,org.apache.commons.logging.Log 用于 Apache Commons Logging。

示例如下:

@RestController
@Slf4j  // 使用 @Slf4j 
public class LombokLoggingController {
 
    @RequestMapping("/lombok")
    public String index() {

        // log 变量是 Lombok 在编译时生成的,可以直接使用

        log.trace("A TRACE Message");
        log.debug("A DEBUG Message");
        log.info("An INFO Message");
        log.warn("A WARN Message");
        log.error("An ERROR Message");
 
        return "Howdy! Check out the Logs to see the output...";
    }
}

如上,@Slf4j 注解会自动添加一个名为 log 的字段,即 Logger 实例。

@CommonsLog 替换注解 @Slf4j 时,效果类似。

7.2、@Log4j2

可以使用 @Log4j2 注解来直接使用 Log4j2,如下:

@RestController
@Log4j2 // @Log4j2 注解
public class LombokLoggingController {
 
    @RequestMapping("/lombok")
    public String index() {
        log.trace("A TRACE Message");
        log.debug("A DEBUG Message");
        log.info("An INFO Message");
        log.warn("A WARN Message");
        log.error("An ERROR Message");
 
        return "Howdy! Check out the Logs to see the output...";
    }
}   

8、Java Util Logging

Spring Boot 也支持通过 logging.properties 配置 JDK 日志(Java Util Logging)。

但,并不推荐,Java Util Logging 存在已知的类加载问题。

使用 Spring 4 时,通常需要在 pom.xml 中手动排除 commons-logging,以避免日志库之间的潜在冲突。Spring 5 则会自动处理,因此在使用 Spring Boot 2 时不需要做任何事情。

9、Windows 环境下的 JANSI

基于 Unix 的操作系统(如 Linux 和 Mac OS X)默认支持 ANSI 颜色代码,但在 Windows 控制台上,一切都是单色的。

Windows 可以通过一个名为 JANSI 的库获取 ANSI 颜色(需要注意,可能存在类加载缺陷问题)。

Logback 配置中导入并激活它,如下所示:

<configuration debug="true">
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <withJansi>true</withJansi>
        <encoder>
            <pattern>[%thread] %highlight(%-5level) %cyan(%logger{15}) - %msg %n</pattern>
        </encoder>
    </appender>
    <!-- 其他配置 -->
</configuration>

Log4j2

许多平台都支持 ANSI 转义序列,但 Windows 默认不支持。要启用 ANSI 支持,请将 Jansi jar 添加到应用,并将属性 log4j.skipJansi 设置为 false。这将允许 Log4j 在写入控制台时使用 Jansi 添加 ANSI 转义码。

注:在 Log4j 2.10 之前,Jansi 是默认启用的。Jansi 需要 native 代码,这意味着 Jansi 只能由单个类加载器加载。对于 Web 应用,这意味着 Jansi jar 必须位于 Web 容器的 classpath 中。为避免给 Web 应用程序带来问题,从 Log4j 2.10 开始,Log4j 不再在没有明确配置的情况下自动尝试加载 Jansi。

其他的一些注意点:

  • layout 文档页的 highlight{pattern}{style} 部分包含有用的 Log4j2 JANSI 信息。
  • 虽然 JANSI 可以为输出着色,但 Spring Boot 的 Banner 将保持单色。

10、总结

本文介绍了如何在 Spring Boot 中配置使用 Logback 和 Log4j2 日志库。还介绍了如何使用 Lombok 来减少模板代码以及如何在 Windwos 下通过 JANSI 库输出彩色日志。


Ref:https://www.baeldung.com/spring-boot-logging