龙空技术网

知识总结-大型Java项目打印日志log的时机、原则

Hi老杨 1024

前言:

现在姐妹们对“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 日志输出规范