TOP生产环境近来频频发生日志遗失风波,上了三拨人去解决,过了一段时间又出现了 ,太怪异了!具体现象如下:
1.有一半的机器日志正常生成,而另一半的机器几乎没有生成日志。
2.在日志遗失的机器上,所有普通logger配置的日志文件都没有生成 ,而rootlogger配置的日志文件却生成了,但是rootlogger只记录了搜索引擎的日志,其它日志信息一个都没有。
同样的机器 ,同样的代码,同样的环境,为何会出现这些问题呢?
要想弄清楚缘由 ,我们还得先来了解JAVA开源世界里的各类日志组件 。
一、日志介绍
1.commons-logging:Apache最早提供的日志店面插口,主要是为了防止程序的代码和具体的实现相耦合。类似于JDBC的API插口,具体的JDBCDriver是由各个数据库提供商来实现的。通过统一插口前馈 ,不过其内部也实现了一些简单的日志方案 。
2.log4j:应用最广泛的一种日志解决方案,主要由Appender,Logger,Pattern,Category等组成,通过log4j.xml或log4j.properties配置文件来实现日志系统的管理和多元化配置。可单独做为日志方案来使用,也可以配合commons-logging插口来使用 ,以达到前馈。
3.slf4j:SimpleLoggerFacadeforJAVA,是继commons-logging后的又一日志店面插口 。与commons-logging的配置加载实现不同,slf4j是通过类加载来感知实现的。slf4j还有一个比较好的特点是 ,可以通过占位符{}来实现日志替换,防止了log.isXXXEnabled这些无耐的判别。
4.logback:log4j作者的又一力作,作为一个通用可靠、快速灵活的日志框架 ,将作为log4j的取代和slf4j组成新的日志系统的完整实现 。官网上称具有绝佳的性能,在关键路径上执行速率是log4j的10倍,且显存消耗更少。
二 、加载次序
1.commons-logging:它是通过LogFactory.getgetFactory()方式依照固定的次序来加载实现类的:
1)首先:通过查找系统变量org.apache.commons.logging.LogFactory的配置值来加载相应的实现(可通过JVM的启动参数来配置)。
2)否则 ,扫描ClassPath路径下的META-INF/services/org.apache.commons.logging.LogFactory文件,通过此文件的第一行配置值来加载实现(jcl-over-slf4j.jar中包含此文件) 。
3)否则,从ClassPath中找寻commons-loggings.properties文件 ,通过上面的配置项org.apache.commons.logging.LogFactory来加载相应的实现。
4)否则,使用默认的配置形式:假如能找到log4j则默认使用log4j实现,假如没有则使用JDK14Logger实现,再没有则使用commons-logging内部提供的SimpleLog实现。
2.slf4j:它是通过LoggerFactory类在编译时绑定的importorg.slf4j.impl.StaticLoggerBinder类加载的 ,任何一种基于slf4j的实现都要有一个这个类。
三、如何使用
1.commons-logging+log4j
这是应用最广泛的日志方案,大部分开源软件都采用了这些方法 。使用此方案只需引入commons-logging和log4j两个jar包,并提供log4j.xml或log4j.properties配置文件即可。代码如下:
1)privatestaticfinalLoglog=LogFactory.getLog(LogTest.class);//推荐使用这些方法
2)privatestaticfinalLoggerlog=Logger.getLogger(LogTest.class);//使用这些方法似乎只须要引入log4j包即可
2.slf4j+logback
此方案性能高 ,使用灵活便捷,可使用默认配置文件,也可以通过加载指定的配置文件。使用此方案须要引入slf4j,logback-core和logback-classic三个jar包 。代码如下:
privatestaticfinalLoggerlogger=LoggerFactory.getLogger(LogTest.class);
3.commons-logging+slf4j+log4j
假如原有的系统中使用的是commons-logging+log4j ,须要迁移到slf4j,则须要使用jcl-over-slf4j桥接包,这个包提供了一个桥接 ,让底层实现是基于slf4j。使用此方案须要引入commons-logging,jcl-over-slf4j,slf4j-log4j和log4j四个jar包。代码和commons-logging+log4j是一样的 。
privatestaticfinalLoglog=LogFactory.getLog(LogTest.class)
四、问题确诊
有了前面的了解,如今来回头看一下日志遗失的问题就便捷了,你会发觉所有的奇特问题背后似乎都是有诱因的。
首先来看一下TOP生产环境中都依赖了什么日志jar包:
-commons-logging
-log4j
-slf4j
-logback(包含org.slf4j.impl.StaticLoggerBinder)
-jcl-over-slf4j(包含META-INF/services/org.apache.commons.logging.LogFactory)
-slf4j-log4j(包含org.slf4j.impl.StaticLoggerBinder)
几乎引入了前面提及的所有日志组件 ,不出问题才怪,如今我们来剖析一下诱因:
系统中依赖了commons-logging,jcl-over-slf4j两个包,按照commons-logging的加载次序可以晓得,只要依赖了jcl-over-slf4j包 ,系统必将被桥接到了slf4j的日志方案上来。愈发悲剧的是,系统中有两个org.slf4j.impl.StaticLoggerBinder实现,因为JVM加载类的随机性 ,整个系统将会出现两种日志方案:
1)commons-logging+slf4j+logback
2)commons-logging+slf4j+log4j
因为TOP系统是采用log4j.xml来配置的,假如系统采用的是1)方案,则似乎没有日志输出;倘若采用的是2)方案 ,则输出正常 。这也就解释了为何会出现“有一半的机器日志正常生成,而另一半的机器几乎没有生成日志”
但还有一个问题难以解释的是:为何被采用1)方案的机器上还有root.log生成,但是上面只有搜索引擎的日志。悉心的朋友可以发觉里面的“使用方法 ”中介绍了可以直接通过log4j的Loggerlog=Logger.getLogger(LogTest.class)来使用 ,果然通过查看搜索引擎的代码发觉上面是直接使用了log4j来记日志的,没有采用commons-logging店面插口,而log4j是认识log4j.xml的 ,再加上搜索引擎的包路径没有被配置成普通的logger,所以搜索引擎的日志会被记录在rootlogger下。这也就解释了哪些会出现“普通的logger没有日志生成,而rootlogger却有日志生成”
五 、如何解决
1)删掉jcl-over-slf4j.jar,采用commons-logging+log4j实现
或则
2)删掉logback.jar ,采用commons-logging+slf4j+log4j实现
还没有评论,来说两句吧...