专栏名称: 朱小厮的博客
著有畅销书:《深入理解Kafka》和《RabbitMQ实战指南》。公众号主要用来分享Java技术栈、Golang技术栈、消息中间件(如Kafka、RabbitMQ)、存储、大数据以及通用型技术架构等相关的技术。
目录
相关文章推荐
高工智能汽车  ·  数据首发!25-30万元价位车型「爆拉」AD ... ·  昨天  
草原云 北方新报  ·  车辆年检新规出台!3月1日起实施! ·  2 天前  
草原云 北方新报  ·  车辆年检新规出台!3月1日起实施! ·  2 天前  
比亚迪汽车  ·  国货之光·悦己宜家 | 方程豹 ... ·  4 天前  
比亚迪汽车  ·  方华2025 | ... ·  5 天前  
51好读  ›  专栏  ›  朱小厮的博客

惰性日志

朱小厮的博客  · 公众号  ·  · 2019-06-29 11:20

正文

点击上方“ 朱小厮的博客 ”,选择“ 设为星标

做积极的人,而不是积极废人


来源: itnext.io/lazy-logging-40314cf9bb25


在代码中添加日志时要当心: 有时尽管并没有记录日志,也会执行日志语句。 例如下面的代码:


```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;

public class LazyString {
private final Supplier> stringSupplier;

public static LazyString lazy(Supplier> stringSupplier) {
return new LazyString(stringSupplier);
}

public LazyString(final Supplier> stringSupplier) {
this.stringSupplier = stringSupplier;
}

@Override
public String toString()
{
return String.valueOf(stringSupplier.get());
}
}
```


现在可以更新之前的日志代码,结果如下:


```java
import static LazyString.lazy;
log.debug("I found {} and {}", lazy(this::getone), lazy(this::gettwo));
```






请到「今天看啥」查看全文