文章目录

  • 为什么我们需要日志记录?`[线上,我们要想查找问题,只能是通过日志的形式]`
  • 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的所有特性。

java 记录数据变化 java历史记录_Java

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组合使用