Java日志框架中须要判断log.isDebugEnabled()吗?
背景
在日常开发中,我的项目会应用形象日志接口slf4j来打印日志。如下是一段典型的打印日志代码:
logger.debug("hello, world");
然而在一些我的项目或第三方开源框架中,也会发现有些代码在输入日志时,在后面增加if判断,代码如下:
if(logger.isDebugEnabled()){ logger.debug("hello, world");}
简略来说,先应用isDebufEnabled
来判断日志级别。这么写的目标是什么呢?而且网上有些文档指出这种判断其实是不须要的。那理论开发中,咱们到底要不要判断isDebugEnabled
呢?心愿通过这篇文章来分享一些我对日志打印的思考。
简略的源码分析
有些人不明确为什么要增加if判断,会认为这样是为了管制日志的输入。其实这是不对的。对于上面的两段代码:
logger.debug("hello, world")
if(logger.isDebugEnabled()){ logger.debug("hello, world");}
如果利用的日志级别大于debug
,比方为info
。那么这两段代码,最终都不会输入日志。在debug
办法外部,会判断日志级别,如果利用级别大于日志级别,就不会输入日志。以下是isDebugEnabled
和debug
的外围代码(我删除了一些无关代码):
isDebugEnabled
办法:
public boolean isDebugEnabled(Marker marker) { final FilterReply decision = callTurboFilters(marker, Level.DEBUG); if (decision == FilterReply.NEUTRAL) { return effectiveLevelInt <= Level.DEBUG_INT; } else { throw new IllegalStateException("Unknown FilterReply value: " + decision); } }
debug
办法:
private void filterAndLog_0_Or3Plus(final String localFQCN, final Marker marker, final Level level, final String msg, final Object[] params, final Throwable t) { final FilterReply decision = loggerContext.getTurboFilterChainDecision_0_3OrMore(marker, this, level, msg, params, t); if (decision == FilterReply.NEUTRAL) { if (effectiveLevelInt > level.levelInt) { return; } } else if (decision == FilterReply.DENY) { return; } buildLoggingEventAndAppend(localFQCN, marker, level, msg, params, t); }
那么问题来了,既然isDebugEnabled
不会影响日志是否输入,那为什么要增加这个判断呢?
为什么要增加if判断
咱们思考上面几段代码:
代码清单一:
logger.debug("hello, world")
代码清单二:
if(logger.isDebugEnabled()){ logger.debug("hello, world")}
代码清单三:
logger.debug("hello" + "world");
代码清单四:
logger.debug(String.format("hello, %s", "world"))
代码清单五:
logger.debug("hello {}", "world");
以上5段代码,如果利用日志级别为info,那么这5段代码都不会输入日志。它们的差别其实是性能不同。上面咱们来一一剖析。
- 代码清单一:执行
debug
办法。debug
办法外部判断日志级别,而后退出。 - 代码清单二:
isDebugEnabled
判断日志级别,而后退出。 - 代码清单三:先拼接字符串“hello”和“world”。而后执行
debug
办法。 - 代码清单四:先执行
String.format
办法,而后执行debug
办法。 - 代码清单五:执行
debug
办法。
大家发现了吗?尽管最终都不会输入日志,但这5段代码还是有差别的。代码清单三和代码清单四别离执行了"+"字符串拼接和String.format
办法,但最终却没用到。也就是说,这两段代码执行了一些无用操作,造成了额定的性能损耗。
所以,代码清单二中增加isDebugEnabled
能够防止无用的字符串操作,进步性能。
isDebugEnabled
是必须的吗?
上一节中,我提到应用isDebugEnabled
能够晋升性能,那是不是在所有中央都须要增加isDebugEnabled
判断呢?
先说论断,不是的。应该依据具体场景来判断是否增加isDebugEnabled
。
比方上面的代码:
logger.debug("hello, world");
打印一条日志“hello,world”。那么这时候就不必增加isDebugEnabled
判断了。对于isDebugEnabled
的应用场景,总结了如下的最佳实际:
isDebugEnabled
最佳实际
准则一:如果打印字符串常量,不须要isDebugEnabled
比拟上面两段代码:
logger.debug("hello, world");
if(logger.isDebugEnabled()){ logger.debug("hello, world");}
因为打印的日志是字面常量,没有计算逻辑。两段代码的性能是简直一样的。增加isDebugEnabled
反而会导致额定的代码。
准则二:如果有参数,且参数只是字符串常量或计算简略,应用占位符
思考如下代码,debug
办法蕴含了参数user.getName()
。尽管执行debug
办法时,会计算user.getName()
,但只是一个简略的get办法,没有简单计算,这时候,也能够不增加isDebugEnabled
。
logger.debug("hello, {}", user.getName());
准则三:如果有参数,且参数计算简单,增加isDebugEnabled
logger.debug("order price: {}", calculatePrice());
假如calculatePrice
办法须要通过简单计算。那么就应该增加isDebugEnabled
判断,应用如下的代码:
if(logger.isDebugEnabled()){ logger.debug("order price: {}", calculatePrice());}