打日志 也能更高效?

560 阅读3分钟

背景:mentor 在cr别人代码的时 发现有一句打印日志的代码

log.info("xxxxx {}",xxx.toString());

mentor 提示这边需要注意效率问题info级别跟系统打印日志级别相同 toString()方法一定会执行,但是如果为debug级别toString()方法会执行但是日志不会打印造成效率问题。

深入:

review代码时,发现太多人习惯log日志直接用“+”号连接。这是很不好的习惯。

In Logger, the logging methods are overloaded with forms that accept one, two or more values.[9] Occurrences of the simple pattern {} in the log message are replaced in turn with the values. This is simple to use yet provides a performance benefit when the values have expensive toString() methods. When logging is disabled at the DEBUG level, the logging framework does not need to evaluate the string representation of the values. In the following example, the values count or userAccountList only need to be evaluated when DEBUG is enabled; otherwise the overhead of the debug call is trivial.

private static final Logger LOG = LoggerFactory.getLogger(Wombat.class);
LOG.debug("There are now " + count + " user accounts: " + userAccountList); // slow
LOG.debug("There are now {} user accounts: {}", count, userAccountList);    // faster
123

如上面demo,请选择第二种书写方式。 原因1,第二种使用占位符只有当日志级别是debug,才会执行count和userAccountlist的toString方法,而第一种非debug级别也会执行。 原因2,更具可读性。

第一种无论是debug还是其他级别,都会执行输入值的toString方法,第二种只有在debug级别才会执行。

其次使用占用符 和使用string 字符拼接底层都是使用StringBuilder()进行实现。多字符情况下使用占位符效率会稍高。具体选择根据个人喜好。需要注意占位符个数少于传入实参的时候。不会报错,实参进行映射的时候会有一个顺序问题。使用sonarlint插件可以进行扫描避免这个问题。 下面还有一些总结的打印日志的技巧

  1. 日志打印的级别
级别内容
ERROR发生了严重的错误,必须马上处理。这种级别的错误是任何系统都无法容忍的。比如:空指针异常,数据库不可用,关键路径的用例无法继续执行。
WARN还会继续执行后面的流程,但应该引起重视。其实在这里我希望有两种级别:一个是存在解决方案的明显的问题(比如,"当前数据不可用,使用缓存数据"),另一个是潜在的问题和建议(比如“程序运行在开发模式下”或者“管理控制台的密码不够安全”)。应用程序可以容忍这些信息,不过它们应该被检查及修复。
DEBUG开发人员关注的事。后面我会讲到什么样的东西应该记录到这个级别。
TRACE更为详尽的信息,只是开发阶段使用。在产品上线之后的一小段时间内你可能还需要关注下这些信息,不过这些日志记录只是临时性的,最终应该关掉。DEBUG和TRACE的区别很难区分,不过如果你加了一行日志,在开发测试完后又删了它的话,这条日志就应该是TRACE级别的。
  1. 日志内容打印的时候 语义要清楚 可以方便进行错误排查 ,一般在请求方法或者远程调用的时候打印出入参和出参。对于出入参数 使用占位符,同时对于字符串的拼接使用ToStringBuilder(非反射实现) 对于数组 或者集合的打印使用Arrays.deepToString();
  2. 当抛出一个异常的时候 不需要再打印日志,因为这样会重复打印日志。
  3. 打印错误日志异常信息的正确打印方法 log**.error("Error reading configuration file",** e**);**
  4. 日志可读性需要考虑,比如日期格式类的转换。

参考博客

参考博客