簡體   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