zoukankan      html  css  js  c++  java
  • java中日志打印规范

    1.选择恰当的日志级别

    日常开发中常见日志级别有:trace、debug、info、warn、error(级别依次增大):
    1.trace:最详细的日志信息,一般记录到日志文件中
    2.debug:一般用于开发中DEBUG的关键逻辑的运行时数据
    3.info:记录排查问题的关键信息,如出参,入参等
    4.warn:警告日志,一般的错误,对正常业务影响不大,需要开发者关注
    5.error:错误日志,对正常业务有影响,需要运维配置日志监控

    2.日志要打印方法的入参和出参

    例如在Controller层,请求入参、响应出参和响应异常,一般需要打印日志,出问题时,方便追踪代码逻辑运行的路线。建议这里使用日志切面进行统一日志打印;

    其他层级的方法入参和出参,如有必要,可以打印整个出参和入参的数据,反之可以打印有效的关键日志,方便问题定位即可;

    3.日志格式

    一般日志中包含:时间、日志级别、线程名称、日志具体内容等

    %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger:%line - %msg%n

    4.在多个if-else等条件时,每个分支首行尽量打印日志

    可以在进入分支前打印日志,后续可以快速定位到进入了哪个分支,方便排查问题

    String requestNo = "RN7195458555001";
    String channel = "weixin";
    log.info("请求流水号[{}]支付处理,渠道为:{}", requestNo, channel);
    if (Objects.equals("zhifubao", channel)) {
        // TODO
    } else if (Objects.equals("yinlian", channel)) {
        // TODO
    } else if (Objects.equals("weixin", channel)) {
        // TODO
    } else {
        // TODO
    }

    5.日志级别比较低时,进行日志开关判断

    对于trace、debug级别的日志打印,需要进行开关判断

    if (log.isTraceEnabled()) {
        log.trace("trace log detail......");
    }
    if (log.isDebugEnabled()) {
        log.debug("debug log detail......");            
    }

    比如需要打印如下日志

    log.debug("Payment processing,requestNo=" + requestNo + ",channel=" + channel);

    当前配置的日志级别为info,则上面日志不会打印,但会进行字符串拼接;如果是对象,还会执行toString()方法,浪费了系统资源

    6.不要直接使用日志系统(Log4j、Logback)中的 API,而是使用日志框架SLF4J中的API

    SLF4J是门面模式的日志框架,需要更换日志框架实现时,在不改动代码的情况下,可以方便切换到不同的日志实现框架

    import org.slf4j.Logger; 
    import org.slf4j.LoggerFactory;
    
    private static final Logger logger = LoggerFactory.getLogger(Demo.class);

    // 或者使用Lombok @Slf4j

    7.建议使用参数占位{},而不是用+拼接

    反例:

    log.debug("Payment processing,requestNo=" + requestNo + ",channel=" + channel);

    字符串使用"+"进行拼接操作,会有一定的性能损耗,虽然高版本的jdk对字符串拼接进行了性能优化,但不建议使用

    正例:

    log.info("Payment processing,requestNo={},channel={}", requestNo, channel);

    使用大括号{}进行占位符的替换,相比字符串拼接,性能上更高,日志代码也更加优雅

    8.不要使用e.printStackTrace() 和 System.out.println();

    反例:

    try{
      // TODO 业务代码处理
    }catch(Exception e){
     //System.out.println("xxx业务处理异常,异常信息:" + e); e.printStackTrace(); }

    正例:

    try {
        // TODO 业务代码处理
    } catch (Exception e) {
        log.error("xxx业务处理异常 requestNo={}", requestNo, e);
    }
    e.printStackTrace()打印在堆栈信息中,如果异常过多,会导致堆栈内存不足,出现卡(运行极慢)的现象,最后出现OOM,这是一种非常糟糕的现象;
    使用log来打印日志会记录到日志文件中,占用的是磁盘内存,一般不会经常出现卡(运行极慢)的现象,但如果磁盘内存占用比较高时,需要对日志进行备份处理,然后清理日志;

    9.异常日志不要只打一半,要输出全部错误信息

    反例:

    log.error("xxx业务处理异常");
    log.error("xxx业务处理异常", e.getMessage());

    e.getMessage()不会记录详细的堆栈异常信息,只会记录错误基本描述信息,不利于排查问题。

    正例:

    log.error("xxx业务处理异常 requestNo={}", requestNo, e);

    10.禁止在线上环境开启 debug

    一般业务系统的debug日志较多,引入的第三方框架debug日志也较多,随着业务交易的增多,容易占用磁盘内存空间,最后可能会影响正常业务系统的运行

    ,所以生产环境禁止开启debug

    11.不要既打印了异常日志,又抛出异常

    try {
        // TODO 业务代码处理
    } catch (Exception e) {
        log.error("xxx业务处理异常", e);
        // BusinessException:自定义业务处理异常类
        throw new BusinessException("xxx业务处理异常", e);
    }

    此处会打印两次异常日志:

    第一次是log.error("xxx业务处理异常", e)会打印一次;
    第二次是throw new BusinessException("xxx业务处理异常", e)会打印一次;

    可以根据具体情况来选择,例如此处就应该抛异常处理,那么可以仅使用throw new BusinessException("xxx业务处理异常", e)即可

    12.避免重复打印日志

    如果一行日志可以表达清楚,则使用一行打印即可,避免日志信息冗余

    反例:

    log.info("创建用户信息 userId={}", userId);
    log.info("创建用户信息 userName={}", userName);

    正例:

    log.info("创建用户信息 userId={},userName={}", userId, userName);

    13.日志文件分离

    根据不同的日志级别,打印在不同的日志文件中,例如debug、info、warn、error日志级别的日志分别创建一个日志文件debug.log、info.log、warn.log、error.log进行日志打印;

    将不同类型的日志进行日志分类,例如access.log、error.log等

    14.核心功能模块,建议打印较完整的日志

    业务系统中,核心功能的代码,尽可能打印日志完整,核心代码执行频率极高,出问题时,根据日志信息能快速定位。

  • 相关阅读:
    在react-native中使用es7语法中的decorator装饰器
    chrome从版本55开始,不再支持设置网页内容编码
    react-native 获取组件的宽度和高度
    手动安装Android Support Library(23.0.1)
    ubuntu 14.04 git clone 出现 fatal: Unable to find remote helper for 'https'
    React-Native 在android写不支持gif的解决方案!
    游戏大世界场景(胡诌篇)
    多线程先判断再操作免锁设计方案
    Mysql语句优化
    JVM GC Q&A(补充ing)
  • 原文地址:https://www.cnblogs.com/lwcode6/p/15527912.html
Copyright © 2011-2022 走看看