繁体   English   中英

懒惰评估登录 Java 8

[英]Lazy evaluation for logging in Java 8

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

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

由于 Java 添加了 8 个 lambda,所以这样做会很好:

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

几乎可以工作,因为日志记录框架将对参数执行toString() 问题是Supplier上的toString()Object中的实现。

有没有办法向Logger方法提供惰性评估的内容? 它几乎只是一个具有调用get()的默认toString()Supplier

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

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()); 

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

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

几乎起作用,因为日志框架将对参数执行toString()

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

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

如果未达到该level ,则甚至不使用Supplier

有趣的是,你甚至不能使用这样的东西

interface LazyString { String toString(); }

作为功​​能界面

到目前为止我找到的唯一方法是通过匿名课程。

Object o = new Object() { @Override public String toString() { return myExpensiveComputation(); } }; System.out.printf("%s", o);

对于java.util.logging和Java 8+,您还可以使用这种懒惰且方便的表示法:

LOGGER.fine(() -> "Message1: "  + longComputation1() + ". Message2: " + longComputation2());

longComputation1()longComputation2()将被称为lazy - 即仅在需要时。

因为你透露你使用的 SLF4J 仍然不支持它的核心,如果你在 Kotlin 中编码(你可以使用 JDK 8),这可能会派上用场:

fun Logger.info( provider: () -> String ) { if (this.isInfoEnabled) this.info(provider.invoke())
fun Logger.debug( provider: () -> String ) { if (this.isDebugEnabled) this.debug(provider.invoke())
fun Logger.trace( provider: () -> String ) { if (this.isTraceEnabled) this.trace(provider.invoke()) 

用法:

log.trace { "State dump: " + expensiveLongSerialisation(state) }

资料来源:我的要点:) https://gist.github.com/OndraZizka/a7381b8cd86f734bc3b6bf9e528a01ad

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM