我在我的应用程序中使用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()是一个非常小的方法(就代码而言),因此它可能是内联的良好候选方法。


当前回答

我建议大多数人使用选项2,因为它不是特别贵。

案例1: log.debug(一个字符串)

例2: Log.debug(“一个字符串”+“两个字符串”+对象。toString + object2.toString)

在调用这两个函数时,必须计算log.debug中的参数字符串(无论是CASE 1还是Case2)。这就是人们所说的“昂贵”。如果你在它之前有一个条件,'isDebugEnabled()',这些不需要计算,这是性能保存的地方。

其他回答

在这种特殊情况下,选择1更好。

当涉及调用各种对象的toString()方法并连接结果时,保护语句(检查isDebugEnabled())是为了防止日志消息潜在的昂贵计算。

在给定的示例中,日志消息是一个常量字符串,因此让记录器丢弃它与检查记录器是否启用一样有效,并且由于分支较少,因此降低了代码的复杂性。

更好的方法是使用最新的日志记录框架,其中日志语句接受一个格式规范和一个参数列表,由日志记录器代替——但是“惰性地”,只有在启用了日志记录器的情况下。这是slf4j采用的方法。

有关更多信息,请参阅我对相关问题的回答,以及使用log4j执行类似操作的示例。

我建议大多数人使用选项2,因为它不是特别贵。

案例1: log.debug(一个字符串)

例2: Log.debug(“一个字符串”+“两个字符串”+对象。toString + object2.toString)

在调用这两个函数时,必须计算log.debug中的参数字符串(无论是CASE 1还是Case2)。这就是人们所说的“昂贵”。如果你在它之前有一个条件,'isDebugEnabled()',这些不需要计算,这是性能保存的地方。

Log4j2允许您将参数格式化为消息模板,类似于String.format(),因此不需要执行isDebugEnabled()。

Logger log = LogManager.getFormatterLogger(getClass());
log.debug("Some message [myField=%s]", myField);

简单的log4j2.properties示例:

filter.threshold.type = ThresholdFilter
filter.threshold.level = debug
appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %d %-5p: %c - %m%n
appender.console.filter.threshold.type = ThresholdFilter
appender.console.filter.threshold.level = debug
rootLogger.level = info
rootLogger.appenderRef.stdout.ref = STDOUT

选择2更好。

它本身并不能提高性能。但它确保性能不会下降。这是如何。

通常我们认为 logger.debug (someString);

但通常,随着应用程序的发展,会有很多人转手,尤其是新手开发人员

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

诸如此类。

即使日志级别设置为ERROR或FATAL,字符串的连接也会发生! 如果应用程序包含大量带有字符串连接的DEBUG级别消息,那么它肯定会受到性能影响,特别是使用jdk 1.4或以下版本时。(我不确定以后版本的jdk内部是否做任何stringbuffer.append())。

这就是为什么选择2是安全的。即使字符串连接也不会发生。

简短版本:你也可以做布尔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.
*   */