在Scala中进行调试日志,不影响性能。

7
在像C/C++/Objective-C这样的语言中,通常使用预处理器宏来定义日志机制,这些机制甚至不会在发布的二进制文件中编译,因此不会造成性能损失。例如:
#ifdef DEBUG
printf("some event we want to log\n");
#endif

现在,我知道Scala没有预处理器。因此,我的问题是:在不影响性能的情况下,实现用于调试目的的记录程序活动的最佳方法是什么?

3个回答

15
您可以使用 scala.annotation.elidable
这是一个用于标记方法的注解,标记该方法可能在生成的代码中被移除。
传递 -Xelide-below 参数给 scalac 可以影响其行为。如果该方法被标记为可消除(elidable),且注解的优先级低于命令行参数,则该方法将从生成的代码中省略。例如:

这是一个不错的想法,但并非完美:它与C/C++方法非常相似。但现在你需要管理多个编译二进制版本,而不是只有一个。 - Rick-777

5

目前的实践(在Scala 2.9.x或之前的版本中)是使用thunk类型(例如,参见Simple Logging Facade for Scala SLFS):

def log(x: =>Any) = if (logging) println(x)

// later in code
log("var1: " + myVar1)

这通常比实际构造字符串更便宜,因为只有在 logging 为真时才会创建字符串(以及任何后续活动)。然而,对于上面的 x thunk,它仍然需要闭包创建的成本。

然而,从Scala 2.10.x开始,在标准发行版中包含了一个实验性的宏实现(请参见此页面SIP)。宏系统允许您编写几乎没有运行时成本的日志记录调用(除了检查 logging 变量)- 它们允许您内联调用 log,这样就可以:

log("var1: " + myVar1)

成为:

if (logging) log("var1: " + myVar1)

请注意,在此情况下,log没有创建闭包,只有在logging为真时才会评估日志记录消息字符串-成本仅为if-check。

5
宏也可以自省编译器设置,如果这些设置告诉它完全省略日志,则可以发出空树。 - Eugene Burmako
如果您在编译时知道不需要记录日志,则完全没有运行时成本,这是真的。 - axel22
谢谢,这正是我在寻找的简单解决方案!我知道2.10.x上有实验性宏实现,并期待着尝试它,但目前我仍在使用2.9。 - telmomenezes
1
你可能想看一下@senia提到的@elidable - axel22

1

Log4J是一种常见的JVM日志框架。它专门设计为对性能影响最小:

在运行JDK 1.3.1的800Mhz AMD Duron上,确定是否应记录日志语句的成本约为5纳秒。实际记录日志也非常快,使用SimpleLayout时范围为21微秒,使用TTCCLayout时范围为37微秒。PatternLayout的性能几乎与专用布局一样好,只是更加灵活。

因此,当您进行如下调用时:

LOG.debug("something here")

框架将首先检查是否启用了“debug”日志记录。这个检查非常快速。如果禁用了日志记录,则不会再执行任何工作。

然而,有一个注意点。如果您编写

LOG.debug(expensiveOperation())

那么在执行昂贵的操作之前,框架将不会进行启用调试的检查。纠正这种情况的方法是:

if(LOG.isDebugEnabled) LOG.debug(expensiveOperation())

Log4J已经严重过时。构建字符串可能很耗费资源,特别是当您将多个值连接在一起时。例如,SLF4J(或SLFS)仅在需要时使用简单的策略构建字符串。 - paradigmatic
@paradigmatic:看代码,SLF4S正在做相同的事情(if (slf4jLogger.isDebugEnabled) slf4jLogger.debug(msg, t)),但将消息包装在闭包中。因此,它并没有为您节省任何东西,反而增加了创建闭包的成本。闭包版本确实更清晰,但我认为您不能声称它更快。 - dhg
1
这应该与构建字符串的成本进行比较,例如:"Request: " + request + "; context: " + ctx + "; version: " + v。使用按名称调用或 slf4j 中使用的策略可以取消该成本。 - paradigmatic
@paradigmatic 是正确的,SLF4J允许在可变参数中传递消息占位符,因此只有在启用日志记录时才构建“真实”的字符串。 - Sebastien Lorber

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接