• Java日志设计&实践(3)



    1.选择恰当的日志级别
    2.输出明确的提示文字和充分的现场信息
    3.输出内容一行搞定,不要换行
    4.其他

    1.选择恰当的日志级别



    选择日志级别时需要遵循一些通用规范,不可随意定义

    log4j的日志级别,由低到高排列:all trace debug info warn error fatal off
    其中,all off仅用以log4j配置文件中开启或关闭所有日志,trace fatal一般也用不到
    对于开发人员来说,只需要关注debug info warn error

    debug
        正常情况下不需要输出,只有当出问题时才需要输出的日志信息,由于生产环境无法单步调试,可以把debug级别的日志想象成你在生成环境中debug
    info
        可能要关注或者只有比较重要的信息才需要输出,如:用户登录、退出、后台job执行时长等
    warn
        存在一些潜在的危险时输出的日志,比如:请求参数中包含攻击注入脚本
    error
        如:请求数据库时的SQL异常

    当然,最好的方法还是参考优秀的开源代码
       

    2.输出明确的提示文字和充分的现场信息


    要点:
    1)明确的提示文字,看到这段提示文本就可以知道发生了什么,不需要再去扒拉源码
    2)充分的现场信息,如:用户信息、引发异常的参数值、异常栈信息等

    举例:
    LOG.warn("Unknown value for includeParams parameter to URL tag: " + includeParams);
    LOG.warn("Unable to put request parameters (" + extractQueryString() + ") into parameter map.", e);
    LOG.warn("Could not find token mapped to token name " + tokenName);

    3.一条日志一行搞定


    这个是为了方便跟踪和分析日志,使用grep命令时不至于仅看到一条日志的部分内容

    4.其他

    4.1.尽量使用一套日志接口,强烈推荐slf4j


    两大理由:
    1)使用{}占位符,避免字符串拼接

    以刚才三个log为例
    LOG.warn("Unknown value for includeParams parameter to URL tag: " + includeParams);
    LOG.warn("Unable to put request parameters (" + extractQueryString() + ") into parameter map.", e);
    LOG.warn("Could not find token mapped to token name " + tokenName);

    如果改用slf4j的话,写法如下:
    log.warn("Unknown value for includeParams parameter to URL tag: {}", includeParams);
    log.warn("Unable to put request parameters ({}) into parameter map.", extractQueryString(), e);
    log.warn("Could not find token mapped to token name {}", tokenName);


    2)执行实际日志输出前强制检查log是否开启

    组合使用log4j+slf4j时,执行的warn方法实际是这样的:
      public void warn(String format, Object arg) {
        if (logger.isEnabledFor(Level.WARN)) {
          FormattingTuple ft = MessageFormatter.format(format, arg);
          logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable());
        }
      }

    4.2.不要使用System.out.println()


    这个就不多说了,日志中看到一句莫名其妙hello,world你会怎么想,怎么查????

    4.3.不要使用e.printStackTrace()


    这种打印只能输出到catalina.out中,无法单独制定输出目的文件,还会导致日志输出混乱

    4.4.slf4j打印异常堆栈信息


    两个例子:

    try { 
        if (true) { 
            throw new RuntimeException("i'm ok"); 
        } 
    } catch (Exception e) { 
        log.error("Error. param:{}, param2:{}, param3:{}", param, param2, param3, e); 
    }

    将打印:
    ERROR 2015-01-17 15:11:51,426 Error. param:0, param2:2, param3:false [cn.xxt.log.test.Slf4jTest.main(Slf4jTest.java:36)]
    java.lang.RuntimeException: i'm ok
        at cn.xxt.log.test.Slf4jTest.main(Slf4jTest.java:33) 
       
    try { 
        if (true) { 
            throw new RuntimeException("i'm sorry"); 
        } 
    } catch (Exception e) { 
        log.error("Error. param:{}, param2:{}, param3:{}, {}", param, param2, param3, e); 
    }

    将打印:
    ERROR 2015-01-17 15:11:51,429 Error. param:0, param2:2, param3:false, java.lang.RuntimeException: i'm sorry [cn.xxt.log.test.Slf4jTest.main(Slf4jTest.java:44)]

    差异:前者输出了异常栈信息,后者没有
    原因:后者用{}占位符打印异常对象e,导致异常栈信息没有输出

    参考文档


    为什么要使用SLF4J而不是Log4J
    http://www.importnew.com/7450.html

  • 相关阅读:
    Gist
    Gist
    Gist
    汉字编码与其16进制对照
    Horizon组件安装详解
    Github目录生成器
    MVC模式网站编写经验总结
    Java多线程小结
    JGit与远程仓库链接使用的两种验证方式(ssh和https)
    Peterson算法与Dekker算法解析
  • 原文地址:https://www.cnblogs.com/xxt-mov/p/4230535.html
Copyright © 2020-2023  润新知