之前的一次代码评审,说代码中有问题,对于频发打印的日志,没有使用如下第二中方式,说是有问题,虽然日志没有打印,但是还是会调用demo.toString()方法,占用系统资源
// 方式一:
log.debug("xxxx:{}",demo)
// 方式二:
if(log.isDebugEnabled()){
log.debug("xxxx:{}",demo)
}
说的我一脸蒙B,我之前也没看过具体源码,也貌似听过这个说法,加之是在很多源码里面看到各个大佬都是使用的这种写法。也没敢吭声。但调整了代码,闲来无事,总觉得吧还是要研究一下知其所以然,不然以后还得蒙B。
查看log4J日志打印源码
public void info(final String format, final Object o) {
this.logger.logIfEnabled(FQCN, Level.INFO, (org.apache.logging.log4j.Marker)null, format, o);
}
@Override
public void logIfEnabled(final String fqcn, final Level level, final Marker marker, final String message,
final Object p0) {
if (isEnabled(level, marker, message, p0)) {
logMessage(fqcn, level, marker, message, p0);
}
}
不看还好,看了感觉更加的蒙了,这个不是在框架中已经帮我们自行添加了logIfEnabled的判断了吗,如果不满足日志输出的条件,就不会调用logMessage方法进行字符的拼接。兜兜转转终于发现了大家所说的问题了。我们来看看如下两个日志输出的方式:
写法1:
log.info("ffffffffffffff:"+ demo);
写法2:
log.error("bbbbbbbbb:{}", demo);
问题就在这里,如果使用写法1,在进行日志级别的判断前,就会调用demo的string方法对需要打印的日志内容进行拼接组装,然后再进行日志级别的判断。这就出现了之前大家说了,虽然不满足日志输出级别的要求,但是还是调用了对象的toString()方法,占用了系统资源。
如果我们使用写法2,则不存在这种问题,因为demo作为一个对象传入被调用的方法中,需要在isEnabled()方法调用后满足条件后,调用logMessage()时才会调用demo的toString()方法进行字符的拼接。
总结:
log日志的打印不是非要使用if(log.isDebugEnabled())的方式,来避免系统资源的占用。我们需要通过规范自己日志输出的格式。不要使用+进行字符串的拼接,而因使用{}占位符的形式,避免资源的占用。