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

时间:2017-11-01 20:34:36

标签: java lambda lazy-evaluation

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

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

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

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

哪个几乎有效,因为日志记录框架会对参数执行toString()。问题是toString() SupplierObject中的实现。

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

5 个答案:

答案 0 :(得分:6)

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

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

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

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

  

void debug(MessageSupplier msgSupplier, Throwable t)

     

记录消息(仅在记录级别为时才构建)   DEBUG级别)包括传递给Throwable的堆栈跟踪   参数。 MessageSupplier可能使用也可能不使用MessageFactory   构建消息。

     

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

答案 1 :(得分: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);
    }
}

然后,静态导入msg

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

答案 2 :(得分:1)

  

哪个几乎有效,因为日志框架会对参数执行toString()

此声明不正确。如果您进入debug / info /无论采用何种方式,您都会找到此实施方式:

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

如果level未满足,则Supplier甚至无法使用。

答案 3 :(得分:1)

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

interface LazyString { String toString(); }

作为功能界面

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

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

答案 4 :(得分:0)

对于java.util.logging和Java 8+,您还可以使用以下 lazy 和方便的符号:

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

longComputation1()longComputation2()将被称为惰性-即仅在需要时使用。