当我们打开或关闭某些日志位置时,log4j实际上在做什么?

时间:2010-02-09 15:29:47

标签: java log4j

我们知道我们可以通过其属性/配置文件来配置log4j来关闭特定位置(Java中的类或包)的日志。我的问题是:

  1. log4j实际上为这些标志做了什么?
  2. 是log4j中仍然调用的日志语句,但由于该标志而没有写入文件或控制台?那还有性能影响吗?
  3. 就像C ++中的#ifdef在编译时生效然后可以限制性能影响吗?
  4. 感谢,

3 个答案:

答案 0 :(得分:16)

是的,日志语句仍将执行。这就是为什么首先检查日志级别是一个很好的模式:类似

if (log.isInfoEnabled()) {
    log.info("My big long info string: " + someMessage);
}

这是为了防止在日志级别不支持String语句时为信息INFO重新分配空间。

它不是#ifdef - #ifdef是编译器指令,而Log4J配置是在运行时处理的。

编辑:我讨厌由于无知导致失败,所以这里有一篇文章支持我的回答。

来自http://surguy.net/articles/removing-log-messages.xml

  

在Log4J中,如果您在其中记录消息   DEBUG级别和当前的Appender   设置为仅记录INFO的消息   级别及以上,然后消息将   不显示。表现   调用日志方法的惩罚   本身很小 - 几纳秒。   但是,可能需要更长时间   评估日志的参数   方法。例如:

     

logger.debug(“大对象是   “+ largeObject.toString());

     

评估largeObject.toString()可能   要慢,然后进行评估   调用记录器,所以记录器   不能阻止它被评估,   即使它不会被使用。

编辑2 :来自log4j手册本身(http://logging.apache.org/log4j/1.2/manual.html):

用户应了解以下性能问题。

  1. 关闭日志记录时的记录性能。   当完全关闭日志记录或仅针对一组级别关闭日志记录时,日志请求的开销包括方法调用和整数比较。在233 MHz Pentium II机器上,此成本通常在5到50纳秒范围内。

    但是,方法调用涉及参数构造的“隐藏”成本。

    例如,对于某些记录器猫,写作,

     logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
    

    会产生构造消息参数的成本,即将integer i和entry [i]都转换为String,并连接中间字符串,无论是否记录消息。参数构造的成本可能非常高,并且取决于所涉及参数的大小。

    为避免参数构造成本写:

    if(logger.isDebugEnabled() {
      logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
    }
    

    如果禁用调试,这不会产生参数构造的成本。另一方面,如果记录器是启用调试的,则会产生两倍于评估记录器是否启用的成本:一次在debugEnabled中,一次在调试中。这是一个微不足道的开销,因为评估记录器需要大约1%的时间来实际记录。

答案 1 :(得分:5)

我运行了一个简单的基准测试。

    for (int j = 0; j < 5; j++) {
        long t1 = System.nanoTime() / 1000000;
        int iterations = 1000000;
        for (int i = 0; i < iterations; i++) {
            int test = i % 10;
            log.debug("Test " + i + " has value " + test);
        }
        long t2 = System.nanoTime() / 1000000;
        log.info("elapsed time: " + (t2 - t1));

        long t3 = System.nanoTime() / 1000000;
        for (int i = 0; i < iterations; i++) {
            int test = i % 10;
            if (log.isDebugEnabled()) {
                log.debug("Test " + i + " has value " + test);
            }
        }
        long t4 = System.nanoTime() / 1000000;
        log.info("elapsed time 2: " + (t4 - t3));
    }

elapsed time: 539
elapsed time 2: 17
elapsed time: 450
elapsed time 2: 18
elapsed time: 454
elapsed time 2: 19
elapsed time: 454
elapsed time 2: 17
elapsed time: 450
elapsed time 2: 19

1.6.0_18,让我感到惊讶,因为我认为内联会阻止这一点。也许带有转义分析的Java 7会。

但是我仍然不会在if子句中包装调试语句,除非半微秒的时间改进变得很重要!

答案 2 :(得分:1)

  1. log4j将处理日志语句,并检查特定日志记录器是否在特定日志记录级别启用。如果不是,则不会记录该语句。

  2. 这些检查比实际写入磁盘(或控制台)要便宜得多,但它们仍有影响。

  3. 不,java没有像#ifdef这样的概念(无论如何都有开箱即用的java预编译器)