日志记录是在软件开发过程中经常须要考虑的关键因素。

当产品执行出错时,日志文件一般是我们进行错误分析的首要选择。

并且,在非常多情况下,它们是我们手上唯一能够用来查明发生状况和问题根本原因的信息。

可见。正确记录须要的信息是极其重要的。

下面5条日志规则,让我们能够检查和改进在代码中操作日志记录的方式。

同一时候也请注意。我们既不会讨论怎么配置一个日志引擎,也不会相互比較。

规则1、日志是面向读者的

日志消息不仅要对书写(日志)代码的人有意义,也应该对日志文件的读者有意义。

这似乎是一条非常明显但却常常违背的规则。




1




​ERROR: Save failure - SQLException .....​



举个样例吧。我们来看看以下这条日志信息:




1




​ERROR: Save failure - SQLException .....​



保存什么呢?这条消息在开发人员看来是能说明一些问题的,可是对于正在苦苦查看产品问题的可怜家伙来说,却毫无用处。




1




​RROR: Save failure- Entity=Person, Data=[id=​​​​123​​​​surname=​​​​"Mario"​​​​] - SQLException....​



更合适的信息是这种:




1




​RROR: Save failure- Entity=Person, Data=[id=​​​​123​​​​surname=​​​​"Mario"​​​​] - SQLException....​



这就解释了你想要存储的东西(这里是一个 Person,是一个 JPA 实体)以及这个 Person 实例相关的内容。

请注意相关这个单词,并非指泛泛的全体:我们不应该让无价值的信息使日志文件变得乱糟糟。比方说完整打印全部的实体字段。

通常,实体名字和其逻辑keyword足以识别在表格中的一条记录了。

规则2、匹配日志等级和运行环境

在 Java 系统中提供的全部日志管理工具和引擎都有日志等级(ERROR、INFO……)的概念,这将有可能过滤掉等级过低的消息。

比如,​​Java util logging​​ 使用例如以下的等级:SEVERE、WARN、INFO、FINE、FINER、FINEST(+ CONFIG 和 OFF)。相反,两个最受欢迎的日志管理工具。 ​ ​Apache Commons Logging​ ​ 和 ​​SLFJ​​更倾向于例如以下的等级:FATAL、ERROR、WARN、INFO、DEBUG、TRACE。

日志过滤等级则须要取决于代码的开发阶段:成品与仍处在測试、集成环境下的代码日志等级就不能同样。

更详细的来说,日志等级也应该參考代码的归属情况。

一般而言,我们自己的应用程序代码应该比使用的不论什么第三方开发库拥有更具体的日志记录。

比方说。Apache 的通用调试消息出如今我们的日志文件里,就没有多大意义。

我通常像这样配置日志记录:

  • 成品阶段: 我的代码是 INFO 等级,第三方库是 WARN。
  • 測试、集成阶段:我的代码是 DEBUG 等级,第三方库是 WARN(或者假设须要的话是 INFO)。
  • 开发阶段:不论什么有意义的信息。

注意:个人而言,我不建议使用 TRACE/FINEST 等级(我并非唯一持这样的观点的人。能够參考 ​​这里​​ 的样例)。

我并没有发现 DEBUG 和 TRACE 有多大的差别,而年轻团队的成员经常苦恼于究竟是使用 DEBUG 还是 TRACE 。

依据 KISS 原则。我建议仅仅使用 RROR、WARN、INFO 和 DEBUG 等级。

规则3、提交前去除编码帮助日志

编码时,我们经常会使用 logger 或是 System.out 在代码中加入日志消息,来更好地掌握应用程序在运行、调试期间发生的状况。




1


2


3


4


5




​void​​​​aMethod(String aParam) {​


​LOGGER.debug(“Enter in aMethod”);​


​if​​​​(“no”.equals(aParam)) {​


​LOGGER.debug(“User says no”);​


​….​



比方这种代码:




1


2


3


4


5




​void​​​​aMethod(String aParam) {​


​LOGGER.debug(“Enter in aMethod”);​


​if​​​​(“no”.equals(aParam)) {​


​LOGGER.debug(“User says no”);​


​….​



这些消息显示被调用的方法而且备份内部变量及方法參数值,主要是为了追踪应用程序的行为。这在非​​測试驱动开发​​中相当受欢迎。

但糟糕的是。一旦代码公布(測试之后成为成品)这些消息通常就无用武之地了。

所以,这条规则简单来说就是:一旦你已经完毕开发工作,在将代码提交到使用中的 SCM 系统(git、svn……)之前,要去除全部暂时的和不必要的日志消息。

这条规则并非要求去除全部的 DEBUG 消息。仅仅是针对那些在应用程序完毕和公布后就没有意义的消息,或者是说当我们有理由相信应用程序能正确执行时就失去意义的那些消息。

规则4、log DEBUG消息之前检查日志等级

依据第2条规则。在产品日志中,我们仅仅会显示 ERROR、WARN、INFO 等级的消息,可是在代码中我们也能够使用一些不会影响产品执行的 DEBUG 消息。




1


2


3




​if​​​​( LOGGER.isDebugEnabled((){​


​LOGGER.debug (…….)​


​}​



每次你想要 log 一个 DEBUG 消息时(在使用了规则3后的留下的全部消息)。须要在前面加入一个检查来明白是否启用了 DEBUG 日志:




1


2


3




​if​​​​( LOGGER.isDebugEnabled((){​


​LOGGER.debug (…….)​


​}​



这样的做法能够阻止代码去创建日志消息和调用 logger,提高产品执行程序的效率。

规则5、了解你的 logger

我们使用 logger 方法的方式可能会带来巨大的开销:

  • 创建消息字符串
  • 组织包括在消息字符串中的数据

我们应该查阅所选择的日志管理工具、引擎的 javadoc 文档,了解使用它们 logger 的最有效的方法。




1




​LOGGER.info(“Person name is “ + person.getName());​



比如,我们能够创建一条这种消息:




1




​LOGGER.info(“Person name is “ + person.getName());​



这就创建了不必要的字符串实例。




1




​LOGGER.info(“Person name is {}“, person.getName());​



使用SLF4J。正确的使用方法应该是:




1




​LOGGER.info(“Person name is {}“, person.getName());​



这里的格式化字符串是常量。不可变消息仅仅有在同意 logging 的情况下才会被创建。

看 ​​这里​​ 能够获得很多其它细节内容。