java中日志打印规范

日志的用途

不管是使用何种编程语言,日志输出几乎无处不在,总结起来,日志大概有以下几种用途:

  • 问题跟踪:通过日志可以追踪程序的一些bug,也在可以在安装配置时,可以及时发现问题。
  • 状态监控:通过实时分析日志,可以监控系统的运行状态,做到早发现问题,早处理问题,
  • 安全审计:审计主要体现在安全方面上,通过日志进行分析,可以发现是否存在非授权的操作,
    日志是程序员们追踪错误的好帮手,但是平常日志记录又没有什么规范,我们日志应该什么时候打,打印什么内容的日志。
    日志对于程序员们来说是非常重要的工具,它可以帮助我们追踪错误信息、监控程序运行状态以及诊断问题。为了让日志更加有效,我们可以遵循一些基本的日志记录规范。
  1. 日志级别:为日志设置不同的级别,例如:DEBUG、INFO、WARNING、ERROR和CRITICAL。这样,在不同情况下,可以方便地过滤和查看相关地日志。
  2. 日志内容:日志应当包含足够的上下文信息,便于诊断问题、例如,记录请求参数、用户ID、操作类型、时间戳等。同时,也要注意保护敏感信息,避免泄露。
  3. 结构化日志:使用结构化的日志格式(JSON),以便于后期日志分析和处理。
  4. 日志记录时机:
    • DEBUG:用于开发阶段,记录详细地程序运行信息,有助于发现潜在问题。
    • INFO:记录程序运行的关键节点信息,如程序启动、关闭、配置文件加载、关键操作等;
    • WARNING:记录一些非致命性问题,如临时性错误、资源不足等,可能需要关注但不会导致 程序中断。
    • ERROR:记录程序中的错误,如异常、错误的输入参数等,可能会导致程序无法正常运行。
    • CRITICAL:记录严重的错误,如数据丢失、系统奔溃等,需要立即处理。
  5. 日志记录原则
  • 保持日志简介明了,避免冗余信息;
  • 适当地使用日志级别,以便快速定位问题;
  • 遵循团队或项目地日志规范,保持一致性。
  1. 日志轮转与归档:根据日志地大小、事件或其他条件,定期轮转和归档日志文件,避免单个日志文件过大,影响系统性能。

遵循这些基本规范,可以让我们更有效地利用日志,提高工作效率。

日志打印优化

  1. 选择恰当的日志级别
    日常开发中常见日志级别有:trace、debug、info、warn、error(级别依次增大)
  • trace:最详细的日志信息,一般记录到日志文件中;
  • debug:一般用于开发中Debug的关键逻辑的运行时数据;
  • info:记录排查问题的关键信息,如出参、入参等;
  • warn:警告日志,一般的错误,对正常业务影响不大需要开发者关注;
  • error:错误日志,对正常业务有影响,需要运维配置日志监控。
  1. 日志要打印方法的入参和出参
    例如在Controller层,请求入参、响应出参和响应异常,一般需要打印日志,出问题时,方便追踪代码逻辑运行的路线,建议这里使用日志切面统一日志打印,
    其他层级的方法入参和出参,如有必要,可以打印整个出参和入参的数据,繁殖可以打印有效的关键日志,方便问题定位即可。
  2. 日志格式
    一般日志中包含时间、日志级别、线程名称、日志具体内容;
  3. 在多个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
}
  1. 日志级别比较低时,进行日志开关判断
    对于trace、debug级别的日志打印,需要进行开关判断
if (log.isTraceEnabled()) {
    log.trace("trace log detail......");
}
if (log.isDebugEnabled()) {
    log.debug("debug log detail......");            
}
  1. 不要直接使用日志系统(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
  1. 建议使用参数占位{},而不是用+拼接
log.debug("Payment processing,requestNo=" + requestNo + ",channel=" + channel);

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

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

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

  1. 不要使用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);
  1. 禁止在线上环境开启debug
    一般业务系统的debug日志较多,引入的第三方框架dubug日志也较多,随着业务交易的增多,容易占用磁盘空间,最后可能会影响正常业务系统的运行,所以生产环境禁止开启dubug。
  2. 不要既打印了异常日志,又抛出异常
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)即可。

  1. 避免重复打印日志
    如果一次日志可以表达清楚,,则使用一次打印即可,避免日志信息冗余。
    反例:
log.info("创建用户信息 userId={}", userId);
log.info("创建用户信息 userName={}", userName);

正例:

log.info("创建用户信息 userId={},userName={}", userId, userName);
  1. 日志文件分离
    根据不同的日志级别,打印在不同的日志文件中,例如deug、info、error日志级别的日志分别创建一个日志文件debug.log、info.log、warn.log、error.log.
  2. 核心功能模块,建议打印较完整地日志
    业务系统中,核心功能地代码,尽可能打印日志完整,核心代码执行频率极高,出问题时,根据日志信息能够快速定位。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值