日志框架是每个系统必备的功能之一,在日常使用当中却往往没有得到应有的重视,要么跟随“前辈”,原来用什么就用什么,要么随便选择一个……甚至还有项目大量使用System.out.println来打印日志……

本篇文章带大家来聊聊Java主流的一些日志框架,已经适用的场景。作为相关技术领域的汇总,也作为一项参考资料。

主流的日志框架

目前主流的日志框架包括以下几种:

  • Log4j、Log4j2;
  • Logback;
  • Slf4j;
  • JCL (Jakarta Commons Logging),也叫Apache Common logging;
  • J.U.L (java.util.logging);

其中Log4j、Logback和Slf4j均同一个作者Ceki Gülcü所创。这也是为什么Logback必须配合Slf4j的原因。

而Log4j2是Log4j的升级版本,而且是不兼容性升级。Apache眼看有被Logback反超的势头,于2012-07重写了log4j 1.x,成立了新的项目Log4j2。Log4j2具有logback的所有特性。

鉴于目前Log4j2和Logback的性能及市场占有率,如果新项目对日志有一定的要求,建议在二者中选其一。

下面我们就详细了解这几款日志框架的特性及相关使用场景。

Log4j的历史

在JDK1.4以前,Java中日志的打印通过System.out.println(),System.err.println()或者e.printStackTrace()来实现。Debug日志被写到STDOUT流,错误日志被写到STDERR流。

也就是说日志只能分两类打印成流信息:Debug级别和Error级别。很显然,粒度不够细,而且无法定制。

Ceki在2001年发布了Log4j,并成为Apache的顶级项目。Log4j的设计对后续的Java日志框架有长久而深远的影响,它定义的Logger、Appender、Level等概念已被广泛运用。但Log4j的短板在于性能,在Logback和Log4j2问世之后,便逐渐被替代。

所以,如果你在项目中还在使用System流的形式打印日志,只能说已经回到了JDK1.4以前的时代了。

J.U.L

2002年Java1.4发布,Sun推出了自己的日志库JUL(Java Util Logging),其实现基本模仿了Log4j的实现。但是它的功能远不如log4j完善,开发者需要自己编写Appenders(Sun称之为Handlers),且只有两个Handlers可用(Console和File),在Java1.5以后性能和可用性才有所提升。

JUL因为是JDK默认的框架,很多开源框架还在使用,针对于开发者来说,简单的项目还是可以考虑使用的。但如果是大型项目,对日志有一定的要求,那么就不推荐了。

JCL(commons-logging)

面对日志框架二选一的情况,Apache推出了Jakarta Commons Logging。JCL是一个日志门面框架(Log Facade,它定义了一套日志接口(其内部也提供一个Simple Log的简单实现),支持运行时动态加载日志组件的实现。也就是说代码中只需调用Commons Logging的接口,底层实现可以是log4j,也可以是Java Util Logging。

而在项目使用时,可根据自己的需要或爱好选择使用合适的Log Implementation。需要什么日志框架,就添加对应的依赖jar包,配置对应的配置文件即可。不过commons-logging对Log4j和j.u.l的配置问题兼容的并不好,它在加载时可能会导致NoClassDefFoundError错误。

SLF4J & Logback

2006年,Ceki不适应Apache的工作方式,离开了Apache。先后创建了slf4j(日志门面接口,类似于Commons Logging)和Logback(Slf4j的实现)两个项目,并创建了QOS公司,官网上是这样描述Logback的:The Generic,Reliable Fast&Flexible Logging Framework(一个通用,可靠,快速且灵活的日志框架)。

可以看一下这位大神的照片:

image

这也导致了现今日志框架分为两大阵营:Commons Logging阵营和SLF4J阵营。

slf4j通过各种Adapter和Bridge实现了各种Log日志框架之间的可以方便的相互替换。

image

可以看到,对另外一个阵营的Log4j和JUL都进行了相应的支持。

Log4j2

前面已经提到,面对SLF4J和Logback的攻势,Log4j团队也不甘示弱,设计出了Log4j2。

Log4j2和Log4j并不兼容,设计上很大程度上模仿了SLF4J/Logback,性能上也获得了很大的提升。Log4j2也做了Facade/Implementation分离的设计,分成为log4j-api和log4j-core。

日志框架的分类

经过上面的分析,我们大概了解了各个日志框架的基本来源及功能。通过下图,可以对日志框架进行一个简单的分类。

image

接口层为:slf4j和commons-logging。而实现层为:log4j、Logback、JUL、log4j2。

日志门面的出现很大程度缓解了日志系统的混乱,很多库的作者不再使用具体的日志框架实现了,而是去使用接口层,即面向接口编程。

门面模式

我们知道slf4j和commons-logging都使用了门面模式。门面模式,是指提供一个统一的接口去访问多个子系统的多个不同的接口,它为子系统中的一组接口提供一个统一的高层接口。使得子系统更容易使用。

日志门面是门面模式的一个典型的应用。下面是门面模式的一个类图。

image

日志门面接口提供了一套独立于具体日志框架实现的API,应用程序通过使用这些独立的API就能够实现与具体日志框架的解耦,这跟JDBC是类似的。

以slf4j为例,api对外暴露的都是接口。

image

slf4j api使用的是slf4j-api.jar,然后调用下层各个日志框架(通过桥接或直接继承)的实现。

Java日志框架的选择

成本考虑:Logback的所有文档是全面免费提供,而Log4J只提供部分免费文档。

资源开销:Commons Logging比SLF4J开销更高一些。

性能:Logback比Log4j拥有更好的性能,但与Log4j2的比较说法不一。

参考文章:
(1)https://blog.csdn.net/xintonghanchuang/article/details/90752323

(2)https://www.jianshu.com/p/5326b5cc7d6c
(3)https://www.cnblogs.com/xiaobingblog/p/11502976.html
(4)https://segmentfault.com/a/1190000006925098



聊聊这些年我们用过的Java日志框架插图5

关注公众号:程序新视界,一个让你软实力、硬技术同步提升的平台

除非注明,否则均为程序新视界原创文章,转载必须以链接形式标明本文链接

本文链接:http://www.choupangxia.com/2020/10/25/java-log/