惰性日志

在代码中添加日志时要当心:有时尽管并没有记录日志,也会执行日志语句。例如下面的代码:
“`java
log.debug(“I found {} and {}”, getone(), gettwo());
“`
看起来很好,似乎没有任何问题。日志输出字符串中包含了两个调试参数。
所以一切正常,没有问题?也不尽然。
在记录日志的代码中可以看到下面两个输入:
  •  `getone()`
  •  `gettwo()`
这两个方法会”一直“调用。这意味着,即使实际可能不会执行 `log` 语句,仍然会计算所有 `log` 方法传入的参数。
如果这些调用开销很大,那么可能会浪费大量 CPU 资源。
一种典型的解决方案像下面这样:
“`java
if (log.isDebugEnabled()) {
log.debug(“I found {} and {}”, getone(), gettwo());
}
“`
但这种方法相当丑陋:这不正是 `log.debug` 完成的功能吗?只在启用调试时才记录日志。
我们需要的是一个单行调试语句,只在启用日志记录时计算输入的参数。
为了解决类似的情况,我们将应用 Java 8 Supplier 模式,只在需要的时候执行计算。
不幸的是,大多数日志框架并不支持 Supplier 模式。
至少是直接支持。
实际上,`logger` 并不期望输入的参数一定是字符串,实际参数可以是任意对象。`logger` 会调用对象的 `toString` 方法把它转换为字符串。这里的诀窍是`logger` 只在日志启用的情况下调用字符串。
因此,要实现惰性日志只需要用一个对象来包装 Supplier,该对象仅在调用 toString 时调用 Supplier。
“`java
import java.util.function.Supplier;
publicclass LazyString {
private final Supplier<?> stringSupplier;
publicstatic LazyString lazy(Supplier<?> stringSupplier){
returnnew LazyString(stringSupplier);
}
publicLazyString(final Supplier<?> stringSupplier){
this.stringSupplier = stringSupplier;
}
@Override
public String toString(){
return String.valueOf(stringSupplier.get());
}
}
“`
现在可以更新之前的日志代码,结果如下:
“`java
importstatic LazyString.lazy;
log.debug(“I found {} and {}”, lazy(this::getone), lazy(this::gettwo));
“`
理想情况下,日志框架能直接支持 Supplier。但在等待的过程中,这也是一种变通的办法。
完整示例代码,请查看我的 Github 仓库:<https://github.com/efenglu/lazyLogger>
本站所有文章均由网友分享,仅用于参考学习用,请勿直接转载,如有侵权,请联系网站客服删除相关文章。若由于商用引起版权纠纷,一切责任均由使用者承担
极客文库 » 惰性日志

Leave a Reply

欢迎加入「极客文库」,成为原创作者从这里开始!

立即加入 了解更多