由客户现场引发的思考

平时项目使用日志功能,找一个常用的拿来用就可以了.最近两周用户现场的问题,搞得我一头包,发现两个必须在项目与产品上十分重视的地方:日志+异常处理。

首先说日志,用户现场出现的问题一般不容易重现出来,如果很容易重现,说明起初的测试并不过关。那么日志是唯一真实的信息来源。客户以及现场支持的人员反馈的信息某些时候会产生误导作用。如果这个时候日志不给力,那时你才知道什么叫举目无亲。

这一次现场的日志有部分日志输出出现了问题,只有异常信息,连堆栈都没有打出来,确认不了这些日志到底从哪里打出来的,为什么在那里catch了这个异常。么办法了。

在说异常,异常处理从来都是项目与产品中处理起来最让人头疼的事情,哪些异常应该捕获,捕获后如何处理,如果需要输出日志,输出什么级别的日志呢。那些异常必须抛出,抛出动作什么时候停止.等等。

再说此次现场问题。项目中有些异常属正常情况,比较实然Socket中断,IO读取出错等,都属于比较正常的异常,捕获并输出FINE级别日志是可以的。但有些线程捕获力度偏大,比如catch throwable,即便是OOM,也无法出局。更给力的是,这时输出的日志居然是FINE级别。

在生产环境上没有把日志启为FINE级别的,这些日志当然就出不来了。最终系统不断出错,日志文件无反应。

为了下一阶段改进日志系统,发现大多数开源产品Geronimo,mina等都采有SLF4J。决定深入了解一下。

SLF4J(Simple Logging Facade for Java)是一个通用的日志门面库,为各种Log实现提供了一套通用的日志接口。SLF4J会根据classpath中所存在的适配器jar来决定将使用的日志实现库。

这样就完成了动态的修改系统日志的实现框架。

比如我们常用的log4j,如果我们的项目采用SLF4J+Log4j构建日志输出,则需要三个JAR文件:

1.slf4j-api-1.6.4.jar

2.slf4j-log4j12-1.6.4.jar

3.log4j-1.2.13.jar

slf4j-api-1.6.4.jar是Slf4j是Slf4j的接口,也是我们项目编译需要依赖的JAR文件。而slf4j-log4j12-1.6.4.jar就是上面说到适配器的jar。log4j-1.2.13.jar不用说了,log4j的JAR文件。

其实slf4j-api-1.6.4.jar非常简洁,相信你几个小时或更短的时间内就能读完他的代码,20个类而已(目前好像是23个)。

那么SLF4J是如何根据classpath中所存在的适配器jar来决定将使用的日志实现库。其实每一个适配器jar里都含有一个特殊的类:Org.slf4j.impl.StaticLoggerBinder.class。实现LoggerFactoryBinder接口:

public interface LoggerFactoryBinder {

public ILoggerFactory getLoggerFactory();

public String getLoggerFactoryClassStr();

}

他是一个饿汉式的单例类,也就是通过该类的getLoggerFactory方法获得实现日志(这里指log4j)的ILoggerFactory,然后再通过ILoggerFactory获得log4j的相应的Logger.多个熟悉的名字,这样就完成了Slf4j与Log4j的姻缘。

SLF4J首先在classpath中寻找Org.slf4j.impl.StaticLoggerBinder.class,如果找到则结对成功。

如果找到多个StaticLoggerBinder,则会提示用户应只保留一个(Class path contains multiple SLF4J bindings)。

一些与Slf4j关系比较昧的日志实现,自身实现了适配器,比如目前比较火的logback。配置logback日志就只需要两个JAR:slf4j-api-1.6.4.jar,虚拟主机,logback1.0.3.jar。属于此类的一般晚于Slf4j开发。目前未发现哪个日志实现主动弥补适配器这一缺口的。而且Log4j,slf4j,logback都是同一作者。

最后推荐几个logback的源码分析文章。

关于异常处理总结了几条:

1.不处理的异常不捕获。前天有个同事这样写:

Try{// some op

} catch(IOException e){

Throw e;

}

这是个不好的习惯。除非想只抛出IOException,免备案空间,其他异常不抛出的情况下考虑这样做。

2. VirualMachineError.

3.没有必要的信息附加时,不要包装原始的异常.

除非做异常转换,比如checkException转化为uncheckException

4. 一般情况不捕获Exception,香港服务器,因为这样有可能吃掉RuntimeException异常。

5. 异常日志输出一次。一个异常只在一个合适的地方输出。一方面代码简洁,另一方面方便定位问题。

本文出自 “天下无贼” 博客,请务必保留此出处

让我们将事前的忧虑,换为事前的思考和计划吧!

由客户现场引发的思考

相关文章:

你感兴趣的文章:

标签云: