对于开发和调试以及上线运营,日志必不可少,常用日志工具有:Log4j、commons-logging、甚至System.out。
这里用Log4j为例,说说如何将日志输出和业务代码做到最大分离。
Log4j 一般使用方法:
1.定义配置文件:log4j.properties
2.在需要输出日志的类里获取Logger实例:static Logger logger = Logger.getLogger(AAA.class);
3.输出日志:logger.debug("xxx");
大家这么做都已经轻车熟路了,但是这样做有两个问题:
1.每个需要输出日志信息的类里,都要引入log4j的包,都要定义一个Logger实例。
2.如果一旦系统由log4j改为别的日志输出方式,如System.out 或commons-logging,则要修改N多个类的代码。
以上两点,使得业务代码和log4j的耦合太大。所以,如果我们能将日志输出定义为一个静态工具方法,改变这种情况。
定义一个静态工具类:
1 import org.apache.log4j.Logger ; 2 public class Logs{ 3 private static Logger logger = Logger.getLogger(Logs.class); 4 //debug方法,其他error、warn类似定义 5 public static void debug(Object obj){ 6 //如果更改日志输出工具,只需修改该行代码即可。如:可改为 System.out.println(obj); 7 logger.debug(obj); 8 } 9 }
这样我们就可以在其他类里用直接 Logs.debug("xxx"); 进行日志输出了。
而且,一旦我们改变了日志输出工具,只要修改 Logs类即可,其他业务类不必修改。
也许很多人也都能想到这么做,同时也有很多人会意识到这么做带来的另一个问题:源代码定位。
Log4j的日志信息,能够进行源代码定位——也就是说,能够在日志信息中输出,调用日志的类、方法及代码所在的行。
而当我们按上面方法改为静态输出后,就不能进行源代码定位了——虽然仍有源代码信息,但都是指向了Logs类。
这对程序员调试,以及跟踪、解决问题都不方便了。
不过既然Log4j能做到源代码定位,相信我们也会有办法做到,如果您有兴趣请继续看:
Log4j能准确捕获源代码的所在的类、方法、行。但java并没有提供响应的方法,这似乎很神奇。
上网搜一下 “Log4j 行号” 已经有高人指出:Log4j是通过java错误堆栈来实现的,也就是说通过new一个异常Throwable,然后再捕获,从而得到堆栈信息,在进行分析就可以得到行号等了。
所以,有人提出像log4j那样,抛出一个异常,然后捕获分析,从而在我们自己的静态日志工具里实现源代码定位,但是这样就多抛出一次异常,效率肯定低了。
而且抛出异常过多,引起额外事故也是个重大问题。
不管怎么说,这毕竟是一个思路,我尝试着找其他能得到堆栈信息的方法,最后在Thread类里找到了一个getStackTrace();
我没有深入研究,但感觉用这个方法得到堆栈应该比抛出异常好多了。
于是我对静态日志工具类,进行了一番改造,自我感觉还是不错的,下面贴出源码,欢迎讨论。
说明:该类有main方法以供测试。