如何使用更少的logger.isDebugEnabled()

时间:2011-06-23 09:53:26

标签: java log4j

这里我将为logger.debug()添加logger.isDebugEnabled()条件语句。 但有时候循环中有很多logger.debug()。例如:

Logger log = Logger.getLogger(Test.class);

for(int i = 0; i < 1000; i++) {
    ...
    log.debug("aaaaa");
    ...
    for(int j = 0; i < 100; j++) {
        ...
        log.debug("bbbb");
    }
}

如果我直接添加,如下:

for(int i = 0; i < 1000; i++) {
    ...
    if(log.isDebugEnabled()) {
        log.debug("aaaaa");
    }
    ...
    for(int j = 0; i < 100; j++) {
        ...
        if(log.isDebugEnabled()) {
            log.debug("bbbb");
         }
    }
}

所以,在循环中,它会if()很多次。我怎么能用if(logger.isDebugEnabled())?
有没有人有想法?
感谢。

4 个答案:

答案 0 :(得分:4)

  

我关心的是if()in循环是否会影响性能?

考虑以下代码:

    boolean logging = log.isDebugEnabled();

    for (int i = 0; i < 1000; i++) {
        // stuff
        if (logging) { 
            log.debug("Hi Mum!");
        }
        // more stuff
    }

if测试的成本可能只有2条指令,具体取决于JIT编译器的寄存器分配如何调整。这很可能是微不足道的,除非您正在进行荒谬的数量的日志记录。

但是,如果这些2到4条指令的性能损失真的很重要,那么你可以考虑:

  • 完全取消对log的调用,

  • 使其以编译时常量为条件(以便优化器可以修剪代码),或

  • 将测试从环路中提升出来;例如重构代码如下:

    boolean logging = log.isDebugEnabled();
    
    if (logging) {
        for (int i = 0; i < 1000; i++) {
            // stuff
            log.debug("Hi Mum!");
            // more stuff
        }
    } else {
        for (int i = 0; i < 1000; i++) {
            // stuff
            // more stuff
        }
    } 
    

然而,IMO,治愈方法比疾病更糟。


@ Vineet的观点也很重要。在实践中,这样的昂贵部分:

log.debug("Today is " + date);

是无论实际的日志记录级别如何,都会计算字符串连接表达式。除了if测试之外,还有其他方法可以避免这种开销......虽然它们比缓存标志上的if测试更昂贵

答案 1 :(得分:2)

使用slf4j

答案 2 :(得分:2)

log.isDebugEnabled()的值存储在本地变量中,如下所示:

// Calculate once and cache the answer
boolean areLogging = log.isDebugEnabled();

for (int i = 0; i < 1000; i++) {
    ...
    if (areLogging) { 
        log.debug("aaaaa");
    }
    ...
    for (int j = 0; i < 100; j++) {
        ...
        if (areLogging) {
            log.debug("bbbb");
        }
    }
}

答案 3 :(得分:2)

已经指出使用slf4j。具体来说,您应该使用slf4j的“参数化消息”功能。

发布的代码未演示使用parameterized messages的实用程序。显然,“bbbb”将被视为字符串文字(因为编译器可以在运行时计算它的值并将其放在类的常量池中),当类加载并汇集到内部时,它将由JVM加载。字符串池;构建日志消息显然没有成本,log.isDebugEnabled()调用是多余的。因此,我将使用更具描述性的示例来说明参数化消息的使用,以证明它的好处

for(int j = 0; i < 100; j++) {
    ...
    if(log.isDebugEnabled()) { // this is required by log4j. Without this, on every iteration, a new String object will be created in the following statement.
        log.debug("Loop counter is" + j); // This constructs a new String object only if DEBUG is enabled.
    }
}

可以简化为:

for(int j = 0; i < 100; j++) {
    ...
    log.debug("Loop counter is {}", j); //There is no explicit call to log.isDebugEnabled() in this case. The log message will be created only if DEBUG is enabled.
}

String literal Loop counter is {}再次汇集在String intern池中,但在运行时,slf4j将创建值为Loop counter is 0Loop counter is 1等的String对象,但前提是DEBUG级别已启用。