文章目录
- 为什么我们需要日志记录?`[线上,我们要想查找问题,只能是通过日志的形式]`
- Java常用日志框架历史
- Log4j 1.x `[Apache日志实现]`
- Java Util Logging `[自Java1.4以来的官方日志实现]`
- Commons Logging`[一个日志门面]`
- SLF4J/Logback`[slf4j 日志门面]` `[logback 日志实现]`
- Log4j2`[Facade/Implementation 分离设计,分成 log4j-api 和 log4j-core]`
- 小结一下
为什么我们需要日志记录?[线上,我们要想查找问题,只能是通过日志的形式]
日志可以帮助我们记录应用的运行状态以及一些关键业务信息。
对于一个应用程序来说日志记录是必不可少的一部分。线上问题追踪,基于日志的业务逻辑统计分析等都离不日志。
在项目开发过程中,我们可以通过 debug 查找问题。
而在线上环境我们查找问题只能通过打印日志的方式查找问题。因此对于一个项目而言,日志记录是一个非常重要的问题。
Java常用日志框架历史
1996年早期,欧洲安全电子市场项目组决定编写它自己的程序跟踪API(Tracing API)。
经过不断的完善,这个API终于成为一个十分受欢迎的Java日志软件包,即Log4j。
后来Log4j成为Apache基金会项目中的一员。
期间Log4j近乎成了Java社区的日志标准。
据说Apache基金会还曾经建议sun引入Log4j到java的标准库中,但Sun拒绝了。
2002年Java1.4发布,Sun推出了自己的日志库JUL(Java Util Logging),其实现基本模仿了Log4j的实现。
在JUL出现以前,log4j就已经成为一项成熟的技术,使得log4j在选择上占据了一定的优势。
接着,Apache推出了Jakarta Commons Logging(后更名为Commons Logging),JCL只是定义了一套日志接口(其内部也提供一个Simple Log的简单实现),支持运行时动态加载日志组件的实现。
也就是说,在你应用代码里,只需调用Commons Logging的接口,底层实现可以是log4j,也可以是Java Util Logging。
后来(2006年),Ceki Gülcü不适应Apache的工作方式,离开了Apache。
然后先后创建了slf4j(日志门面接口,类似于Commons Logging)和Logback(Slf4j的实现)两个项目,
并回瑞典创建了QOS公司,QOS官网上是这样描述Logback的:
The Generic,Reliable Fast&Flexible Logging Framework(一个通用,可靠,快速且灵活的日志框架)。
现今,Java日志领域被划分为两大阵营:Commons Logging阵营和SLF4J阵营。
Commons Logging在Apache大树的笼罩下,有很大的用户基数。但有证据表明,形式正在发生变化。
2013年底有人分析了GitHub上30000个项目,统计出了最流行的100个Libraries,可以看出slf4j的发展趋势更好。
Apache眼看有被Logback反超的势头,于2012-07重写了log4j 1.x,成立了新的项目Log4j 2。
Log4j 2具有logback的所有特性。
Log4j 1.x [Apache日志实现]
短板在于性能差
Log4j 是在Logback出现之前被广泛使用的Log Lib, 由 Gülcü 于2001年发布,后来成为Apache基金会的顶级项目。
Log4j 在设计上非常优秀,对后续的 Java Log 框架有长久而深远的影响,也产生了Log4c, Log4s, Log4perl 等到其他语言的移植。
Log4j 的短板在于性能,在Logback 和 Log4j2 出来之后,Log4j的使用也减少了。
Java Util Logging [自Java1.4以来的官方日志实现]
[出现的晚][性能差][功能不完善]
简称JUL,是JDK 中自带的log功能。虽然是官方自带的log lib,JUL的使用确不广泛。
主要原因:
1)、JUL从JDK 1.4才开始加入(2002年),当时各种第三方log lib已经被广泛使用了
2)、JUL早期存在性能问题,到JDK1.5上才有了不错的进步,但现在和Logback/Log4j2相比还是有所不如
3)、JUL的功能不如Logback/Log4j2等完善,比如Output Handler就没有Logback/Log4j2的丰富,
有时候需要自己来继承定制,又比如默认没有从ClassPath里加载配置文件的功能
Commons Logging[一个日志门面]
[输出日志时,若使用不当,则会导致大量无用的字符串拼接,影响性能]
简称JCL,是Apache下面的项目。之前叫Jakarta Commons Logging,后更名为Commons Logging。
JCL 是一个Log Facade,只提供 Log API,不提供实现,然后由 Adapter 来使用 Log4j 或者 JUL 作为Log Implementation。
JDK现在带了自己的JUL,然后又有第三方的 Log4j 等日志库存在,不同的项目可能各自使用了不同的日志库。
如果你的项目依赖的其他 lib 各自使用了不同的日志库,你想控制日志行为,就需要针对每个日志库都写一个配置文件。
然后这个时候 JCL 就出现了。在程序中日志创建和记录都是用JCL中的接口,在真正运行时,会看当前ClassPath中有什么实现,如果有Log4j 就是用 Log4j, 如果啥都没有就是用 JDK 的 JUL。
这样,在你的项目中,还有第三方的项目中,大家记录日志都使用 JCL 的接口,然后最终运行程序时,可以按照自己的需求(或者喜好)来选择使用合适的Log Implementation。
如果用Log4j, 就添加 Log4j 的jar包进去,然后写一个 Log4j 的配置文件[log4j.properties];
如果喜欢用JUL,就只需要写个 JUL 的配置文件[properties]。
如果有其他的新的日志库出现,也只需要它提供一个Adapter,运行的时候把这个日志库的 jar 包加进去。
SLF4J/Logback[slf4j 日志门面]
[logback 日志实现]
SLF4J(The Simple Logging Facade for Java) 和 Logback 也是Gülcü 创立的项目,其创立主要是为了提供更高性能的实现。
其中,SLF4j 是类似于JCL 的Log Facade,Logback 是类似于Log4j 的 Log Implementation。
Apache 有了个JCL,用来做各种Log lib统一的接口,如果 Gülcü 要搞一个更好的 Log 实现的话,直接写一个实现就好了,为啥还要搞一个SLF4J呢?
原因是Gülcü 认为 JCL 的 API 设计得不好,容易让使用者写出性能有问题的代码。
// 比如在用 JCL 输出一个 debug 级别的 log:
logger.debug("start process request, url:" + url);
这个有什么问题呢?
一般生产环境 log 级别都会设到 info 或者以上,那这条 log 是不会被输出的。
然而不管会不会输出,这其中都会做一个字符串连接操作,然后生产一个新的字符串。
如果这条语句在循环或者被调用很多次的函数中,就会多做很多无用的字符串连接,影响性能。
// JCL 的最佳实践推荐写法
if (logger.isDebugEnabled()) {
logger.debug("start process request, url:" + url);
}
// 然而开发者常常忽略这个问题或是觉得麻烦而不愿意这么写。所以SLF4J提供了新的API,方便开发者使用:
logger.debug("start process request, url:{}", url);
这样的话,在不输出 log 的时候避免了字符串拼接的开销;
在输出的时候需要做一个字符串format,代价比手工拼接字符串大一些,但是可以接受。
而 Logback 则是作为 Log4j 的继承者来开发的,提供了性能更好的实现,异步 logger,Filter等更多的特性。
现在事情变复杂了。我们有了两个流行的 Log Facade,以及三个流行的 Log Implementation。
Gülcü 是个追求完美的人,他决定让这些Log之间都能够方便的互相替换,所以做了各种 Adapter 和 Bridge 来连接
Log4j2[Facade/Implementation 分离设计,分成 log4j-api 和 log4j-core]
现在有了更好的 SLF4J 和 Logback,你会想事情到这里总该结束了吧,让它们慢慢取代JCL 和 Log4j 好了。
然而维护 Log4j 的人不这样想,他们不想坐视用户一点点被 SLF4J/Logback 蚕食,继而搞出了 Log4j2。
Log4j2 和 Log4j1.x 并不兼容,设计上很大程度上模仿了 SLF4J/Logback,性能上也获得了很大的提升。
Log4j2 也做了 Facade/Implementation 分离的设计,分成了 log4j-api 和 log4j-core。
现在好了,我们有了三个流行的Log 接口和四个流行的Log实现
小结一下
Commons Logging和Slf4j是日志门面,log4j和Logback则是具体的日志实现方案
常用的组合使用方式是Slf4j与Logback组合使用,Commons Logging与Log4j组合使用