一. 日志框架介绍
在项目的开发中,日志是必不可少的一个记录事件的组件,不管是记录运行情况还是追踪线上问题,都离不开对日志的分析,所以也会相应的在项目中实现和构建我们所需要的日志框架。
而市面上常见的日志框架有很多,比如: JCL 、 SLF4J 、 Jboss-logging 、 jUL 、 log4j 、 log4j2 、 logback 等等,我们该如何选择呢?
通常情况下,日志是由一个抽象层 + 实现层的组合来搭建的。
Spring 框架选择使用了 JCL 作为默认日志输出。而 Spring Boot 默认选择了 SLF4J 结合 LogBack
二. SLF4J 的使用
在开发的时候不应该直接使用日志实现类,应该使用日志的抽象层。具体参考 SLF4J 官方 。
SLF4J 官方给出了简单示例。
首先要为系统导入 SLF4J 的 jar .
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld {
public static void main(String[] args) {
elloWorld.class);
logger.info("Hello World");
}
}
下图是 SLF4J 结合各种日志框架的官方示例,从图中可以清晰的看出 SLF4J API 永远作为日志的门面,直接应用与应用程序中。
注意 : 由于每一个日志的实现框架都有自己的配置文件,所以在使用 SLF4j 之后,配置文件还是要使用实现日志框架的配置文件。
三. 统一日志框架的使用
遗留问题: A 项目( slf4J + logback ) : Spring ( commons logging )、 Hibernate ( jboss-logging )、mybatis....
一般情况下,在项目中存在着各种不同的第三方 jar ,且它们的日志选择也可能不尽相同,显然这样是不利于我们使用的,那么如果我们想为项目设置统一的日志框架该怎么办呢?
在 SLF4J 官方 ,也给了我们参考的例子
从图中我们得到一种统一日志框架使用的方式,可以使用一种和要替换的日志框架类完全一样的 jar 进行替换,这样不至于原来的第三方 jar 报错,而这个替换的 jar 其实使用了 SLF4J API. 这样项目中的日 志就都可以通过 SLF4J API 结合自己选择的框架进行日志输出。
统一日志框架使用步骤归纳如下 :
1. 排除系统中的其他日志框架。
2. 使用中间包替换要替换的日志框架。
3. 导入我们选择的 SLF4J 实现。
四. Spring Boot 的日志关系
(一)排除其他日志框架
根据上面总结的要统一日志框架的使用,第一步要排除其他的日志框架,在 Spring Boot 的 Maven 依赖里可以清楚的看到 Spring Boot 排除了其他日志框架。
我们自行排除依赖时也只需要按照图中的方式就好了。
(二)统一框架引入替换包
Spring Boot 是使用了 SLF4J+logback 的日志框架组合,查看 Spring Boot 项目的 Maven 依赖关系可以看到 Spring Boot 的核心启动器 spring-boot-starter 引入了 spring-boot-starter-logging.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<version>2.4.0.RELEASE</version>
</dependency>
而 spring-boot-starter-logging 的 Maven 依赖主要引入了 logback-classic ( 包含了日志框架 Logback的实现 ) , log4j-to-slf4j ( 在 log4j 日志框架作者开发此框架的时候还没有想到使用日志抽象层进行开 发,因此出现了 log4j 向 slf4j 转换的工具 ) , jul-to-slf4j ( Java 自带的日志框架转换为 slf4j).
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.13.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.7.30</version>
<scope>compile</scope>
</dependency>
</dependencies>
从上面的分析, Spring Boot 对日志框架的使用已经是清晰明了了
,我们使用 IDEA 工具查看 Maven 依赖关系,可以清晰的看到日志框架的引用
由此可见, Spring Boot 可以自动的适配日志框架,而且底层使用 SLF4j+ LogBack 记录日志,如果我 们自行引入其他框架,需要排除其日志框架。
五. Spring Boot 的日志使用
日志级别和格式
从上面的分析,发现 Spring Boot 默认已经使用了 SLF4J + LogBack . 所以我们在不进行任何额外操作 的情况下就可以使用 SLF4J + Logback 进行日志输出。
编写 Java 测试类进行测试。
Logger logger = LoggerFactory.getLogger(this.getClass());
/*
测试日志输出
SLF4J 日志级别(从小到大):trace<debug<info<warn<error 只会输出比当前级别更高的级别日志
日志级别:我们是可以进行手动调整级别
*/
@Test
public void testLog(){
// System.out.println();
logger.trace("trace日志....");
logger.debug("debug日志....");
// springboot中,日志的默认级别就是info级别 root级别
logger.info("info日志....");
logger.warn("warn日志....");
logger.error("error日志....");
已知日志级别从小到大为 trace < debug < info < warn < error . 运行得到输出如下。由此可见 Spring Boot 默认日志级别为 INFO.
从上面的日志结合 Logback 日志格式可以知道 Spring Boot 默认日志格式是
至于为什么 Spring Boot 的默认日志输出格式是这样?
我们可以在 Spring Boot 的源码里找到答案。
六. 自定义日志输出
可以直接在配置文件编写日志相关配置
# 日志配置
# 指定具体包的日志级别
logging.level.com.lagou=debug
# 控制台和日志文件输出格式
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
# 日志输出路径,默认文件spring.log
logging.file.path=spring.log
#logging.file.name=log.log
关于日志的输出路径,可以使用 logging.file 或者 logging.path 进行定义,两者存在关系如下表。
logging .file | logging .path | 例子 | 描述 |
(没有) | (没有) | 仅控制台记录。 | |
具体文件 | (没有) | my.log | 写入指定的日志文件,名称可以是精确 位置或相对于当前目录。 |
(没有) | 具体目录 | /var/log | 写入 spring.log指定的目录,名称可 以是精确位置或相对于当前目录。 |
七. 替换日志框架
因为 Log4j 日志框架已经年久失修,原作者都觉得写的不好,所以下面演示替换日志框架为 Log4j2 的 方式。根据官网我们 Log4j2 与 logging 需要二选一,因此修改 pom如下
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-logging</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>