从logger.isDebugEnabled()谈起

2019/04/02 20:43 下午 posted in  Java

0. 问题

在很多框架中,我们看到在logger.debug处经常会这样写

if (logger.isDebugEnabled()) {
    logger.debug(message);
}

我们知道logger.debug(),在日志级别不够的时候是不会输出日志的。那么这么写的目的何在?

1. 分析

我们来看一个例子

String error = "debug日志";
logger.debug("这是一个" + error);

按照正常的逻辑,在执行logger.debug()之前需要先行计算括号里的内容。然后才会判断当前日志级别不符合不输出。这里就存在一个无用计算的过程。相比对直接执行语句对logger.isDebugEnabled()进行先判断,显然是一个更优的方案,避免了无用的计算过程。

然而这个结论在占位符的使用下,有了一点不同。

再来看一个例子

1.1. logger.debug("这是一个{}", model);

public static class Model{
    int age;

    @Override
    public String toString() {
        System.out.println("toString called");
        return "model{" +
                "age=" + age +
                '}';
    }
}
public static void main(String[] args) {
    Model model = new Model();
    model.age = 3;
    
    logger.debug("这是一个{}", model);
}

同样的作用,但是当日志级别高于debug时,不会执行括号内部的字符串拼接。也就是如果使用占位符{}来组合输出日志,可以不用判断logger.isDebugEnabled()

1.2. logger.debug("test:{}", test());

Model的toString方法在用占位符{}的方式时,没有执行,那么如果是一个普通的方法呢?

public static String test(){
    System.out.println("test");
    return "test";
}
public static void main(String[] args) {
    logger.debug("test:{}", test()); //日志级别info
}

结果,logger.debug("test:{}", test());无输出,但是test()方法在控制台打印出了test。

结论:有占位符的存在,但是如果字符串拼接调用了函数,仍然会先执行函数,这和日志级别无关。

1.3. logger.debug("test2:{}, {}", model, test());

public static String test(){
    System.out.println("print test");
    return "fdsf";
}
public static void main(String[] args) {
    Model model = new Model();
    model.age = 3;
    logger.debug("test1:" + model);
    model.age = 5;
    logger.debug("test2:{}, {}", model, test());
}

结果,最后一句debug,model的toString方法没有执行,而test()方法打印出了"print test"。也就是在占位符的作用下,对象的toString()方法不会执行,而不同方法仍然会执行。

2. 结论

通过logger.isDebugEnabled()进行先行判断,肯定是没有错的。虽然在占位符的帮助下,当日志级别高于debug时,对象的toString()方法不会执行,但是普通的方法仍然会执行。如果能够保证logger.debug()中的内容只涉及最简单的字符串拼接和toString(),那么可以简略logger.isDebugEnabled(),否则还是加上避免无用计算。