log4j -> log4j2 桥接
去掉 log4j 1.x jar,添加log4j-1.2-api.jar,配合 log4j-api-2.x.x.jar 和 log4j-core-2.x.x.jar 即可,依赖如下
log4j-1.2-api.jar log4j-api-2.x.x.jar log4j-core-2.x.x.jar
log4j2 -> log4j 桥接
不建议。
本来log4j在2015年停止更新后,就建议转向log4j2,并提供了到log4j2的桥接接口。
所以反过来log4j2到log4j是不建议这么做的,log4j2也没有提供直接支持。
但理清了上面的jar包作用,就会发现,可以通过 log4j2 -> slf4j -> log4j 的方式来实现。
需要的jar包,根据依赖关系分别是:
log4j-api-2.x.x.jar log4j-to-slf4j.jar slf4j-api-x.x.x.jar slf4j-log4j12-x.x.x.jar l log4j-1.2.17.jar
slf4j
同时有日志输出和转接功能。
核心jar包是 slf4j-api-x.x.x.jar
因为一般slf4j 只作为桥接用,如果要搭配 slf4j 自带的简单日志输出,那么就加上 slf4j-simple.jar
log4j -> slf4j
将代码中的log4j日志桥接到 slf4j,需要如下jar包
log4j-over-slf4j-x.x.x.jar slf4j-api-x.x.x.jar
log4j2 -> slf4j
将代码中的log4j2日志桥接到 slf4j,需要如下jar包
log4j-api-2.x.x.jar log4j-to-slf4j-2.x.x.jar slf4j-api-x.x.x.jar
slf4j -> log4j
将slf4j日志,采用log4j实现进行输出,需要如下jar包
slf4j-api-x.x.x.jar slf4j-log4j12.jar log4j-1.2.17.jar
slf4j -> log4j2
将slf4j日志,采用log4j2实现进行输出,需要如下jar包
slf4j-api-x.x.x.jar log4j-slf4j-impl.jar log4j-api.jar log4j-core.jar
slf4j的代理绑定和输出组合起来,就实现了从一种日志框架,转到另一种日志实现框架的效果。
建议在这三种日志混用的情况下,采用如下方案
log4j -> log4j2 slf4j -> log4j2
日志系统桥接器
日志系统桥接器说白了就是一种偷天换日的解决方案。
比如log4j-over-slf4j,即log4j -> slf4j的桥接器,这个库定义了与log4j一致的接口(包名、类名、方法签名均一致),但是接口的实现却是对slf4j日志接口的包装,即间接调用了slf4j日志接口,实现了对日志的转发。
但是,jul-to-slf4j是个意外例外,毕竟JDK自带的logging包排除不掉啊,其实是利用jdk-logging的Handler机制,在root logger上install一个handler,将所有日志劫持到slf4j上。要使得jul-to-slf4j生效,需要执行
SLF4JBridgeHandler.removeHandlersForRootLogger(); SLF4JBridgeHandler.install(); 12
spring boot中的日志初始化模块已经包括了该逻辑,故无需手动调用。在使用其他框架时,建议在入口类处的static{ }区执行,确保尽早初始化。
日志桥接器使用
log4j -> slf4j,slf4j -> log4j两个桥接器同时存在会出现什么情况?
互相委托,无限循环,堆栈溢出。
slf4j -> logback,slf4j -> log4j两个桥接器同时存在会如何?
两个桥接器都会被slf4j发现,在slf4j中定义了优先顺序,优先使用logback,仅会报警,发现多个日志框架绑定实现;但有一些框架中封装了自己的日志facade,如果其对绑定日志实现定义的优先级顺序与slf4j不一致,优先使用log4j,那整个程序中就有两套日志系统在工作。
为达到统一使用slf4j & logback的目的,必须要做4件事:
- 引入slf4j & logback日志包和slf4j -> logback桥接器;
- 排除common-logging、log4j、log4j2日志包;
- 引入jdk-logging -> slf4j、common-logging -> slf4j、log4j -> slf4j、log4j2 -> slf4j桥接器;
- 排除slf4j -> jdk-logging、slf4j -> common-logging、slf4j -> log4j、slf4j -> log4j2桥接器
*ps*:log4j2桥接器由log4j2提供,其他桥接器由slf4j提供。
如果再严谨一点,还要排除掉slf4j-simple、slf4j-nop两个框架,不过这两个一般没人用。
maven首先遵循路径最短优先原则,即直接引入最优先,传递依赖层级越浅,越优先。若依然无法仲裁,则遵循优先声明原则,在pom中声明靠前的优先
如何进行日志系统转换?
在实际的日志转换过程中,SLF4J其实是充当了一个中介的角色。例如当我们一个项目原来是使用LOG4J进行日志记录,但是我们要换成LogBack进行日志记录。
此时我们需要先将LOG4J转换成SLF4J日志系统,再从SLF4J日志系统转成LogBack日志系统。
从日志框架转向SLF4J
- jul-to-slf4j:jdk-logging到slf4j的桥梁
- log4j-over-slf4j:log4j1到slf4j的桥梁
- jcl-over-slf4j:commons-logging到slf4j的桥梁
从SLF4J转向具体的日志框架
- slf4j-jdk14:slf4j到jdk-logging的桥梁
- slf4j-log4j12:slf4j到log4j1的桥梁
- log4j-slf4j-impl:slf4j到log4j2的桥梁
- logback-classic:slf4j到logback的桥梁
- slf4j-jcl:slf4j到commons-logging的桥梁
不能同时使用
- jcl-over-slf4j 和 slf4j-jcl
- log4j-over-slf4j 和 slf4j-log4j12
- jul-to-slf4j 和 slf4j-jdk14
例如我们一开始使用的是 Log4J 日志框架,现在我们希望转成 LogBack 框架,那么我们首先需要加入 log4j-over-slf4j.jar 将 Log4J 转成 SLF4J,之后再加入 logback-classic.jar 将 SLF4J 转成 LogBack。