#1 系列目录html
#2各类jar包总结java
log4j1:apache
log4j2:编程
logback:api
commons-logging:微信
slf4j转向某个实际的日志框架:架构
场景介绍:如 使用slf4j的API进行编程,底层想使用log4j1来进行实际的日志输出,这就是slf4j-log4j12干的事。框架
某个实际的日志框架转向slf4j:this
场景介绍:如 使用log4j1的API进行编程,可是想最终经过logback来进行输出,因此就须要先将log4j1的日志输出转交给slf4j来输出,slf4j再交给logback来输出。将log4j1的输出转给slf4j,这就是log4j-over-slf4j作的事.net
这一部分主要用来进行实际的日志框架之间的切换(下文会详细讲解)
#3集成总结
##3.1 commons-logging与其余日志框架集成
1 commons-logging与jdk-logging集成:
须要的jar包:
2 commons-logging与log4j1集成:
须要的jar包:
3 commons-logging与log4j2集成:
须要的jar包:
4 commons-logging与logback集成:
须要的jar包:
5 commons-logging与slf4j集成:
须要的jar包:
##3.2 slf4j与其余日志框架集成
slf4j与jdk-logging集成:
须要的jar包:
slf4j与log4j1集成:
须要的jar包:
slf4j与log4j2集成:
须要的jar包:
slf4j与logback集成:
须要的jar包:
slf4j与commons-logging集成:
须要的jar包:
#4 日志系统之间的切换
##4.1 log4j无缝切换到logback
###4.1.1 案例
咱们已经在代码中使用了log4j1的API来进行日志的输出,如今想不更改已有代码的前提下,使之经过logback来进行实际的日志输出。
已使用的jar包:
使用案例:
private static final Logger logger=Logger.getLogger(Log4jTest.class); public static void main(String[] args){ if(logger.isInfoEnabled()){ logger.info("log4j info message"); } }
上述的Logger是log4j1本身的org.apache.log4j.Logger,在上述代码中,咱们在使用log4j1的API进行编程
如今如何能让上述的日志输出经过logback来进行输出呢?
只须要更换一下jar包就能够:
第一步:去掉log4j jar包
第二步:加入如下jar包
第三步:在类路径下加入logback的配置文件
原理是什么呢?
###4.1.2 切换原理
看下log4j-over-slf4j就一目了然了:
咱们能够看到,这里面实际上是简化更改版的log4j。去掉log4j1的原生jar包,换成该简化更改版的jar包(能够实现无缝迁移)。
可是简化更改版中的Logger和原生版中的实现就不一样了,简化版中的Logger实现以下(继承了Category):
public class Category { private String name; protected org.slf4j.Logger slf4jLogger; private org.slf4j.spi.LocationAwareLogger locationAwareLogger; Category(String name) { this.name = name; slf4jLogger = LoggerFactory.getLogger(name); if (slf4jLogger instanceof LocationAwareLogger) { locationAwareLogger = (LocationAwareLogger) slf4jLogger; } } }
从上面能够看到简化版中的Logger内部是使用slf4j的API来生成的,因此咱们使用的简化版的Logger会委托给slf4j来进行输出,因为当前类路径下有logback-classic,因此slf4j会选择logback进行输出。从而实现了log4j到logback的日志切换。
下面的内容就只讲解日志系统到slf4j的切换,再也不讲解slf4j选择何种日志来输出
##4.2 jdk-logging无缝切换到logback
###4.2.1 案例
private static final Logger logger=Logger.getLogger(JulSlf4jLog4jTest.class.getName()); public static void main(String[] args){ logger.log(Level.INFO,"jul info a msg"); logger.log(Level.WARNING,"jul waring a msg"); }
能够看到上述是使用jdk-logging自带的API来进行编程的,如今咱们想这些日志交给logback来输出
解决办法以下:
第一步:加入如下jar包:
第二步:在类路径下加入logback的配置文件
第三步:在代码中加入以下代码:
static{ SLF4JBridgeHandler.install(); }
###4.2.2 切换原理
先来看下jul-to-slf4j jar包中的内容:
咱们看到只有一个类:SLF4JBridgeHandler
它继承了jdk-logging中定义的java.util.logging.Handler,Handler是jdk-logging处理日志过程当中的一个处理器(具体我也没仔细研究过),在使用以前,必需要提早注册这个处理器,即上述的SLF4JBridgeHandler.install()操做,install后咱们就能够经过这个handler实现日志的切换工做,以下:
protected Logger getSLF4JLogger(LogRecord record) { String name = record.getLoggerName(); if (name == null) { name = UNKNOWN_LOGGER_NAME; } return LoggerFactory.getLogger(name); }
在处理日志的过程当中,使用了slf4j的原生方式LoggerFactory来获取一个slf4j定义的Logger来进行日志的输出
而slf4j则又会选择logback来进行实际的日志输出
##4.3 commons-logging切换到logback
###4.3.1 使用案例
使用的jar包
案例以下:
private static Log logger=LogFactory.getLog(JulJclTest.class); public static void main(String[] args){ if(logger.isTraceEnabled()){ logger.trace("commons-logging-jcl trace message"); } }
能够看到咱们使用commons-logging的API来进行日志的编程操做,如今想切换成logback来进行日志的输出(这其实就是commons-logging与logback的集成)
解决办法以下:
第一步:去掉commons-logging jar包(其实去不去都无所谓)
第二步:加入如下jar包:
第三步:在类路径下加入logback的配置文件
###4.3.2 切换原理
这个原理以前都已经说过了,能够看下commons-logging与logback的集成
就是commons-logging经过jcl-over-slf4j 来选择slf4j做为底层的日志输出对象,而slf4j又选择logback来做为底层的日志输出对象。
##4.4 经常使用的日志场景切换解释
上面把日志的切换原理说清楚了,下面就针对具体的例子来进行应用
先来看下slf4j官方的一张图:
下面分别详细说明这三个案例
###4.4.1 左上图
现状:
目前的应用程序中已经使用了以下混杂方式的API来进行日志的编程:
如今想统一将日志的输出交给logback
解决办法:
第一步:将上述日志系统所有无缝先切换到slf4j
第二步:使slf4j选择logback来做为底层日志输出
加入如下jar包:
下面的2张图和上面就很相似
###4.4.2 右上图
现状:
目前的应用程序中已经使用了以下混杂方式的API来进行日志的编程:
如今想统一将日志的输出交给log4j1
解决办法:
第一步:将上述日志系统所有无缝先切换到slf4j
第二步:使slf4j选择log4j1来做为底层日志输出
加入如下jar包:
###4.4.3 左下图
现状:
目前的应用程序中已经使用了以下混杂方式的API来进行日志的编程:
如今想统一将日志的输出交给jdk-logging
解决办法:
第一步:将上述日志系统所有无缝先切换到slf4j
第二步:使slf4j选择jdk-logging来做为底层日志输出
加入如下jar包:
#5 冲突说明
仍然是这里的内容slf4j官网的冲突说明
其实明白上面介绍的各jar包的做用,就很容易理解
##5.1 jcl-over-slf4j 与 slf4j-jcl 冲突
jcl-over-slf4j: commons-logging切换到slf4j
slf4j-jcl : slf4j切换到commons-logging
若是这二者共存的话,必然形成相互委托,形成内存溢出
##5.2 log4j-over-slf4j 与 slf4j-log4j12 冲突
若是这二者共存的话,必然形成相互委托,形成内存溢出。可是log4j-over-slf4内部作了一个判断,能够防止形成内存溢出:
即判断slf4j-log4j12 jar包中的org.slf4j.impl.Log4jLoggerFactory是否存在,若是存在则表示冲突了,抛出异常提示用户要去掉对应的jar包,代码以下,在slf4j-log4j12 jar包的org.apache.log4j.Log4jLoggerFactory中:
##5.3 jul-to-slf4j 与 slf4j-jdk14 冲突
若是这二者共存的话,必然形成相互委托,形成内存溢出
#6 结束语
至此,这个日志系列就算终于完成了。它注重于日志系统之间的交互与集成,因此想深刻研究单个日志系统的架构的话,就须要各位自行去深刻研究了。
欢迎关注微信公众号:乒乓狂魔