日志框架发展历程
实现框架
log4j1
JUL
logback
log4j2
门面日志
SLF4J
JCL
Spring-JCL
Jboss-logging
日志框架选型
现在,java日志框架分为实现类和门面类。
常见的日志输出框架有:log4j1,log4j2,logback,JUL等。
log4j1(又叫log4j)是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、数据库等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。当前已经停止维护,不建议使用。
JUL是JDK自带的一个日志实现,java.util.logging包下的各个类提供了原生的日志记录和输出支持。
未配置JUL配置文件时,JUL的日志将输到控制台。如果需要转换到slf4j/log4j,除了要使用桥接包外,还必须正确地初始化jul桥接包(因为JUL由jdk携带,无法排除,不初始化桥接包,就不会转到其它日志框架输出),初始化方式参见下文桥接包说明。
Logback,一个“可靠、通用、快速而又灵活的Java日志框架”。Logback当前分成三个模块:logback-core,logback- classic和logback-access。
logback-core:是logback的核心模块。
logback- classic:logback的日志实现,同时实现了slf4j。
logback-access:与servlet容器(如Tomcat和Jetty)集成,以提供记录HTTP访问日志。
Apache Log4j2是Log4j的升级,对其前身Log4j1进行了重大改进,并提供了Logback中可用的许多改进,同时修复了Logback架构中的一些固有问题。注意:log4j2与log4j1相互不兼容(但log4j2提供了桥接包,可以将log4j1桥接到log4j2)。
log4j2核心包 | |
log4j-api | log4j2核心包,api接口。当使用log4j2输出日志时,必须提供此包。 |
log4j-core | log4j2日志输出包。实现log4j2日志输出功能。当使用log4j2输出日志时,必须提供此包。 |
各日志框架桥接到log4j2输出日志 | |
log4j-1.2-api | log4j1日志api桥接到log4j2,使用log4j2 api输出日志。 引入此包后,不需要再引入log4j1包,使用了log4j1的api代码不会出错。 |
log4j-jcl | JCL日志api桥接到log4j2包(在META-INF配置文件中指定了jcl 日志的实现工厂)。 引入此包后时,必须引入JCL API包。 |
log4j-jul | JUL日志api桥接到log4j2包。 将JUL转换成log4j2日志输出。 使用此包时,必须在使用jul相关api之前设置参数:java.util.logging.manager为org.apache.logging.log4j.jul.LogManager,例如: 虚拟机参数:-Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager 或代码设置:System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") |
log4j-slf4j-impl | slf4j 1.7桥接到log4j2包。 使用此包后,使用slf4j api的日志输出将使用log4j2打印日志。 此包对应slf4j 1.7(包含)以下版本。 选择此包时,需要同时选择slf4j-api。 |
log4j-slf4j18-impl | slf4j 1.8桥接到log4j2包。 使用此包后,使用slf4j api的日志输出将使用log4j2打印日志。 此包对应slf4j 1.8(包含)以上版本。slf4j 1.7不能使用此包。 选择此包时,需要同时选择slf4j-api。 |
log4j2桥接到其它日志框架包 | |
log4j-to-slf4j | log4j2桥接到slf4j包。 使用此包后,log4j2 api的日志输出将使用slf4j api打印日志。 选择此包时,需要同时选择log4j-api,不能选择log4j-core |
常见的门面日志框架有:slf4j,jcl(Apache Commons Logging),Spring-JCL,jboss-logging等。
Java简易日志门面(Simple Logging Facade for Java,缩写SLF4J),是一套包装Logging 框架的界面程式,以外观模式实现。可以在软件部署的时候决定要使用的 Logging 框架,目前主要支持的有Java Logging API、Log4j2及logback等框架。
SLF4J只是一个门面服务而已,他并不是真正的日志框架,真正的日志的输出相关的实现还是要依赖其背后的日志实现Log4j2、logback等日志框架的,具体信息见下图。
由上图可以看到 slf4j 几乎可以使用所有的具体日志框架,图中颜色意义如下:
绿色的 application:应用层,向下可直接调用 slf4j 提供的 API
浅蓝色的 abstract logging api:抽象 API 层
深蓝色的 native implementation of slf4j-api:具体日志框架实现层,不需要适配器,本身已经实现了 slf4j-api
湖蓝色的 adaptation layer:适配层,也就是桥接器
灰色的 non-native implementation of slf4j-api:具体日志框架实现层,本身没有实现 slf4j-api,需要桥接器。
具体包jar包说明如下
jar包 | jar包作用 | 说明 |
slf4j核心包 | ||
slf4j-api | sfl4j核心包,api | 使用slf4j框架时,必须包 |
将各种日志桥接到slf4j输出包: | ||
jcl-over-slf4j |
将jcl桥接到sl4j,使用此包后,不需要引入JCL API,Spring JCL包。 |
使用其它日志框架api转换为slf4j实现。 即其它框架api打日志时,将调用slf4输出日志。 使用这部分包时,原来的日志框架api可以不再依赖。 |
jul-to-slf4j | 将jul桥接到slf4j。 相关类由JDK提供,我们不能排除掉JDK,因此引入jar包后,需要调用以下代码,才会生效(或使用其它方式): SLF4JBridgeHandler.removeHandlersForRootLogger(); SLF4JBridgeHandler.install(); |
|
log4j-over-slf4j | 将log4j1桥接到sfl4j。 使用此包后,使用log4j1 api的日志输出将使用slf4j打印日志。引用此包后不需要引入log4j1的jar包。 |
|
将slf4j桥接到其它日志框架输出 | ||
slf4j-jcl | 将slf4j转换成jcl输出日志 | 将sfl4j转换成其它日志。即当使用sfl4j api打日志时,将调用其它日志框架输出日志。 当使用这几个jar包时,需要对应的日志框架api和实现。 |
slf4j-jdk14 | 将slf4j转换成jul输出日志。 | |
|
|
|
slf4j默认实现包 | ||
slf4j-nop | 当使用slf4j api打日志时,无日志输出 | |
slf4j-simple | 当使用slf4j-api打日志时,直接控制台输出 |
log4j-slf4j-impl | slf4j 1.7桥接到log4j2包。 使用此包后,使用slf4j api的日志输出将使用log4j2打印日志。 此包对应slf4j 1.7(包含)以下版本。 选择此包时,需要同时选择slf4j-api。 |
由log4j2发布,版本号与log4j2一样 |
log4j-slf4j18-impl | slf4j 1.8桥接到log4j2包。 使用此包后,使用slf4j api的日志输出将使用log4j2打印日志。 此包对应slf4j 1.8(包含)以上版本。slf4j 1.7不能使用此包。 选择此包时,需要同时选择slf4j-api。 |
|
log4j-to-slf4j | log4j2桥接到slf4j包。 使用此包后,log4j2 api的日志输出将使用slf4j打印日志。 选择此包时,需要同时选择log4j-api,不能选择log4j-core |
slf4j jar包冲突
如果选择了同一种框架桥接到->slf4j的日志输出时,就不能再选择sfl4j转换到此框架的转换包,否则将造成循环调用(其它日志框架slf4j),如下图:
调用 slf4j 的 API 接口,然后 slf4j 将请求转发给 slf4j-log4j12,使用log4j1来输出日志,log4j1日志请求会重新打回给 slf4j,从而形成一个死循环。
JCL全名叫Apache Commons Logging(原名 Jakarta Commons Logging,JCL)是一个基于Java的日志记录实用程序,是用于日志记录和其他工具包的编程模型。它通过其他一些工具提供API,日志实现和包装器实现。目前已经停止更新(可以使用spring jcl替代)。
commons-logging和SLF4J的功能是类似的,主要是用来做日志门面的。
JCL会自动寻找合适的日志框架输出日志。
依次自动寻找:log4j1(只支持logj1,不支持log4j2),JDK14(JUL),Jdk13Lumberjack,SimpleLog(直接打在控制台)。
如果要让JCL使用log4j2/slf4j输出日志,一定要使用jcl到log4j2/slf4j的桥接包,也可以选择使用Spring JCL或其它JCL桥接器替代JCL。
由于目前Apache JCL已经停止维护,所以从Spring 5.0开始,它提供了spring版本的JCL,对外API与Apache JCL一样。
他会依次自动寻找:log4j2(如果是log4j2->slf4j桥接包中的api,则直接使用slf4j),slf4,jul日志框架记录日志(谁先找到就用谁)。
Spring JCL可以完全替换Apache JCL。jcl-over-slf4j也可以完全替代Apache JCL。两个包只需要二远一即可。有了Spring JCL/jcl-over-slf4j包的工程,可以完全排除Apache JCL。
jsobb-logging是一款类似slf4j的门面日志框架,一般主要用于hibernate中。
它会自动寻找:JBoss LogManager(主要在 WildFly 应用服务器内部使用),Log4j2,log4j1,JUL日志框架记录日志(谁先找到就用谁)。
因jboss能自动适配log4j2,因此当log4j2/log4j1作为实现时日志输出时,可以不需要转换;否则,会自动匹配JUL输出日志,如果未配置JUL作为日志实现时,需要将JUL转换到其它日志输出,否则会直接打在控制台。
一般说来,在代码中都直接使用门面日志框架来记录日志。再组合各转换桥接包输出日志。
常用的就是使用slf4j,其它各框架都将转换成slf4j输出日志,再由slf4j调用真实的日志输出包。
因此这里只列出slf4j作为日志框架的jar包选择。
必选包:slf4j-api | ||||
可选包:XXX-to-slf4j,XXX-over-slf4j。 根据代码或第3方jar包的需要,选择合适的桥接器,将相应的日志框架输转换到slf4j输出日志。 |
||||
真实日志输出包(必须选择一个): slf4j+logback:logback-core,logback- classic。 log4j2:log4j-api、log4j-core、log4j-slf4j-impl或log4j-slf4j18-impl。注意此时不能再选择log4j-to-slf4j包,否则会死循环。 log4j1:log4j-1.2.X.jar、slf4j-log4j12-X.jar。目前log4j2已经停止发布,不建议选择。 JCL:JCL包,slf4j-jcl-X.jar。注意此时不能再选择jcl-over-slf4j包,否则会死循环。 JUL:slf4j-jul-X.jar。注意此时不能再选择jul-to-slf4j包,否则会死循环。 |
如下图所示:
slf4j搭配几种主流日志输出图解图中展示了能安全地从别的日志框架 API 转调回 slf4j 的三种情形。要想实现转调,方法就是图上列出的用特定的桥接器 jar 替换掉原有的日志框架 jar。