Java日志框架历史演进及最佳实践

Java日志框架历史演进

日志作为逻辑追踪、线上问题排查、监控报警的有效基础利器被开发人员所熟知。问题发现、定位到解决都离不开它,而且从它的演进过程也能看到现代互联网发展的一个缩影。

互联网发展的早期,不管是C/S模式(客户端+服务端模式)还是B/S模式(浏览器+服务端模式),因为只有前端和后端交互这一层,验证逻辑基本上用的是前端alert,后台用System.out.print,服务器用echo命令回显。链路短,基本上够用。

JUL

Java Util Logging简称JUL,是JDK 中自带的log功能。虽然是官方自带的log lib,JUL的使用确不广泛。主要原因:

JUL从JDK1.4 才开始加入(2002年),当时各种第三方log lib已经被广泛使用了。Java Logging API提供了七个日志级别用来控制输出。这七个级别分别是:SEVERE、WARNING、INFO、CONFIG、FINE、FINER、FINEST。
JUL早期存在性能问题,到JDK1.5上才有了不错的进步,但现在和Logback/Log4j2相比还是有所不如。
JUL的功能不如Logback/Log4j2等完善,比如Output Handler就没有Logback/Log4j2的丰富,有时候需要自己来继承定制,又比如默认没有从ClassPath里加载配置文件的功能。

Log4j 1.x

Log4j 是在 Logback 出现之前被广泛使用的 Log Lib, 由 Gülcü 于2001年发布,后来成为Apache 基金会的顶级项目。Log4j 在设计上非常优秀,对后续的 Java Log 框架有长久而深远的影响,也产生了Log4c, Log4s, Log4perl 等到其他语言的移植。
通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。Log4j也有七种日志级别:OFF、FATAL、ERROR、WARN、INFO、DEBUG和TRACE。Log4j 的短板在于性能,在Logback 和 Log4j2 出来之后,Log4j的使用也减少了。
通过使用Log4j,可控制日志信息输送的目的地是控制台、文件、数据库等。也可以控制每一条日志的输出格式,通过定义每一条日志信息的级别,能够更加细致的控制日志的生成过程。Log4j支持两种格式的配置文件:properties和xml。包含三个主要的组件:Logger、appender、Layout。

JCL

JCL是Jakarta Commons-Logging的缩写,Jakarta在这里指的是一个组织,而不是印度的首都雅加达。Jakarta,一个早期的Apache开源项目,用于管理各个Java子项目,诸如Tomcat, Ant, Maven, Struts, JMeter, Velocity, JMeter, Commons等。2011年12月,在所有子项目都被迁移为独立项目后,Jakarta名称就不再使用了。

JCL诞生的初衷是因为Java自身的一些包用了JUL,而Log4j用户使用的有很多,那么JCL就是提供一套API来实现不同Logger之间的切换。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 的配置文件;如果喜欢用JUL,就只需要写个 JUL 的配置文件。如果有其他的新的日志库出现,也只需要它提供一个Adapter,运行的时候把这个日志库的 jar 包加进去。

image

到这个时候一切看起来都很简单,很美好。接口和实现做了良好的分离,在统一的JCL之下,不改变任何代码,就可以通过配置就换用功能更强大,或者性能更好的日志库实现。这种简单美好一直持续到SLF4J出现。

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等更多的特性。

Logback有三个模块:

  • logback-core:日志处理核心组件
  • logback-classic:完整的实现了SLF4j API,用于切换日志实现。
  • logback-access:与Servlet容器集成提供通过http来访问日志的功能。

因为logback比log4j大约快10倍、消耗更少的内存,迁移成本也很低,自动压缩日志、支持多样化配置、不需要重启就可以恢复I/O异常等优势,又名噪一时。

现在事情变复杂了。我们有了两个流行的 Log Facade,以及三个流行的 Log Implementation。Gülcü 是个追求完美的人,他决定让这些Log之间都能够方便的互相替换,所以做了各种 Adapter 和 Bridge 来连接:

image

可以看到甚至 Log4j 和 JUL 都可以桥接到SLF4J,再通过 SLF4J 适配到到 Logback!

在这里需要注意不能搞出循环的桥接,比如下面这些依赖就不能同时存在:

  • jcl-over-slf4j 和 slf4j-jcl
  • log4j-over-slf4j 和 slf4j-log4j12
  • jul-to-slf4j 和 slf4j-jdk14

Log4j2

维护 Log4j 的人不这样想,他们不想坐视用户一点点被 SLF4J /Logback 蚕食,继而搞出了 Log4j2。

Log4j2 和 Log4j1.x 并不兼容,设计上很大程度上模仿了 SLF4J/Logback,性能上也获得了很大的提升。 Log4j2与Logback非常类似,但是它有自己的亮点:如插件式结构、配置文件优化、异步日志

Log4j2 也做了 Facade/Implementation 分离的设计,分成了 log4j-api 和 log4j-core。Log4j2是Log4j的升级,它比其前身Log4j 1.x提供了重大改进,并提供了Logback中可用的许多改进,同时修复了Logback架构中的一些固有问题。

从GitHub的更新日志来看,Logback已经有半年没有更新了,而作为知名组织的Apache下的Log4j2的更新却是非常活跃的,Log4j 1.x 于2015年8月停止维护更新了

现在好了,我们有了三个流行的Log 接口和四个流行的Log实现,如果画出桥接关系的图来会是什么样子呢?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值