标签:
一个在生产环境里运行的程序如果没有日志是很让维护者提心吊胆的,有太多杂乱又无意义的日志也是令人伤神。程序出现问题时候,从日志里如果发现不了问题可能的原因是很令人受挫的。本文想讨论的是如何在Java程序里写好日志。
一般来说日志分为两种:业务日志和异常日志,使用日志我们希望能达到以下目标:
Java的日志框架太多了。。。
选项太多了的后果就是选择困难症,我的看法是没有最好的,只有最合适的。在比较关注性能的地方,选择Logback或自己实现高性能Logging API可能更合适;在已经使用了Log4j的项目中,如果没有发现问题,继续使用可能是更合适的方式;我一般会在项目里选择使用Slf4j, 如果不想有依赖则使用java.util.logging或框架容器已经提供的日志接口。
日志变量往往不变,最好定义成final static,变量名用大写。
Java的日志框架一般会提供以下日志级别,缺省打开info级别,也就是debug,trace级别的日志在生产环境不会输出,在开发和测试环境可以通过不同的日志配置文件打开debug级别。
在程序里要合理使用日志分级:
1 LOGGER.debug("entering getting content"); 2 String content =CacheManager.getCachedContent(); 3 if(content == null){ 4 5 //使用warn,因为程序还可以继续执行,但类似警告太多可能说明缓存服务不可用了,值得注意 6 LOGGER.warn("Got empty content from cache,need perform database lookup"); 7 8 Connection conn = ConnectionFactory.getConnection(); 9 if (conn=null) { 10 LOGGER.error("Can‘t get database connection, failed to return content");//尽量提供详细的信息,知道错误的原因,而不能简单的写logger.error("failed") 11 }else{ 12 try{ 13 content = conn.query(...); 14 }catch ( IOException e ){ 15 //异常要记录错误堆栈 16 LOGGER.error("Failed to perform database lookup", e ); 17 }finally{ 18 ConnectionFactory.releaseConnection(conn); 19 } 20 } 21 } 22 //调试的时候可以知道方法的返回了 23 LOGGER.debug("returning content: "+ content); 24 return content;
1.在一个对象中通常只使用一个Logger对象,Logger应该是static final的,只有在少数需要在构造函数中传递logger的情况下才使用private final。
static final logger_LOG=loggerFactory.getLogger(Main.class);
2.输出Exceptions的全部Throwable信息,因为logger.error(msg)和logger.error(msg,e.getMessage())这样的日志输出方法会丢失掉最重要的StackTrace信息。
void foo(){ try { // do something... }catch ( Exception e ){ _LOG.error(e.getMessage()); // 错误 _LOG.error("Bad things : ",e.getMessage()); // 错误 _LOG.error("Bad things : ",e); // 正确 } }
3.不允许记录日志后又抛出异常,因为这样会多次记录日志,只允许记录一次日志。
void foo() throws LogException{ try{ // do something... }catch ( Exception e ){ _LOG.error("Bad things : ", e); throw new LogException("Bad things : ",e); } }
4.不允许出现System print(包括System.out.println和System.error.println)语句。
void foo() { try{ // do something... }catch( Exception e ){ System.out.println(e.getMessage()); // 错误 System.err.println(e.getMessage()); // 错误 _LOG.error("Bad things : ",e ); // 正确 } }
5.不允许出现printStackTrace。
void foo() { try { // do something... }catch ( Exception e ) { e.printStackTrace(); // 错误 _LOG.error("Bad things : ", e ); //正确 } }
6.日志性能的考虑,如果代码为核心代码,执行频率非常高,则输出日志建议增加判断,尤其是低级别的输出<debug、info、warn>。
debug日志太多后可能会影响性能,有一种改进方法是:
if (LOGGER.isDebugEnabled ()) { LOGGER.debug("returning content: "+ content); }
但更好的方法是Slf4j提供的最佳实践:
LOGGER.debug("returning content: {}", content);
一方面可以减少参数构造的开销,另一方面也不用多写两行代码。
7.有意义的日志
通常情况下在程序日志里记录一些比较有意义的状态数据:程序启动,退出的时间点;程序运行消耗时间;耗时程序的执行进度;重要变量的状态变化。
除此之外,在公共的日志里规避打印程序的调试或者提示信息。
FAQ:参考
1.7 Good Rules to Log Exceptions
标签:
原文地址:http://www.cnblogs.com/beatIteWeNerverGiveUp/p/5755864.html