在有效日志级别检查的上下文中,Log4j2 中的替换参数和 Java lambda 表达式有什么区别?
What is the difference between Substituting Parameters and Java lambda expressions in Log4j2 in the context of effective log level checking?
我想了解 Log4j 的好处 2.x 但 documentation 让我感到困惑。
有两部分:替换参数和 Java 8 lambda 支持惰性日志记录。
在第一个中说使用:
logger.debug("Logging in user {} with birthday {}", user.getName(), user.getBirthdayCalendar());
不需要检查日志级别两次就足够了。
另一方面,在第二部分他们说我应该使用 lambda 表达式来延迟记录消息。
// pre-Java 8 style optimization: explicitly check the log level
// to make sure the expensiveOperation() method is only called if necessary
if (logger.isTraceEnabled()) {
logger.trace("Some long-running operation returned {}", expensiveOperation());
}
// Java-8 style optimization: no need to explicitly check the log level:
// the lambda expression is not evaluated if the TRACE level is not enabled
logger.trace("Some long-running operation returned {}", () -> expensiveOperation());
那有什么区别呢?
在第一部分中,调用了user.getName()
,并将值传递给了logger.debug()
函数。如果禁用调试日志记录,则丢弃该值。获取用户名可能是"expensive";它可以存储为名字、姓氏、前缀和后缀,并构建成更大的字符串。如果不使用该值,则浪费精力。
但从未创建完整的日志消息。考虑:
logger.debug("Logging in user " + user.getName() + " with birthday " + user.getBirthdayCalendar());
在这里,我们不仅调用了getName()
和getBirthdayCalender()
,而且我们还进行了字符串连接来构建整个日志消息!至少在使用 {}
替换代码时,记录器可以意识到,如果它不记录调试消息,则不必进行字符串替换。程序员需要为该优化添加 if (isDebugEnabled()
语句。
在第二个示例中,isTraceEnabled()
验证在调用尝试在跟踪级别记录某些内容的语句之前,记录器实际上会记录该值。 expensiveOperation()
仅在启用 "trace" 日志记录时才执行。
使用 lambda,我们有另一种方法来延迟对 expensiveOperation()
的调用:
logger.trace("Some long-running operation returned {}", () -> expensiveOperation());
而不是计算 expensiveOperation()
,我们只传递一个 可以 调用的函数来执行昂贵的操作。如果启用跟踪级别日志记录,记录器将自己调用 lambda 函数,调用昂贵的操作函数。如果未启用跟踪日志记录,则不会调用 lambda 函数,因此永远不会执行昂贵的操作。
总而言之,如果禁用跟踪级日志记录:
// Calls expensiveOperation & builds log string:
logger.trace("Some long running operation returned "+expensiveOperation())
// Calls expensiveOperation, but does not build log string:
logger.trace("Some long-running operation returned {}", expensiveOperation());
// Does not call expensiveOperation, nor builds log string:
logger.trace("Some long-running operation returned {}", () -> expensiveOperation());
我想了解 Log4j 的好处 2.x 但 documentation 让我感到困惑。 有两部分:替换参数和 Java 8 lambda 支持惰性日志记录。
在第一个中说使用:
logger.debug("Logging in user {} with birthday {}", user.getName(), user.getBirthdayCalendar());
不需要检查日志级别两次就足够了。
另一方面,在第二部分他们说我应该使用 lambda 表达式来延迟记录消息。
// pre-Java 8 style optimization: explicitly check the log level
// to make sure the expensiveOperation() method is only called if necessary
if (logger.isTraceEnabled()) {
logger.trace("Some long-running operation returned {}", expensiveOperation());
}
// Java-8 style optimization: no need to explicitly check the log level:
// the lambda expression is not evaluated if the TRACE level is not enabled
logger.trace("Some long-running operation returned {}", () -> expensiveOperation());
那有什么区别呢?
在第一部分中,调用了user.getName()
,并将值传递给了logger.debug()
函数。如果禁用调试日志记录,则丢弃该值。获取用户名可能是"expensive";它可以存储为名字、姓氏、前缀和后缀,并构建成更大的字符串。如果不使用该值,则浪费精力。
但从未创建完整的日志消息。考虑:
logger.debug("Logging in user " + user.getName() + " with birthday " + user.getBirthdayCalendar());
在这里,我们不仅调用了getName()
和getBirthdayCalender()
,而且我们还进行了字符串连接来构建整个日志消息!至少在使用 {}
替换代码时,记录器可以意识到,如果它不记录调试消息,则不必进行字符串替换。程序员需要为该优化添加 if (isDebugEnabled()
语句。
在第二个示例中,isTraceEnabled()
验证在调用尝试在跟踪级别记录某些内容的语句之前,记录器实际上会记录该值。 expensiveOperation()
仅在启用 "trace" 日志记录时才执行。
使用 lambda,我们有另一种方法来延迟对 expensiveOperation()
的调用:
logger.trace("Some long-running operation returned {}", () -> expensiveOperation());
而不是计算 expensiveOperation()
,我们只传递一个 可以 调用的函数来执行昂贵的操作。如果启用跟踪级别日志记录,记录器将自己调用 lambda 函数,调用昂贵的操作函数。如果未启用跟踪日志记录,则不会调用 lambda 函数,因此永远不会执行昂贵的操作。
总而言之,如果禁用跟踪级日志记录:
// Calls expensiveOperation & builds log string:
logger.trace("Some long running operation returned "+expensiveOperation())
// Calls expensiveOperation, but does not build log string:
logger.trace("Some long-running operation returned {}", expensiveOperation());
// Does not call expensiveOperation, nor builds log string:
logger.trace("Some long-running operation returned {}", () -> expensiveOperation());