前言
市面上的日志框架
日志抽象层 | 日志实现 |
---|---|
JCL(Jakarta Commons Logging)、SLF4J(Simple Logging Facade For Java)、JBoss-Logging | Log4j、JUL(java.util.logging)、Log4j2、Logback |
日志抽象层
JBoss-Logging 不适合平常开发使用。JCL 最后一次更新版本时间为 2014 年,有些过时。所以 SpringBoot 选中的日志抽象层为 SLF4J。
日志实现
日志实现 LogBack、Log4j 和抽象层 SLF4J 的作者是同一个人,且 LogBack 是后期针对 Log4j 的升级版,而 Log4j2 是 Apache 旗下开发的日志框架。所以 SpringBoot 的日志实现使用的是 Logback。
SLF4J 的简单使用
导入 slf4j 和 logback 的依赖,使用如下。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(HelloWorld.class);
logger.info("Hello World");
}
}
原理图
统一使用SLF4J
如何让系统中所有的日志都统一到 sfl4j?
将系统中其它日志框架排除。
用中间包替换原有的日志框架。
导入 SLF4J 的其它实现。
上图描述的是统一使用 SLF4J 需要剔除哪些包以及需要导入哪些替换的中间包。
SpringBoot 的日志结构
我们已经知道一个基本的 SpringBoot Web 项目会包含如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
而 spring-boot-starter-web
又依赖于 spring-boot-stater
,spring-boot-stater
中就包含日志相关依赖,如下:
总结
SpringBoot 底层也是使用 SLF4j+LogBack 的方式进行日志记录。
SpringBoot 使用中间包将其它的日志包都间接替换成了 SLF4J,而 SLF4J 的实现为 LogBack,所以 call 其它日志包 api 的时候实际上调用的是 LogBack,统一了日志实现。
如果我们要引入其它框架,一定要把这个框架的默认日志依赖排除。
SpringBoot日 志使用
默认的日志级别
现有如下示例:
package com.springboot.logging;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class LoggingApplicationTests {
@Test
public void test() {
Logger logger = LoggerFactory.getLogger(this.getClass());
// 如下日志级别由低到高
// 指定一个日志级别,就会在指定的级别之后的高级别生效
logger.trace("trace info");
logger.debug("debug info");
logger.info("info info");
logger.warn("warn info");
logger.error("error info");
}
}
运行该测试代码,输出如下:
2018-03-16 17:08:34.913 INFO 16228 --- [ main] c.s.logging.LoggingApplicationTests : info info
2018-03-16 17:08:34.913 WARN 16228 --- [ main] c.s.logging.LoggingApplicationTests : warn info
2018-03-16 17:08:34.913 ERROR 16228 --- [ main] c.s.logging.LoggingApplicationTests : error info
得出结论,SpringBoot 程序中我们使用的日志输出默认是 info 级别。
我们可以通过配置文件修改指定包下的日志输出级别,例:
logging.level.com.springboot.logging=trace # 指定 com.springboot.logging 包下的日志输出级别为 trace
此时运行上面测试程序,输出内容为:
2018-03-16 17:13:06.451 TRACE 2836 --- [ main] c.s.logging.LoggingApplicationTests : trace info
2018-03-16 17:13:06.451 DEBUG 2836 --- [ main] c.s.logging.LoggingApplicationTests : debug info
2018-03-16 17:13:06.452 INFO 2836 --- [ main] c.s.logging.LoggingApplicationTests : info info
2018-03-16 17:13:06.452 WARN 2836 --- [ main] c.s.logging.LoggingApplicationTests : warn info
2018-03-16 17:13:06.452 ERROR 2836 --- [ main] c.s.logging.LoggingApplicationTests : error info
如果需要直接指定整个项目日志输出级别,那么只需要把包路径位置替换为 root
,如下:
logging.level.root=trace
输出日志到文件
日志不仅可输出到控制台,还可以配置输出到指定文件,如下:
logging.file=springboot.log
此时项目中的日志就会输出到项目根路径下的 springboot.log
文件中。
上面这种方式是使用相对项目路径,也可以使用完整的绝对路径,如下:
logging.file=D://springboot.log
也可以只指定日志存放目录:
logging.path=/springboot/log
此时就会在项目所在磁盘的根目录的 /springboot/log
文件夹下生成一个 spring.log
文件。
控制日志输出格式
我们可以在配置文件中修改在控制台的日志输出格式:
logging.path=/log
# 控制台日志输出格式
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} ---> %msg%n
# 文件中日志输出格式
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} ---> %msg%n
# %d : 日期时间
# %thread : 线程名
# %-5level : 级别,从左显示 5 个字符宽度
# %logger{50} : logger 名称最长为 50 个字符,否则按照句点分割
# %msg : 日志消息
# %n : 换行符
此时运行上面测试程序,输出结果如下:
2019-03-16 17:41:23.432 [main] INFO com.springboot.logging.LoggingApplicationTests ---> Started LoggingApplicationTests in 2.355 seconds (JVM running for 3.052)
2019-03-16 17:41:23.486 [main] INFO com.springboot.logging.LoggingApplicationTests ---> info info
2019-03-16 17:41:23.486 [main] WARN com.springboot.logging.LoggingApplicationTests ---> warn info
2019-03-16 17:41:23.486 [main] ERROR com.springboot.logging.LoggingApplicationTests ---> error info
配置文件
SpringBoot 的日志功能也可以单独使用一个配置文件,要使用自定义的日志配置文件,只需要在类路径下放上对应日志框架自己的配置文件即可,SpringBoot 就不使用它的默认配置了。
而对应日志框架的配置文件命名也是有限制的,如下:
日志框架 | 可使用配置文件名 |
---|---|
Logback | logback-spring.xml、logback-spring.groovy、logback.xml、logback.groovy |
log4j2 | log4j2-spring.xml、log4j2.xml |
JDK(Java Util Logging) | logging.properties |
我们此时使用的是 SpringBoot 默认使用的 Logback,所以可以在类路径下放入 logback.xml
:
<!-- logback.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="log"/>
<!--定义日志文件名称-->
<property name="FILE_NAME" value="testLog"/>
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--
格式化输出:
%d 表示日期
%thread 表示线程名
%-5level 级别从左显示 5 个字符宽度
%msg 日志消息
%n 是换行符
-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/${FILE_NAME}.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d 表示日期,%thread 表示线程名,%-5level 表示级别从左显示 5 个字符宽度 %msg 表示日志消息,%n 是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<!-- 日志输出级别 -->
<root level="INFO">
<appender-ref ref="STDOUT"/> <!--启用控制台输出-->
<appender-ref ref="FILE"/> <!--启用文件输出-->
</root>
</configuration>
此时 logback.xml
就可以直接被日志框架读取配置。
高级功能
在 SpringBoot 项目中,SpringBoot 是推荐我们使用的配置文件名为 logback-spring.xml
的配置文件,因为使用 logback-spring.xml
文件名时该配置文件就不是直接被日志框架读取,而是先被 SpringBoot 读取,此时 SpringBoot 就给我们提供了日志框架以外的功能,可以定制不同 Profile 环境下来生效日志的不同配置,使用如下:
<root level="INFO">
<!--仅在非 prod 环境下启用控制台输出-->
<springProfile name="!prod">
<appender-ref ref="STDOUT"/> <!--启用控制台输出-->
</springProfile>
<!--仅在 prod 环境下启用文件输出-->
<springProfile name="prod">
<appender-ref ref="FILE"/> <!--启用文件输出-->
</springProfile>
</root>
评论区