关于打印debug日志是否加判断日志级别的分析

2019-02-01  本文已影响0人  唐影若凡

一、问题由来

在代码中,我们经常会看到打印debug日志的时候,会判断下当前的日志级别:

if (LOGGER.isDebugEnabled()) {
    LOGGER.debug(... ...);
}

到底有没有必要呢?到底有没有必要呢?到底有没有必要呢

二、答案

为了节省大家的时间,先上答案。

1、如果打印的实参不含计算的,【完全没有必要】

String demo = "demo";
LOGGER.debug("i am a {}", demo); // 实参为: i am a {} 和demo两个

2、如果打印的实参含有计算的,【完全有必要】

Demo demo = new Demo();
LOGGER.debug("i am a " + "demo"); // 实参为: i am a demo,需要先进行实参计算
LOGGER.debug("i am a {}", demo.toString()); // 实参为:i am a {} 和demo.toString(),后者需要计算

三、实验探究

1、Log4j 源码

debug()方法中,一开始就做了和isDebugEnabled()一样的事情,那是不是就不需要判断了?

public boolean isDebugEnabled() {  
    if(repository.isDisabled( Level.DEBUG_INT))  
        return false;  
    return Level.DEBUG.isGreaterOrEqual(this.getEffectiveLevel());  
} 
​
public void debug(Object message) {  
    if(repository.isDisabled(Level.DEBUG_INT))  
        return;  
    if(Level.DEBUG.isGreaterOrEqual(this.getEffectiveLevel())) {  
        forcedLog(FQCN, Level.DEBUG, message, null);  
    }  
} 

2、Log4j的占位符

网上的博客存在大量的分析,说开启了占位符{},完全不用判断。真的是这样吗?

// 虽然不会输出日志,但是demo.toString()确实是执行了
LOGGER.debug("{} {}", "a", demo.toString());

3、Java编译器的实参执行顺序:实参从左到右,最后是执行方法

这问题其实和log4j的关系不大,真正的原因是实参的执行顺序以及计算。😅

public class Test {
    public static String fun1() { System.out.println("fun1"); return "fun1 "; }
    public static String fun2() { System.out.println("fun2"); return "fun2"; }
    public static void test(String s1, String s2) { System.out.println(s1 + s2); }
​
    public static void main(String[] args) {
        test(fun1(), fun2()); 
    }
}
// console: 
fun1
fun2
fun1 fun2

结论:打印debug日志,如果需要打印的数据需要计算实参的,必须加判断。这是因为不管debug()里面具体执不执行,实参的方法调用确实是执行了。

不好的例子:

LOGGER.debug("a" + "b");
LOGGER.debug("" + JSON.toJSONString(demo));
LOGGER.debug("{}", JSON.toJSONString(demo));

好的例子:

LOGGER.debug("{} {}","a","b");
LOGGER.debug("{}", demo);

4、结论

如果debug()里面的含有实参计算的,必须加判断。

推荐一种JSON序列化对象的方式:

public class Log {
    @Override
    public String toString() {
        System.out.println("toString");
        return JSON.toJSONString(this);
    }
}
​
public class Test {
    private static final Logger LOGGER = LoggerFactory.getLogger(Test.class);
  
    public static void main(String[] args) {
        Log log = new Log();
        LOGGER.debug("{}", log); // 实际运行时才会调用其toString()方法 - JSON方法
    }
}
上一篇下一篇

猜你喜欢

热点阅读