一、问题由来
在代码中,我们经常会看到打印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方法
}
}
网友评论