持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情
混乱的日志框架
-
log4j(作者Ceki Gülcü)出来时就等到了广泛的应用(注意这里是直接使用),是Java日志事实上的标准,并成为了Apache的项目 -
Apache要求把log4j并入到JDK,SUN拒绝,并在jdk1.4版本后增加了
JUL(java.util.logging) -
毕竟是JDK自带的,JUL也有很多人用。同时还有其他日志组件,如SimpleLog等。这时如果有人想换成其他日志组件,如log4j换成JUL,因为api完全不同,就需要改动代码。
-
Apache见此,开发了
JCL(Jakarta Commons Logging),即commons-logging-xx.jar。它只提供一套通用的日志接口api,并不提供日志的实现。很好的设计原则嘛,依赖抽象而非实现。这样应用程序可以在运行时选择自己想要的日志实现组件。 -
这样看上去也挺美好的,但是log4j的作者觉得JCL不好用,自己开发出
slf4j,它跟JCL类似,本身不替供日志具体实现,只对外提供接口或门面。目的就是为了替代JCL。同时,还开发出logback,一个比log4j拥有更高性能的组件,目的是为了替代log4j。 -
Apache参考了logback,并做了一系列优化,推出了
log4j2
关系/依赖
日志框架这么多,不同的框架之间切换挺不方便,然后就诞生了Commons Logging和SLF4J,他们都提供统一的API,只针对API编程就行。
调用这两个Commons Logging和SLF4J框架的API进行日志管理,日志框架的具体实现可以是log4j、logback、JUL等
Sprint Boot日志
Spring的内部使用了Commons Logging,如果你的项目里有Log4j2,那就用Log4j2;如果有SLF4J,那就用SLF4J;如果都没有,就用JUL。
如果你引入了Web Starter,它会自动引入入Logging Starter,后者会引入Logback以及SLF4J,你可以使用SLF4J的API来编写log代码,实际底层会调用Logback。
另外Logging Starter还包含了log4j-api依赖,用此依赖你可以使用Log4j2的API来编写代码,但是Logging Starter并没有使用引入log4j-core这个具体实现,而是用了log4j-to-slf4j这个实现,它将Log4j2的调用转发到SLF4J上。
Logging Starter还包含了jul-to-slf4j依赖,它将JUL的日志转到的SLF4J。
总的来说,不管你写代码时候用的是Spring内部的Commons Logging,还是JUL,还是slf4j-api,还是log4j-api,最终都调用到了Logback。
那最终用哪个API好呢?我的建议是用SLF4J,如果感觉它的API(slf4j-api)不够用,比如你需要lambda来对日志参数进行延迟计算,再去换用Log4J2的API,也就是log4j-api模块。Commons Logging已经许久没有维护,Spring用它应该也是历史原因吧。SLF4J的API使用比较简单,如下:
@RestController
public class HelloController {
// getLogger是使用静态绑定的ILoggerFactory实例返回与作为参数传递的类相对应的记录器。这里是从LoggerFactory获取一个和HelloController类绑定的日志记录器
public static final Logger logger = LoggerFactory.getLogger(HelloController.class);
@GetMapping("/hello")
public String hello() {
logger.info("hello,log");
return "hello,log";
}
}
输出如下:
SLF4J日志级别有五个,从高到底分别为 ERROR、 WARN、 INFO、 DEBUG 和 TRACE。默认情况下,应用只会输出INFO及其以上的级别。
如果想查看DEBUG及以上的日志,可以给java -jar app.jar添加--debug参数,或者在application.properties添加debug=true属性,想看TRACE同理。不过这样只会控制Spring Boot内部以及tomcat或者hibernate等的日志,你自己编写的日志和其它库的日志是管不到的,如果你想管,那就需要添加logging.level.[logger名称]属性控制某个logger的输出。想控制全局默认日志输出级别?配置logging.level.root属性。
日志输出
默认情况下,日志会被输出到标准输出,即命令行。
可以使用logging.file指明日志具体保存到哪个文件,可以是绝对路径或者相对路径。你可以使用logging.path指明具体哪个文件夹,日志文件会保存在这个文件夹下,并命名为spring.log,文件夹可以是绝对路径或者相对路径。logging.file 和logging.path只需要设置一个就行。
默认情况下,日志每天都会打包一下, 压缩成.gz文件保存下来。同时你可以使用logging.file.max-size可以指定最大的日志文件大小,比如100MB,如果到达这个大小之后,就会被压缩成.gz文件保存下来,一天中保存的多个压缩文件会用序号来区分,如上图。logging.file.max-history属性可以设置压缩文件最多可以保存多少天,超过期限的就删掉。
Spring Boot中很多日志属性是和Logback严格相关的,如果你感兴趣,可以查看org.springframework.boot:spring-boot:2.1.7.RELEASE源码里的org.springframework.boot.logging.logback包下的相关配置文件defaults.xml和base.xml等等。实在不行还可以看Logback文档。真要自定义一些配置的话,可以在src/main/resources目录下新建logback.xml或者logback-spring.xml文件,Spring Boot推荐使用logback-spring.xml,方便它做一些初始化的工作。
总结
框架会用就好,不必深究,高级日志往往需要根据公司需求定制。
参考:管理日志