teo*_*teo 8 scala parameter-passing slf4j callbyname
这里有两个似乎被普遍接受的陈述,但我无法真正克服:
1)Scala的副名称params优雅地替换了令人讨厌的log4j使用模式:
if (l.isDebugEnabled() ) {
logger.debug("expensive string representation, eg: godObject.toString()")
}
Run Code Online (Sandbox Code Playgroud)
因为在方法调用之前不会评估by-name-parameter(特定于Scala的语言特性).
2)但是,这个问题是通过slf4f中的参数化日志记录解决的:
logger.debug("expensive string representation, eg {}:", godObject[.toString()]);
Run Code Online (Sandbox Code Playgroud)
那么,这是如何工作的?在"调试"方法执行之前,slf4j库中是否存在一些阻止参数评估的低级魔法?(甚至可能吗?图书馆可以影响语言的这一基本方面吗?)
或者只是一个简单的事实,一个对象被传递给方法 - 而不是一个字符串?(并且可能在debug()方法本身中调用该对象的toString()(如果适用).
但那么,log4j也不是这样吗?(它确实有Object params的方法).这不意味着如果你传递一个字符串 - 如上面的代码 - 它的行为与log4j相同吗?
我真的很想在这个问题上有一些亮点.
谢谢!
Pet*_*lák 24
slf4j没有魔力.记录的问题曾经是,如果你想记录让我们说
logger.debug("expensive string representation: " + godObject)
Run Code Online (Sandbox Code Playgroud)
那么无论是否在记录器中启用了调试级别,您始终都会评估godObject.toString()哪些操作可能是昂贵的操作,然后是字符串连接.这很简单,因为在Java(和大多数语言)参数在传递给函数之前进行了评估.
这就是slf4j引入的原因logger.debug(String msg, Object arg)(以及更多参数的其他变体).整个想法是你将廉价参数传递给debug函数并调用toString它们并仅在调试级别打开时将它们组合成一条消息.
请注意,通过电话
logger.debug("expensive string representation, eg: {}", godObject.toString());
Run Code Online (Sandbox Code Playgroud)
你大大减少了这个优势,因为无论调试级别是什么,这种方式都会godObject在你传递之前一直转换debug.你应该只使用
logger.debug("expensive string representation, eg: {}", godObject);
Run Code Online (Sandbox Code Playgroud)
但是,这仍然不太理想.它只保留调用toString和字符串连接.但是,如果您的日志消息需要一些其他昂贵的处理来创建消息,那么它将无济于事.就像你需要调用一些expensiveMethod来创建消息一样:
logger.debug("expensive method, eg: {}",
godObject.expensiveMethod());
Run Code Online (Sandbox Code Playgroud)
然后expensiveMethod总是在传递之前进行评估logger.为了使用slf4j有效地工作,你仍然需要回归
if (logger.isDebugEnabled())
logger.debug("expensive method, eg: {}",
godObject.expensiveMethod());
Run Code Online (Sandbox Code Playgroud)
Scala的call-by-name在这个问题上有很多帮助,因为它允许您将任意代码片段包装到函数对象中,并仅在需要时评估该代码.这正是我们所需要的.我们来看看 slf4s.这个库暴露了像这样的方法
def debug(msg: => String) { ... }
Run Code Online (Sandbox Code Playgroud)
为什么没有像slf4j那样的论据Logger?因为我们不再需要它们了.我们可以写
logger.debug("expensive representation, eg: " +
godObject.expensiveMethod())
Run Code Online (Sandbox Code Playgroud)
我们不传递消息及其参数,我们直接传递一条被评估的消息代码.但只有记录器决定这样做.如果调试级别没有打开,那么任何logger.debug(...)内容都不会被评估,整个过程就会被跳过.既没有expensiveMethod被调用也没有任何toString调用或字符串连接发生.所以这种方法最通用,最灵活.无论它有多复杂,您都可以将任何计算结果的表达式传递给Stringto debug.