前言:
现在姐妹们对“java 日志输出规范”可能比较重视,同学们都想要分析一些“java 日志输出规范”的相关文章。那么小编同时在网上网罗了一些关于“java 日志输出规范””的相关资讯,希望看官们能喜欢,你们快快来学习一下吧!为什么打印
通过打印日志可以了解系统当前的运行状况以及定位线上问题,所以日志打印的时机非常重要。日志打印过多,会导致日志内容过多,影响问题定位的效率和系统性能;日志打印过少缺少关键日志,导致不能在线上定位问题。因此把握日志打印的时机至关重要。
打印日志的时机
1)程序入口、出口(http或者rpc)
在程序调用其他服务或者系统的时候,需要打印接口调用参数、调用结果(成功/失败)、返回结果明细、RT。便于统计和问题排查。
2)程序异常
在程序出现异常的时候,要么选择向上抛出异常,要么必须在catch块中打印异常堆栈信息。有个需要特别注意的地方最好不要重复打印异常日志,比如在catch块里既向上抛出了异常,又去打印错误日志。大量打印堆栈会占用较多的资源。
3)条件分支
程序进入到一些特殊的条件分支时,比如特殊的else或者switch分支。必须打印程序走的流程
public double calcMoneyByAge(int age) {
if (age < 0) {
//理论上年龄不可能小于0,所以需要打印出这种非预期情况或者抛出异常。
logger.("错误的年龄, age:{}", age);
return 0;
}
// ..
}
4)关键执行路径及中间状态
在一些关键的执行路径以及中间状态也需要记录下关键日志信息,比如一个算法可能分为很多步骤,每个步骤的中间输出结果是什么,需要记录下来,以方便后续定位跟踪算法执行状态。
5)调用服务
尤其是写数据的服务,在调用其他服务的请求参数、结果、耗时必须记录。
日志内容与格式
日志打印时机决定了能够根据日志去进行问题定位,而日志的内容决定了是否能够根据日志快速找出问题原因。通常来说,一行日志应该至少包括以下几个组成部分:日志分类标记(场景或者原因)、调用参数(param)、异常堆栈。
话不多说,下面介绍项目中该如何正确的打日志
正确的定义日志
1、使用参数化形式{}占位,[] 进行参数隔离 LOG.debug("Save order with order no:[{}], and order amount:[{}]");
2、输出不同级别的日志 项目中最常用有日志级别是ERROR、WARN、INFO、DEBUG。
几个错误的打日志方式
1、不要使用 System.out.print..
必须通过日志框架来输出日志,而不能使用 System.out.print… 来打印日志,因为这个会打印到 tomcat 控制台,而不会记录到日志文件中,不方便管理日志,会造成磁盘占满、不能查找等问题。
2、不要使用 e.printStackTrace()
它其实也是利用 System.err 输出到了 tomcat 控制台。
3、不要抛出异常后又输出日志
如捕获异常后又抛出了自定义业务异常,此时无需记录错误日志,由最终捕获方进行异常处理。否则会造成重复输出日志。
try {
// ...
} catch (Exception e) {
// 错误
LOG.error("xxx", e);
throw new RuntimeException();
}
4、没有输出全部错误信息
看以下代码,这样不会记录详细的堆栈异常信息,不利于排查问题。
try {
// ...
} catch (Exception e) {
// 错误
LOG.error('XX 发生异常', e.getMessage());
// 正确
LOG.error('XX 发生异常', e);
}
5、使用错误的日志级别
曾经在线上定位一个问题,明明输出了日志啊,为什么找不到…后来排查发现,是这样的:
try {
// ...
} catch (Exception e) {
// 错误
LOG.info("XX 发生异常...", e);
//用 info 记录 error 日志,线上打印ERROR级别的日志,肯定找不到,而且会大量占用性能
}
6、不要在千层循环中打印日志
不要在上千个 for循环中打印日志,这样可能会拖垮你的应用程序,或者严重影响性能。
for(int i=0; i<2000; i++){
LOG.info("XX");
LOG.info(JSON.toJson(obj));
}
7、高性能应用验证日志级别在打印日志(高并发应用重点)、
if(LOG.isInfoEnabled())
{
LOG.info("....");
LOG.info(JSON.toJson(obj));//如果不提前判断,此处序列化仍然执行,但是日志中不输出
}
标签: #java 日志输出规范