文章目录
- Spring Boot 对日志框架的封装
- SLF4J + Logback快速入门
- 调试模式
- Logback 扩展
- SLF4J + Log4J2
Spring Boot 对日志框架的封装
我们知道在日志方面,SpringBoot默认是使用的SLF4J+LogBack的形式。我们来看看它使用的日志实现框架LogBack,其在 DefaultLogbackConfiguration 类中,定义了文件日志格式如下:
// DefaultLogbackConfiguration.java
private static final String FILE_LOG_PATTERN = "%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} "
+ "${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}";
日志输出示例如下:
2023-07-10 21:42:58.925 INFO 7000 --- [ main] com.zyb.MyApplication : No active profile set, falling back to default profiles: default
2023-07-10 21:42:59.473 INFO 7000 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2023-07-10 21:42:59.479 INFO 7000 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
文件日志格式解释:
%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}
日期和时间:毫秒精度。${LOG_LEVEL_PATTERN:-%5p}
日志级别:ERROR、WARN、INFO、DEBUG 或 TRACE。${PID:- }
进程 ID。---
分隔符:用于区分实际日志内容的开始。[%t]
线程名称:在方括号中(可能会截断控制台输出)。%-40.40logger{39}
日志记录器名称:这通常是源类名称(通常为缩写)。%m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}
日志内容。
同时,允许通过 logging.
配置项来,进行自定义设置。例如说:
自定义日志格式
logging.pattern.file
:文件的日志格式。logging.pattern.console
:控制台的日志格式。logging.pattern.dateformat
:日期和时间。logging.pattern.level
:日志级别。logging.pattern.pid
: 进程 ID。logging.exception-conversion-word
:记录异常时使用的转换字
自定义日志文件
logging.file.max-history
:日志文件要保留的归档的最大天数。logging.file.max-size
:日志文件的最大大小。logging.file
:日志文件名。logging.path
:日志文件路径。
自定义日志级别
logging.level.*
:日志等级,通过使用 logging.level.<logger-name>=<level>
来设置。例如说:
logging.level.root=WARN
logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate=ERROR
最主要的是我们可以使用logging.config
定义日志框架使用的配置文件地址。因为根据不同的日志实现框架,Spring Boot 按如下“约定规则”加载配置文件:
- Logback :对应 logback-spring.xml、logback-spring.groovy、logback.xml、logback.groovy 配置文件。
- Log4j2 :对应 log4j2-spring.xml、log4j2.xml 配置文件。
- JUL :对应 logging.properties 配置文件。
这里的配置文件名根据SpringBoot的版本问题可能不同,例如在SpringBoot2.5.0版本中,logback-spring.xml不管用,但是logback.xml是可行的。
虽然 logging.
自定义配置项很多,但是一般情况下,我们只使用 logging.level.*
配置项,设置不同 Logger 的日志级别。也就是说我们主要的配置还是写在配置文件中。
目前,Spring Boot 内置了两个日志相关的 Starter :
spring-boot-starter-logging
:使用 SLF4J + Logback 的组合。spring-boot-starter-log4j2
:使用 SLF4J + Log4j2 的组合。
接下来我们来进行 Spring Boot 集成日志功能的快速入门,使用 SLF4J + Logback 的组合。主要功能包括:
- 控制台打印日志。
- 控制台颜色输出。
- 日志文件打印日志。
- 自定义日志级别。
SLF4J + Logback快速入门
依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
spring-boot-starter-web 包含了 spring-boot-starter ,而 spring-boot-starter 又已经包含了 spring-boot-starter-logging
配置文件
在 application.yml 中,添加日志相关配置,如下:
spring:
application:
name: just_do_it # 应用名
logging:
# 日志文件配置
file:
# path: /Users/yunai/logs/ # 日志文件路径。
name: ./logs/${spring.application.name}.log # 日志文件名。
max-history: 7 # 日志文件要保留的归档的最大天数。默认为 7 天。
max-size: 10MB # 日志文件的最大大小。默认为 10MB 。
# 日志级别
level:
com:
zyb:
controller:
LoggerController: DEBUG
解释一下这个配置文件:
①在 logging.file.*
配置项下,设置 Spring Boot 日志文件
默认情况下,Spring Boot 日志只会打印到控制台。所以需要通过 logging.file.path 或 logging.file.name 配置项来设置。不过要注意,这两者是二选一,并不是共同作用。
- logging.file.name :日志文件全路径名。可以是相对路径,也可以是绝对路径。这里,我们设置为 “/Users/yunai/logs/${spring.application.name}.log” ,绝对路径。
- logging.file.path :日志文件目录。会在该目录下,创建 spring.log 日志文件。例如说:/Users/yunai/logs/ 。
- 上述两者都配置的情况下,以 logging.file.name 配置项为准。
②在 logging.level.*
配置项,设置自定义的日志级别。
Spring Boot 定义的日志级别为 TRACE、DEBUG、INFO、WARN、ERROR、FATAL、OFF。
默认情况下,控制台和日志文件的日志级别 INFO。即,INFO、WARN、ERROR 级别的日志,都会记录到控制台和日志文件中。
可以通过使用 logging.level.<logger-name>= 配置项,自定义 Logger 对应的日志级别。这里,我们设置了名字为 “cn.iocoder.springboot.lab37.loggingdemo.controller” 的 Logger 的日志级别,为 DEBUG 。
如果我们的控制台支持 ANSI ,则可以使用颜色输出,来提高可读性。通过 spring.output.ansi.enabled 配置项,设置 ANSI 功能的状态,有三种选项:
- ALWAYS :启用 ANSI 颜色的输出。
- NEVER :禁用 ANSI 颜色的输出。
- DETECT :自动检测控制台是否支持 ANSI 功能。如果支持则进行开启,否则则进行禁用。默认情况下,使用 DETECT 这种选项。
默认情况下,Spring Boot 已经配置好颜色输出的日志格式,我们并不需要做自定义,所以这里也就不多做介绍了。我们只需要知道,不同日志级别,对应不同的颜色的映射关系即可:
接下来我们写一个Controller测试一下:
@RestController
@RequestMapping("/log")
public class LoggerController {
private Logger logger = LoggerFactory.getLogger(getClass());
@GetMapping("/debug")
public void debug() {
logger.debug("debug");
}
@GetMapping("/info")
public void info() {
logger.info("info");
}
@GetMapping("/error")
public void error() {
logger.error("error");
}
}
我们文件输出日志也有:
调试模式
默认情况下,Spring Boot 只会记录 ERROR、WARN 和 INFO 级别的日志。可能有时我们启动 Spring Boot 失败时,需要通过启动 Spring Boot 调试模式:
- 让核心 Logger(内嵌容器、Hibernate 和 Spring Boot 等等)打印 DEBUG 级别的日志,方便排查原因
- 应用中的其它 Logger 还是保持原有的日志级别。
目前,有两种方式开启 Spring Boot 应用的调试模式:
- 通过启动参数带上 --debug 标识,进行开启。例如说 $ java -jar myapp.jar --debug。
- 通过配置文件的 debug = true 配置项,进行开启。
spring:
application:
name: just_do_it # 应用名
logging:
# 日志文件配置
file:
name: ./logs/${spring.application.name}.log # 日志文件名。
max-history: 7 # 日志文件要保留的归档的最大天数。默认为 7 天。
max-size: 10MB # 日志文件的最大大小。默认为 10MB 。
# 调试模式
debug: true
Logback 扩展
Spring Boot 额外提供了 Logback 的两个 XML 标签的扩展。
① 拓展一:<springProfile /> 标签
通过 <springProfile /> 标签,设置标签内的 Logback 的配置,需要符合指定的 Spring Profile 才可以生效。
<springProfile name="staging">
<!-- configuration to be enabled when the "staging" profile is active -->
</springProfile>
<springProfile name="dev | staging">
<!-- configuration to be enabled when the "dev" or "staging" profiles are active -->
</springProfile>
<springProfile name="!production">
<!-- configuration to be enabled when the "production" profile is not active -->
</springProfile>
② 拓展二:<springProperty /> 标签
通过 <springProperty /> 标签,可以从 Spring Boot 配置文件中读取配置项。示例如下:
<!-- 从 Spring Boot 配置文件中,读取 spring.application.name 应用名 -->
<springProperty name="applicationName" scope="context" source="spring.application.name" />
<!-- 日志文件的路径 -->
<property name="LOG_FILE" value="/Users/yunai/logs/${applicationName}.log"/>
接下来我们进行演示
依赖不变,application.yml中只保留一个应用名的配置即可:
spring:
application:
name: just_do_it
然后开始编写我们的日志配置文件;
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- <1> -->
<!-- 引入 Spring Boot 默认的 logback XML 配置文件 -->
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<!-- <2.1> -->
<!-- 控制台 Appender -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<!-- 日志的格式化 -->
<encoder>
<!--直接使用的默认格式-->
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
<!-- 2.2 -->
<!-- 从 Spring Boot 配置文件中,读取 spring.application.name 应用名 -->
<springProperty name="applicationName" scope="context" source="spring.application.name" />
<!-- 日志文件的路径 -->
<property name="LOG_FILE" value="/Users/yunai/logs/${applicationName}.log"/>
<!-- 滚动日志文件 Appender -->
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--指定了日志文件的输出路径-->
<file>${LOG_FILE}</file>
<!--滚动策略,基于时间 + 大小的分包策略 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--通过指定压缩文件名称,来确定分割文件方式-->
<fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz</fileNamePattern>
<maxHistory>7</maxHistory>
<maxFileSize>10MB</maxFileSize>
</rollingPolicy>
<!-- 日志的格式化 -->
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
<!-- 3.1 -->
<!-- 测试环境,独有的配置 -->
<springProfile name="dev">
<!-- 设置 Appender -->
<root level="INFO">
<appender-ref ref="console"/>
</root>
<!-- 设置 "cn.iocoder.springboot.lab37.loggingdemo" 的 Logger 的日志级别为 DEBUG -->
<logger name="cn.iocoder.springboot.lab37.loggingdemo" level="DEBUG"/>
</springProfile>
<!-- 3.2 -->
<!-- 生产环境,独有的配置 -->
<springProfile name="prod">
<!-- 设置 Appender -->
<root level="INFO">
<appender-ref ref="console"/>
<appender-ref ref="file"/>
</root>
</springProfile>
</configuration>
如果对LogBack配置文件不是很熟悉,可以看我的上一篇文章:
一文弄懂Java日志框架
然后我们编写一个启动类:
@SpringBootApplication
public class MyApplication {
private static final Logger LOGGER = LoggerFactory.getLogger(MyApplication.class);
public static void main(String[] args) {
SpringApplication.run(MyApplication.class,args);
LOGGER.debug("在开发环境下可以看到");
}
}
通过 IDEA 的 Active profiles 选项,设置启动的 Spring Boot 应用的 Profile 。如下图所示:
运行结果如下:
而如果是在生产环境下,我们是看不到这句话的。
SLF4J + Log4J2
引入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!--排除logback-->
<exclusion>
<artifactId>spring-boot-starter-logging</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- 添加log4j2 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
在 application.yml 中,仅添加应用名的配置即可,如下:
spring:
application:
name: just_do_it
然后我们在 log4j2-spring.xml 中,添加 Log4j2 配置,如下:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Properties>
<Property name="PID">????</Property>
<Property name="LOG_EXCEPTION_CONVERSION_WORD">%xwEx</Property>
<Property name="LOG_LEVEL_PATTERN">%5p</Property>
<Property name="LOG_DATEFORMAT_PATTERN">yyyy-MM-dd HH:mm:ss.SSS</Property>
<!-- 1.1 -->
<Property name="FILE_LOG_BASE_PATH">/Users/yunai/logs</Property>
<Property name="APPLICATION_NAME">demo-application</Property>
<!-- 1.2 -->
<!-- 控制台的日志格式 -->
<Property name="CONSOLE_LOG_PATTERN">%clr{%d{${LOG_DATEFORMAT_PATTERN}}}{faint} %clr{${LOG_LEVEL_PATTERN}} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property>
<!-- 1.3 -->
<!-- 日志文件的日志格式 -->
<Property name="FILE_LOG_PATTERN">%d{${LOG_DATEFORMAT_PATTERN}} ${LOG_LEVEL_PATTERN} ${sys:PID} --- [%t] %-40.40c{1.} : %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property>
</Properties>
<Appenders>
<!-- 2.1 -->
<!-- 控制台的 Appender -->
<Console name="Console" target="SYSTEM_OUT" follow="true">
<PatternLayout pattern="${sys:CONSOLE_LOG_PATTERN}" />
</Console>
<!-- 2.2 -->
<!-- 日志文件的 Appender -->
<RollingFile name="File" fileName="${FILE_LOG_BASE_PATH}/${sys:APPLICATION_NAME}"
filePattern="${FILE_LOG_BASE_PATH}/${sys:APPLICATION_NAME}-%d{yyyy-MM-dd-HH}-%i.log.gz">
<!-- 日志的格式化 -->
<PatternLayout>
<Pattern>${sys:FILE_LOG_PATTERN}</Pattern>
</PatternLayout>
<!--滚动策略,基于时间 + 大小的分包策略 -->
<Policies>
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<!-- 3.1 -->
<!-- 常用组件的 Logger 的日志级别 -->
<Logger name="org.apache.catalina.startup.DigesterFactory" level="error" />
<Logger name="org.apache.catalina.util.LifecycleBase" level="error" />
<Logger name="org.apache.coyote.http11.Http11NioProtocol" level="warn" />
<logger name="org.apache.sshd.common.util.SecurityUtils" level="warn"/>
<Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="warn" />
<Logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="error" />
<Logger name="org.hibernate.validator.internal.util.Version" level="warn" />
<logger name="org.springframework.boot.actuate.endpoint.jmx" level="warn"/>
<!-- 3.2 -->
<!-- 自定义的 Logger 的日志级别 -->
<logger name="com.zyb" level="debug"/>
<!-- 3.3 -->
<!-- 设置 Appender ,同时 ROOT 的日志级别为 INFO -->
<Root level="info">
<AppenderRef ref="Console" />
<AppenderRef ref="File" />
</Root>
</Loggers>
</Configuration>
如果对log4j2的配置文件不是很熟悉,同样可以看我的上一篇文章:
一文弄懂Java日志框架
- 参考 Spring Boot 默认的 log4j2 XML 配置文件 log4j2-file.xml,进行修改。
- <1.1> 处,定义日志文件的基础路径和文件名。因为 Spring Boot 并未提供 Log4j2 拓展,无法像「7. Logback 拓展」一样直接读取 Spring Boot 配置文件,所以这里我们只能直接定义。
- <1.2> 处,定义了控制台的日志格式。
- <1.3> 处,定义了日志文件的日志格式。
- <2.1> 处,配置控制台的 Appender 。
- <2.2> 处,配置日志文件的 Appender。
- < 3.1> 处,设置常用组件的 Logger 的日志级别。
- < 3.2> 处,自定义的 Logger 的日志级别。这里,我们设置名字为 “cn.iocoder.springboot.lab37.loggingdemo” 的 Logger 的日志级别为 DEBUG。
- < 3.3> 处,设置 Root 的 Appender 为控制台和日志文件,日志级别为 INFO。
测试方式与前面的例子一样,这里不多赘述。