slf4j 没有魔法。日志记录的问题曾经是,如果你想记录让我们说
logger.debug("expensive string representation: " + godObject)
那么无论是否在记录器中启用了调试级别,您总是评估godObject.toString()
哪个可能是一项昂贵的操作,然后还要进行字符串连接。这仅仅是因为在 Java(和大多数语言)中,参数在传递给函数之前会被评估。
这就是引入 slf4j 的原因logger.debug(String msg, Object arg)
(以及更多参数的其他变体)。整个想法是,您将廉价的参数传递给debug
函数,它会调用toString
它们并将它们组合成一条消息,只有在调试级别打开时。
请注意,通过调用
logger.debug("expensive string representation, eg: {}", godObject.toString());
你大大降低了这个优势,因为这样你godObject
在传递它之前一直在转换debug
,无论调试级别是什么。你应该只使用
logger.debug("expensive string representation, eg: {}", godObject);
但是,这仍然不理想。它只保留调用toString
和字符串连接。但是,如果您的日志消息需要一些其他昂贵的处理来创建消息,那将无济于事。就像您需要调用一些expensiveMethod
来创建消息一样:
logger.debug("expensive method, eg: {}",
godObject.expensiveMethod());
thenexpensiveMethod
在传递给 之前总是被评估logger
。为了让 slf4j 有效地完成这项工作,您仍然必须求助于
if (logger.isDebugEnabled())
logger.debug("expensive method, eg: {}",
godObject.expensiveMethod());
Scala 的名称调用在这方面有很大帮助,因为它允许您将任意一段代码包装到一个函数对象中,并仅在需要时评估该代码。这正是我们所需要的。例如,让我们看一下 slf4s。这个库公开了类似的方法
def debug(msg: => String) { ... }
为什么没有像 slf4j 中的参数Logger
?因为我们不再需要它们了。我们可以只写
logger.debug("expensive representation, eg: " +
godObject.expensiveMethod())
我们不传递消息及其参数,我们直接传递一段对消息进行评估的代码。但前提是记录器决定这样做。如果调试级别未打开,logger.debug(...)
则不会评估其中的任何内容,整个事情都会被跳过。既没有expensiveMethod
被调用,也没有任何toString
调用或字符串连接发生。所以这种方法是最通用和最灵活的。您可以传递任何计算结果为 to 的表达式,String
无论debug
它有多复杂。