尚硅谷SpringBoot顶尖教程
日框架的来龙去脉: https://mp.weixin.qq.com/s/O3wlg8WwQ9c4DXzjC0Zc4w
市面上的日志框架:
上面的日志框架又可以分为日志门面(日志的抽象层)和日志实现.
日志门面(抽象层) | 日志实现 |
---|---|
log4j, JUL(Java Util Logging), log4j2, logback |
我们在项目中选择日志框架落地只需要从左边选择一个日志抽象层, 从右边选择一个日志实现.
SpringBoot默认使用的日志框架是: Slf4j + logback
但是SpringBoot底层依赖的是Spring框架, Spring框架默认使用JCL(Jakarta Commons Logging)
如果选择了slf4j的日志抽象层, 就只需要通过导入slf4j-日志实现的桥接包
, 让slf4j支持多种日志实现框架的接入.
官方适配图:http://www.slf4j.org/images/concrete-bindings.png, 提供了slf4j + logback, slf4j + log4j , slf4j + jul, slf4j + simple的日志实现方案, slf4j桥接到其他日志实现框架方案如下:
上图的方案梳理:
SpringBoot项目中, 整合的各个框架使用的日志框架都不一样, 比如 :
SpringBoot(slf4j+logback), Spring(jcl), Hibernate(jboss-logging)…, 那么如何让它们统一使用slf4j输出日志记录呢?
官方也给我们提供了解决方案, 可以将各个日志实现框架桥接到slf4j.
官方适配图: http://www.slf4j.org/images/legacy.png
上图方案梳理:
SpringBoot的父依赖中自动导入了spring-boot-starter-logging
作为日志的启动配置, 它依赖了logback-classic
, jcl-over-slf4j
, jul-to-slf4j
, log4j-over-slf4j
桥接包, 将各个框架的日志实现统一桥接到slf4j + logback实现, 这就是SpringBoot默认使用slf4j + logback日志实现的原因.
org.springframework.boot spring-boot-starter-logging
SpringBoot底层是使用slf4j+logback的方式进行日志记录, SpringBoot把其他的日志都替换成了slf4j。步骤如下:
上图中可以看到确认导入了其他日志实现框架桥接到slf4j的中间转换包, 我们打开jcl-over-slf4j.jar
中的日志工厂类LogFactory
, 可以看到里面其实是使用slf4j的日志工厂类SLF4JLogFactory
进行了狸猫换太子的操作。
所以,如果要引入其他日志框架, 就一定要把目前使用的日志框架依赖移除掉。比如: Spring框架用的是commons-logging,SpringBoot将它排除掉了,使用整合后的日志框架。
org.springframework spring-core commons-logging commons-logging
SpringBoot能自动适配所有的日志框架,而且底层使用slf4j+logback
的方式记录日志,引入其他框架的时候,只需要把这个框架依赖的原有日志框架排除掉。
logging.file | logging.path | for Example | Description |
---|---|---|---|
只在控制台输出 | |||
指定文件名 | my.log | 输出日志到my.log文件 | |
指定目录 | /var/log | 输出到指定目录的spring.log文件中 |
logging.file与logging.path二选一进行配置.
logging.path 指定路径/var/log在linux系统磁盘中是相对于根目录。
(1) 指定日志配置文件
在classpath类路径下放上每个日志框架自己的配置文件即可;SpringBoot就不会去使用它默认的配置了。配置文件对照如下:
日志框架 | 定制化配置文件 |
---|---|
logback | logback-spring.xml, logback-spring.groovy, logback.xml , logback.groovy |
log4j2 | log4j2-spring.xml, log4j.xml |
jul (java util logging) | logging.properties |
logback.xml 直接被日志框架识别,绕过SpringBoot,无法使用Spring的高级功能。
logback-spring.xml 日志框架不直接加载日志配置项,由SpringBoot解析日志配置,可以SpringBoot的高级功能Profile.
推荐使用 logback-spring.xml , log4j2-spring.xml方式的配置文件.
(2) 在SpringBoot全局配置文件中配置日志属性值:
## logging.file与logging.path二选一
# 在当前C盘路径下创建/spring/log目录, 使用spring.log作为默认日志文件
logging.path=C:/spring/log
# 指定日志输出文件
#logging.file=C:/spring/log/springboot.log# 指定日志输出级别
logging.level.com.aiguigu=debug
logging.level.org.springframework.jdbc=debug
logging.level.root=info## 指定控制台输出的日志格式
logging.pattern.console=[%d{yyyy-MM-dd' 'HH:mm:ss.sss}] [%C] [%t] [%L] [%-5p] %m%n
# 指定文件输出的日志格式
logging.pattern.file=[%d{yyyy-MM-dd' 'HH:mm:ss.sss}] [%C] [%t] [%L] [%-5p] %m%n
(3) 编写测试类, 执行单元测试
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// import ....
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTest {Logger logger = LoggerFactory.getLogger(this.getClass());@Testpublic void testLogger() {/*** 日志级别,SpringBoot默认的是info级别* 由低到高 trace
控制台测试日志:
[2023-03-16 22:13:15.015] [org.springframework.boot.StartupInfoLogger] [main] [57] [INFO ] Started MyTest in 9.347 seconds (JVM running for 10.341)
[2023-03-16 22:13:15.015] [com.aiguigu.spriingboot02config.MyTest] [main] [42] [DEBUG] 这是debug日志...
[2023-03-16 22:13:15.015] [com.aiguigu.spriingboot02config.MyTest] [main] [43] [INFO ] 这是info日志...
[2023-03-16 22:13:15.015] [com.aiguigu.spriingboot02config.MyTest] [main] [44] [WARN ] 这是warn日志...
[2023-03-16 22:13:15.015] [com.aiguigu.spriingboot02config.MyTest] [main] [45] [ERROR] 这是error日志...
C盘目录下的日志:
logging.file=C:/spring/log/springboot.log
指定日志输出文件测试结果:
将logback日志框架切换成log4j。切换到slf4j+log4j日志框架步骤:
排除 logback-classic日志框架依赖的jar, 排除其他日志框架的桥接包;
添加log4j日志框架依赖的jar;
从下面slf4j+log4j适配图中可以发现, 需要剔除jcl-over-slf4j.jar
, jul-to-slf4j.jar
; 添加slf4j-log412.jar
, log4j.jar
实操步骤:
排除logback-classic日志框架的依赖
导入slf4j-log4j12依赖,相关的依赖也一起导入了
pom.xml文件中的体现:
org.springframework.boot spring-boot-starter-web logback-classic ch.qos.logback jul-to-slf4j org.slf4j log4j-over-slf4j org.slf4j jcl-over-slf4j org.slf4j
org.slf4j slf4j-log4j12
在recources目录下添加log4j.properties
配置文件,该配置文件将被log4j日志框架识别
再次执行单元测试, 控制台输出日志报错了
java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactoryat org.springframework.test.context.junit4.SpringJUnit4ClassRunner.(SpringJUnit4ClassRunner.java:96)
// ......
Caused by: java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactoryat java.net.URLClassLoader.findClass(URLClassLoader.java:381)at java.lang.ClassLoader.loadClass(ClassLoader.java:424)at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)at java.lang.ClassLoader.loadClass(ClassLoader.java:357)... 16 more
经过分析, log4j日志实现可能依赖了appache的jcl日志框架的LogFactory类, 所以我们将上面排除的jcl-over-slf4j
取消排除, 重新运行后控制台是按照log4j.properties配置的日志格式打印日志, 至此日志框架从slf4j + logback
切换到 slf4j + log4j
成功.
2023-03-16 22:45:56 [ main:10895 ] - [ INFO ] Started MyTest in 10.576 seconds (JVM running for 11.532)
2023-03-16 22:45:56 [ main:10953 ] - [ INFO ] 这是info日志...
2023-03-16 22:45:56 [ main:10953 ] - [ WARN ] 这是warn日志...
2023-03-16 22:45:56 [ main:10953 ] - [ ERROR ] 这是error日志...
将spring-boot-starter-logging
切换成spring-boot-starter-log4j2
, 从而实现slf4j+log4j2
日志框架组合; 首先排除spring-boot-starter-logging
org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-logging
再添加spring-boot-starter-log4j2的依赖
org.springframework.boot spring-boot-starter-log4j2
Ctrl + Alt + U 查看依赖分析图, 自动导入了中间转换的依赖包 log4j-slf4j-impl
如果没有配置,系统会读取默认的spring-boot-{version}.RELEASE.jar
的logging包下面的默认xml配置。
在resources目录下添加log4j2-spring.xml
的日志配置文件:
启动应用,查看启动日志,已经切换到log4j2日志框架配置的日志格式了。
[20:09:50:068] [DEBUG] - com.aiguigu.spriingboot02config.MyTest.testLogger(MyTest.java:42) - 这是debug日志...
[20:09:50:068] [INFO] - com.aiguigu.spriingboot02config.MyTest.testLogger(MyTest.java:43) - 这是info日志...
[20:09:50:069] [WARN] - com.aiguigu.spriingboot02config.MyTest.testLogger(MyTest.java:44) - 这是warn日志...
[20:09:50:069] [ERROR] - com.aiguigu.spriingboot02config.MyTest.testLogger(MyTest.java:45) - 这是error日志...