我在我的应用程序中使用Log4J进行日志记录。之前我使用的调试调用如下:

选项1:

logger.debug("some debug text");

但是一些链接建议最好先检查isDebugEnabled(),比如:

选项2:

boolean debugEnabled = logger.isDebugEnabled();
if (debugEnabled) {
    logger.debug("some debug text");
}

所以我的问题是“选项2是否能提高性能?”

因为在任何情况下Log4J框架对debugEnabled都有相同的检查。对于选项2,如果我们在一个方法或类中使用多个调试语句可能是有益的,这样框架就不需要多次调用isDebugEnabled()方法(每次调用);在这种情况下,它只调用isDebugEnabled()方法一次,如果Log4J被配置为调试级别,那么实际上它会调用isDebugEnabled()方法两次:

如果将值分配给debugEnabled变量,和 实际上由logger.debug()方法调用。

我不认为如果我们在方法或类中编写多个logger.debug()语句并根据选项1调用debug()方法,那么与选项2相比,Log4J框架的开销是很大的。由于isDebugEnabled()是一个非常小的方法(就代码而言),因此它可能是内联的良好候选方法。


当前回答

由于许多人在搜索log4j2时可能会看到这个答案,而且几乎所有当前的答案都不考虑log4j2或它最近的变化,因此这应该能够回答这个问题。

log4j2支持供应商(目前是它们自己的实现,但根据文档,计划在3.0版本中使用Java的供应商接口)。你可以在手册里读到更多。这允许你把昂贵的日志消息创建到一个供应商,它只创建消息,如果它将被记录:

LogManager.getLogger().debug(() -> createExpensiveLogMessage());

其他回答

简短版本:你也可以做布尔isDebugEnabled()检查。

原因: 1-如果复杂的逻辑/字符串连接。添加到调试语句时,则检查已经就位。 2-你不必有选择地在“复杂”调试语句中包含语句。所有语句都是这样包含的。 3-在记录日志之前,调用log.debug执行以下命令:

如果(repository.isDisabled (Level.DEBUG_INT)) 返回;

这基本上与调用log相同。或猫。isDebugEnabled()。

然而!这是log4j开发人员的想法(因为它在他们的javadoc中,您可能应该遵循它)。

这就是方法

public
  boolean isDebugEnabled() {
     if(repository.isDisabled( Level.DEBUG_INT))
      return false;
    return Level.DEBUG.isGreaterOrEqual(this.getEffectiveLevel());
  }

这是它的javadoc

/**
*  Check whether this category is enabled for the <code>DEBUG</code>
*  Level.
*
*  <p> This function is intended to lessen the computational cost of
*  disabled log debug statements.
*
*  <p> For some <code>cat</code> Category object, when you write,
*  <pre>
*      cat.debug("This is entry number: " + i );
*  </pre>
*
*  <p>You incur the cost constructing the message, concatenatiion in
*  this case, regardless of whether the message is logged or not.
*
*  <p>If you are worried about speed, then you should write
*  <pre>
*    if(cat.isDebugEnabled()) {
*      cat.debug("This is entry number: " + i );
*    }
*  </pre>
*
*  <p>This way you will not incur the cost of parameter
*  construction if debugging is disabled for <code>cat</code>. On
*  the other hand, if the <code>cat</code> is debug enabled, you
*  will incur the cost of evaluating whether the category is debug
*  enabled twice. Once in <code>isDebugEnabled</code> and once in
*  the <code>debug</code>.  This is an insignificant overhead
*  since evaluating a category takes about 1%% of the time it
*  takes to actually log.
*
*  @return boolean - <code>true</code> if this category is debug
*  enabled, <code>false</code> otherwise.
*   */

If you use option 2 you are doing a Boolean check which is fast. In option one you are doing a method call (pushing stuff on the stack) and then doing a Boolean check which is still fast. The problem I see is consistency. If some of your debug and info statements are wrapped and some are not it is not a consistent code style. Plus someone later on could change the debug statement to include concatenate strings, which is still pretty fast. I found that when we wrapped out debug and info statement in a large application and profiled it we saved a couple of percentage points in performance. Not much, but enough to make it worth the work. I now have a couple of macros setup in IntelliJ to automatically generate wrapped debug and info statements for me.

在Java 8中,您不必使用isDebugEnabled()来提高性能。

https://logging.apache.org/log4j/2.0/manual/api.html#Java_8_lambda_support_for_lazy_logging

import java.util.logging.Logger;
...
Logger.getLogger("hello").info(() -> "Hello " + name);

正如其他人提到的,只有在创建字符串是一个耗时的调用时,使用guard语句才真正有用。具体的例子是当创建字符串时会触发一些延迟加载。

值得注意的是,这个问题可以通过使用Java的简单日志Facade或(SLF4J) - http://www.slf4j.org/manual.html来完成避免。这允许调用如下方法:

logger.debug("Temperature set to {}. Old temperature was {}.", t, oldT);

这只会在启用调试时将传入的参数转换为字符串。SLF4J顾名思义只是一个facade,日志调用可以传递给log4j。

你也可以很容易地“滚动”你自己的版本。

希望这能有所帮助。

对于单行,我在日志消息中使用了三元,这样我就不做拼接:

ej:

logger.debug(str1 + str2 + str3 + str4);

我做的事:

logger.debug(logger.isDebugEnable()?str1 + str2 + str3 + str4:null);

但是对于多行代码

ej.

for(Message mess:list) {
    logger.debug("mess:" + mess.getText());
}

我做的事:

if(logger.isDebugEnable()) {
    for(Message mess:list) {
         logger.debug("mess:" + mess.getText());
    }
}