对Java 8中的日志记录进行延迟评估

Dav*_*ann 10 java lambda lazy-evaluation

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

if (log.isDebugEnabled()) {
    String value = expensiveComputation();
    log.debug("value: {}", value);
}
Run Code Online (Sandbox Code Playgroud)

由于Java 8添加了lambdas,所以做得很好:

log.debug("value: {}", (Supplier<String>) this::expensiveComputation);
Run Code Online (Sandbox Code Playgroud)

几乎起作用,因为日志框架将对toString()参数执行.问题是toString()Supplier是在执行Object.

有没有办法提供一些懒惰地评估Logger方法的东西?它几乎只是Supplier一个默认toString()调用get().

dav*_*xxx 8

要传递一个以惰性方式执行String计算的参数,你必须传递一个Supplier而不是一个String.
您调用的方法应具有以下签名:

void debug(Supplier<?> msgSupplier, Throwable t)
Run Code Online (Sandbox Code Playgroud)

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

例如,org.apache.logging.log4j.Logger提供了重载方法来记录接受a 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());
}
Run Code Online (Sandbox Code Playgroud)

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

logger.trace("Some long-running operation returned {}", 
              () ->    expensiveOperation());
Run Code Online (Sandbox Code Playgroud)

  • 最后一行是我正在寻找的.这应该是公认的答案. (3认同)

tep*_*pic 5

一个小帮手对象将允许您做你想要的:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,使用静态导入msg:

log.debug("foo: {}", msg(this::expensiveComputation));
Run Code Online (Sandbox Code Playgroud)


Mur*_*nik 0

几乎可以工作,因为日志框架将对toString()参数进行处理。

这种说法是不正确的。如果你进入debug// infowhatever 方法,你会发现这个实现:

public void log(Level level, Supplier<String> msgSupplier) {
    if (!isLoggable(level)) {
        return;
    }
    LogRecord lr = new LogRecord(level, msgSupplier.get());
    doLog(lr);
}
Run Code Online (Sandbox Code Playgroud)

如果level不满足,则Supplier甚至不使用。

  • 您正在寻找哪个日志框架?我正在寻找 slf4j 的 API 和 Logback 的实现。 (2认同)