[英]Instrumenting (logging) Scala expressions
( UPD after @krivachy.akos ) (@ krivachy.akos之后的UPD )
How to debug expressions in Scala? 如何在Scala中调试表达式? You don't have an opportunity to set a breakpoint and see local variables in most cases because inside the expression there are no variables. 大多数情况下,您没有机会设置断点并查看局部变量,因为在表达式内部没有变量。 And usually there are no statements to which you can set a breakpoint. 通常,没有可设置断点的语句。
One old way of debugging is to have the code instrumented. 调试的一种旧方法是对代码进行检测。 This gives an indispensable information about the internal processing of expressions. 这提供了有关表达式内部处理的必不可少的信息。
However, in a typical logging implementation there are no direct ways of intercepting expressions. 但是,在典型的日志记录实现中,没有截取表达式的直接方法。 In particular, a typical logger have methods with Unit
return type: 特别是,典型的记录器具有Unit
返回类型的方法:
def debug(msg: =>String) {...}
To use the logger one have to rewrite concise expression in a way to be able to call logger: 要使用记录器,必须以一种能够调用记录器的方式重写简洁的表达式:
Example 1 : 范例1 :
if you have some boolean-based rules with complex conditions and multiple evaluation paths: 如果您有一些具有复杂条件和多个评估路径的基于布尔的规则:
val x = if(condition1(a,b))
Some(production1(a,b))
else if(condition2(c,d))
Some(production2(a,b))
else
None
then it is hard to make sure it works as desired. 那么很难确保它能够按需工作。 ( It's not always possible to avoid complex rules altogether. And representation rules in OOP-style is not always good.) (并非总是可以完全避免使用复杂的规则。而且,OOP风格的表示规则并不总是很好。)
Then a typical instrumentation would require introduction of some intermediate variables and blocks of code: 然后,典型的检测将需要引入一些中间变量和代码块:
debug("a="+a)
debug("b="+b)
val x = if(condition1(a,b)) {
debug("rule1 hit")
val production = production1(a,b)
debug("rule1 result: "+production)
Some(production)
} else {
debug("rule1 doesn't hit")
debug("c="+c)
debug("d="+d)
if(condition2(c,d)){
debug("rule2 hit")
Some(production2(a,b))
} else
None
}
Example 2 : 范例2 :
def f(list:List[Int]) =
list.
map(_*2).
flatMap(t =>
(0 until t).
map(_+1)
)
Instrumentation will lead to some intermediate variables: 检测将导致一些中间变量:
def f(list:List[Int]) = {
val twiced = list.map(_*2)
debug(s"twiced = $twiced")
val result = twiced.flatMap(t => {
val widened = (0 until t).map(_+1)
debug(s"widened = $widened")
widened
})
debug(s"result = $result")
result
}
Very ugly, I suppose. 我想很丑。 And this instrumentation takes more space than the code itself. 而且这种检测比代码本身占用更多的空间。 The main reason, I think, is that the logger is incompatible with an expression evaluation style. 我认为,主要原因是记录器与表达式评估风格不兼容。
Is there a way to log expression values in a more concise way? 有没有一种方法可以更简洁地记录表达式值?
I recently found a nice way of logging the value of an expression: 我最近发现了一种记录表达式值的好方法:
trait Logging {
protected val loggerName = getClass.getName
protected lazy val logger = LoggerFactory.getLogger(loggerName)
implicit class RichExpressionForLogging[T](expr: T){
def infoE (msg: T ⇒ String):T = {if (logger.isInfoEnabled ) logger.info (msg(expr)); expr}
def traceE(msg: T ⇒ String):T = {if (logger.isTraceEnabled) logger.trace(msg(expr)); expr}
def debugE(msg: T ⇒ String):T = {if (logger.isDebugEnabled) logger.debug(msg(expr)); expr}
def infoL (msg: String):T = {if (logger.isInfoEnabled ) logger.info (msg+expr); expr}
def traceL(msg: String):T = {if (logger.isTraceEnabled) logger.trace(msg+expr); expr}
def debugL(msg: String):T = {if (logger.isDebugEnabled) logger.debug(msg+expr); expr}
}
}
Here how it is used: 这里是如何使用的:
Example 1 (rules): 示例1(规则):
val x = if(condition1(a.debugL("a="),b.debugL("b=")))
Some(production1(a,b).debugL("rule1="))
else if(condition2(c,d))
Some(production2(a,b).debugL("rule2="))
else
None
Example 2: 范例2:
def f(list:List[Int]) =
list.
map(_*2).
debugE(s"res1="+_).
flatMap(t => (0 until t).
map(_+1).
debugE(s"res2="+_)).
debugE(s"res="+_)
It can also be used everywhere in expressions: 它也可以在表达式中的任何地方使用:
if((a<0).debugE(s"a=$a<0="+_))
for{
a <- f(list).debugE("f(list)="+_)
b <- a.debugL("a=")
} yield b.debugL("b=")
Of course you should mix-in Logging trait to your class. 当然,您应该在班级中混入Logging特性。
This kind of instrumentation doesn't hide the logic of the code. 这种检测不会隐藏代码的逻辑。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.