常见的日志框架-简单介绍
# 02.常见的日志框架-简单介绍
不自己造轮子
# 前言
在前面我们介绍了什么是日志,以及日志的重要性,一般项目中都会用到,并介绍了print大法的缺点,怎么解决呢?我们可以自定义一个工具类,专门用于处理日志,取代sout。这样有几个优点
- 可以设置输出样式,例如设置错误输出的字体颜色,输出字眼是什么;
- 可以自定义输出级别,例如只输出错误日志的级别,当有问题的时候再调整级别更低,打印更多日志
- 可以将输出重定向到文件里(这种文件叫日志文件)
- 可以将输出重定向到数据库
- 可以………………
总之就是很多,工作中也几乎是必用的技术。
很可惜,在早期,Java是没有提供相关的功能的。当时大部分人都是用Java的打印语句:System.out和System.err。 这应该是最早的日志记录方式吧,但是不灵活也不可配置,要么就是全部打印,要么就是全部不打印,没有一个统一的日志级别
直到Java1.4 才有了相关的功能;在这之前,业内已经有不少成熟的日志框架了,几乎很少会用到Java提供的日志功能了。
# Log4j
Log4j,全程是Log for Java,意指Java用的日志框架。官网:Apache Log4j (opens new window)
4是和for谐音,在英语中不少这样的谐音。例如P2P中,2是指to,P2P全称 Peer to Peer
在1996年初,E.U.SEMPER
(欧洲安全电子市场)项目决定编写自己的跟踪API
,最后该API
演变为Log4j
,Log4j
日志软件包一经推出就备受欢迎,当然这里必须要提到一个人,就是Log4j
的主要贡献者:Ceki Gülcü (巨佬,划重点,要考的)
后来Log4j
成为了Apache
基金会项目中的一员,同时Log4j
的火爆,让Log4j
一度成为业内日志标杆。(据说Apache
基金会还曾经建议Sun
引入Log4j
到java
的标准库中,但是sun
拒绝了)
# JUL(Java Util Logging)
2002年2月Java1.4
发布,Sun
竟然推出了自己的日志库Java Util Logging
(难道这就是之前sun拒绝Log4j的原因?),其实很多日志的实现思想也都是仿照Log4j
,毕竟Log4j
先出来很多年了,已经很成熟了此时,这两个日志工具打架,显然Log4j
是更胜一筹..........
# JCL(Jakarta Commons Logging)
目前日志框架有很多个,如果用户想要切换的话,会非常麻烦,因为各个框架的设计和实现都不同;
能不能做一个抽象层?应用程序通过抽象层的API来生成日志,具体底层用什么日志框架,应用程序不用关心;当想要更换日志框架的时候,可以在不用改动代码(或者改动较少代码)的情况下完成切换,让应用程序更灵活。
笔者注:类似JDBC,一统数据库访问层;只提供了一种抽象,具体的实现靠各个数据库厂商实现的抽象。
JUL
刚出来不久,2002年8月Apache
又推出了日志接口Jakarta Commons Logging
,也就是日志抽象层,当然也提供了一个默认实现Simple Log
,这野心很大,想一统日志抽象,让日志产品去实现它的抽象,这样只要你的日志代码依赖的是JCL
的接口,你就可以很方便的在Log4j
和JUL
之间做切换,当时日志领域大概是这样的结构,当然也还是方便理解的,也很优雅
虽然听上去不错,但JCL
用起来似乎并不是那么好,很多人认为引用它后造成的问题比解决的问题还多…………
例如有人是这样说的:Tapestry Central: So long, commons-logging, hello SLF4J (opens new window) (需科学上网)
I'm finally taking a bit to do something I've wanted to do for a long time: get away from commons-logging (opens new window) and switch over to SLF4J (opens new window).
Commons-logging has a justified reputation (opens new window) for causing more problems than it solves.
# Slf4j(Simple Logging Facade for Java)
Ceki Gülcü 觉得 JCL不好用,于2005年也推出了一个接口方式,叫Slf4j(Simple Logging Facade for Java)。事实证明,这个接口要比JCL
在很多地方更优秀
但是由于Slf4j
出来的较晚,而且还只是一个日志接口,所以之前已经出现的日志产品,如JUL
和Log4j
都是没有实现这个接口的。那怎么办呢?之前出现的日志产品就不能使用该接口了吗?可以的, 于是大佬Ceki Gülcü撸出了桥接包,也就是这种类似适配器模式
应用
↓
Slf4j
↓
桥接包
↓
日志产品
2
3
4
5
6
7
也就是说,应用程序通过引用桥接包,可以使用SLF4J接口,至于底层用什么日志框架,应用程序不用关心
此时的桥接包就是分了两种场景
- 为了适配之前
Java
应用用的日志接口(如JCL
) - 为了适配之前
Java
应用用的日志产品(如Log4j, JUL
)
当然,桥接包不仅这么简单,这里不展开来说,具体可以参考本文的末尾。
# Logback
Logback是由log4j创始人设计的又一个开源日志组件,2011年11月3日,Logback 1.0版本发布。
由于有了之前设计Log4j的经验,Logback的性能能好,并且实现了SLF4J的接口,而且大佬还专门写了一篇文章:Reasons to prefer logback (opens new window)
小结下:
- 我们目前有两个日志接口:JCL 和 SLF4J
- 3个日志框架:JUL,Log4j,Logback
但Logback 用起来速度快,效率最高,SLFJ4+Logback 成为了很多人的最爱, 大有超越Apache Common Logging + Log4j 之势。
目前的日志框架,架构图大致如下:
# Log4j2
Apache于2012年推出了新项目Log4j 2, (完全不兼容Log4j1.x 的版本),并且Log4j2几乎涵盖了Logback的特性(Logback是开源的,也不算抄袭?😂 )
并且,Log4j2 也搞了一个新的接口设计,分化成log4j-api
和log4j-core
,这个log4j-api
也是日志接口,log4j-core
才是日志产品。。。
现在我们可有了3个日志接口,以及4个日志产品。。。
- 3个日志接口:JCL, SLF4J,Log4j-API
- 3个日志框架:JUL,Log4j,Logback,Log4j2
听起来可能稍微有点乱,但只要知道他们的历史,还是挺利于理解的。
# 最佳实践
有这么多接口规范和框架,我们应该如何在系统中使用呢?
- 应该使用日志接口的API,而非直接使用框架(这样后期方便更换日志框架)
- 只使用一个日志框架
- 在Maven中,把日志产品的依赖设置为
Optional
和runtime scope
其中Optional
是为了依赖不会被传递,比如别的人引用你这个jar
,就会被迫使用不想用的日志依赖 scope
设置为runtime
,是可以保证日志的产品的依赖只有在运行时需要,编译时不需要,这样,开发人员就不会在编写代码的过程中使用到日志产品的API
了
# 参考
java - Java日志系统历史从入门到崩溃_个人文章 - SegmentFault 思否 (opens new window) :强推,写的很简单易懂,关于桥接包的描述很棒
一个著名的日志系统是怎么设计出来的? (opens new window):介绍了设计思路,提到了正交性,涨知识了
进阶之路:Java 日志框架全画传(上) - 知乎 (opens new window)
进阶之路:Java 日志框架全画传(中) - 知乎 (opens new window)
进阶之路:Java 日志框架全画传(下) - 知乎 (opens new window)