計算にコストがかかる値よりも大きい値がある場合、ロギングフレームワークに見られる一般的なパターンは次のとおりです。
_if (log.isDebugEnabled()) {
String value = expensiveComputation();
log.debug("value: {}", value);
}
_
Java 8個のラムダが追加されたので、次のようにするとよいでしょう。
_log.debug("value: {}", (Supplier<String>) this::expensiveComputation);
_
ロギングフレームワークがパラメータに対してtoString()
を実行するため、どちらがほぼ機能します。問題は、Supplier
のtoString()
がObject
の実装であるということです。
怠惰に評価されるものをLogger
メソッドに提供する方法はありますか? toString()
を呼び出すデフォルトのget()
を含むSupplier
になります。
怠惰な方法で実行される引数をString
計算に渡すには、Supplier
ではなくString
を渡す必要があります。
呼び出すメソッドには、次のシグネチャが必要です。
_void debug(Supplier<?> msgSupplier, Throwable t)
_
このユーティリティメソッドを独自のユーティリティクラスに導入できます。
ただし、Log4j2などの最近のロギングフレームワークがこの機能をすぐに提供するため、これを行う必要はありません。
たとえば、 org.Apache.logging.log4j.Logger は、Supplier
を受け入れるオーバーロードされたログメソッドを提供します。
例 の場合:
void debug(MessageSupplier msgSupplier, Throwable t)
パラメータとして渡されたThrowabletのスタックトレースを含むメッセージをログに記録します(ログレベルがDEBUGレベルの場合にのみ作成されます)。 MessageSupplierは、MessageFactoryを使用してメッセージを作成する場合と使用しない場合があります。
Parameters
:
msgSupplier
-呼び出されると、目的のログメッセージを生成する関数。
t
-スタックトレースを含むログの例外。
Log4j2ドキュメントから:
レイジーロギングのJava 8ラムダサポート
リリース2.4では、Loggerインターフェースでラムダ式のサポートが追加されました。これにより、クライアントコードは、要求されたログレベルが有効になっているかどうかを明示的に確認せずに、メッセージを遅延ログに記録できます。たとえば、以前は次のように記述します。
_if (logger.isTraceEnabled()) { logger.trace("Some long-running operation returned {}", expensiveOperation()); }
_Java 8を使用すると、ラムダ式で同じ効果を得ることができます。ログレベルを明示的にチェックする必要はなくなりました。
_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+の場合、これを使用することもできますlazyおよび便利な表記:
_LOGGER.fine(() -> "Message1: " + longComputation1() + ". Message2: " + longComputation2());
_
longComputation1()
およびlongComputation2()
は、レイジーと呼ばれます。つまり、必要な場合のみです。