在Scala中调试日志,不会影响性能

时间:2012-08-20 19:42:23

标签: debugging scala optimization logging preprocessor

在像C / C ++ / Objective-C这样的语言中,通常使用预处理器宏来定义甚至不为已发布的二进制文件编译的日志记录机制,从而不会导致性能损失。有点像:

#ifdef DEBUG
printf("some event we want to log\n");
#endif

现在,我知道Scala中没有预处理器。所以我的问题是:为了调试目的,实现记录程序活动的机制的最佳方法是什么,而在关闭时影响性能最少?

3 个答案:

答案 0 :(得分:15)

您可以使用scala.annotation.elidable

  

可以在生成的代码中删除调用的方法的注释。

     

行为受到将-Xelide-below传递给scalac的影响。如果给定注释的优先级低于命令行参数,则生成的代码中将省略标记为elidable的方法。例子:

答案 1 :(得分:5)

当前的做法(在Scala 2.9.x或更早版本中)是使用thunk类型(例如,参见Scala的简单日志外观SLFS):

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

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

这通常比实际构造字符串便宜,因为字符串创建(以及任何后续活动)仅在logging为真时才完成。但是,它仍然会产生上面的thunk x的闭包创建成本。

但是,从Scala 2.10.x开始,标准发行版中包含一个实验宏实现(请参阅this pageSIP)。宏系统将允许您编写几乎没有运行时成本的日志记录调用(logging变量检查除外) - 它们允许您内联调用log,以便:

log("var1: " + myVar1)

变为:

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

请注意,在这种情况下,没有为log创建关闭,并且仅在logging为真时才评估日志消息字符串 - 成本仅为if-check。

答案 2 :(得分: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())