Java 8 中日志记录的惰性计算

2022-09-02 03:58:48

当您的计算成本高于计算成本时,您在日志记录框架中看到的常见模式是

if (log.isDebugEnabled()) {
    String value = expensiveComputation();
    log.debug("value: {}", value);
}

由于Java 8添加了lambdas,因此这样做会很好:

log.debug("value: {}", (Supplier<String>) this::expensiveComputation);

几乎是有效的,因为日志记录框架将在参数上执行操作。问题是 中的实现。toString()toString()SupplierObject

有没有办法提供懒惰地评估的方法?它几乎只是一个具有默认值的调用.LoggerSuppliertoString()get()


答案 1

要传递将以懒惰的方式执行计算的参数,您必须传递 a 而不是 .
您调用的方法应具有以下签名:StringSupplierString

void debug(Supplier<?> msgSupplier, Throwable t)

您可以在自己的实用程序类中引入此实用程序方法。
但是您不需要这样做,因为最近的日志记录框架(如 Log4j2)提供了开箱即用的此功能。

例如,org.apache.logging.log4j.Logger 提供了重载方法来记录接受 .
例如Supplier

void debug(MessageSupplier msgSupplier, Throwable t)

记录一条消息(仅当日志记录级别为 DEBUG 级别时才构造),包括作为参数传递的 Throwable t 的堆栈跟踪。MessageSupplier 可能会也可能不会使用 MessageFactory 来构造 Message。

Parameters:

msgSupplier- 一个函数,调用该函数时,将生成所需的日志消息。

t- 日志的异常,包括其堆栈跟踪。

从 Log4j2 文档 :

Java 8 lambda 支持惰性日志记录

在 2.4 版中,Logger 接口添加了对 lambda 表达式的支持。这允许客户端代码懒惰地记录消息,而无需显式检查是否启用了请求的日志级别。例如,以前你会写:

if (logger.isTraceEnabled()) {
    logger.trace("Some long-running operation returned {}", expensiveOperation());
}

使用 Java 8,您可以使用 lambda 表达式实现相同的效果。您不再需要显式检查日志级别:

logger.trace("Some long-running operation returned {}", 
              () ->    expensiveOperation());

答案 2

一个小的帮助程序对象将允许您执行所需的操作:

public class MessageSupplier {
    private Supplier<?> supplier;

    public MessageSupplier(Supplier<?> supplier) {
        this.supplier = supplier;
    }

    @Override
    public String toString() {
        return supplier.get().toString();
    }

    public static MessageSupplier msg(Supplier<?> supplier) {
        return new MessageSupplier(supplier);
    }
}

然后,使用静态导入 :msg

log.debug("foo: {}", msg(this::expensiveComputation));