在scala中定义Logging特征时出现问题

时间:2010-11-26 14:34:49

标签: scala logging traits

scala中的常见日志记录模式似乎是使用与具体类混合的Logging特征(参见Liftweb,akka等开源项目)。

类似的东西:

trait Logging {
  val loggerName = this.getClass.getName
  @transient lazy val log = new Logger(loggerName)
}

这正是我正确使用的知识,但由于这种模式,我遇到了问题。实际上,如果Logging特征由派生的类混合,则Logger将与最派生类的名称一起使用。

这是一个澄清自己的例子:

class Logger(logName : String){
  def debug( msg : String ) { println("["+logName+"] : "+msg) }
}

trait Logging {
  val loggerName = this.getClass.getName
  @transient lazy val log = new Logger(loggerName)
}

package a {
  class A extends Logging {
    log.debug("log from A")
  }
}

package b {
  import a._
  class B extends A with Logging {
    log.debug("log from B")
  }
}

object LogTest {
  import b._
  def main(args : Array[String]) = {
    val instance = new B
  }
}

当我运行这个程序时,我得到了:

[b.B] : log from A
[b.B] : log from B

而不是:

[a.A] : log from A
[b.B] : log from B

有没有人找到解决这个问题的方法?

3 个答案:

答案 0 :(得分:2)

我可以使用伴侣对象中的记录器来实现此效果:

object A extends Logging; 
class A { import A._
  log.debug("log from A")
}

object B extends Logging; 
class B extends A  { import B._
  log.debug("log from B")
}

答案 1 :(得分:2)

根据我的经验,这绝对是不是您想要的行为

当你有一些包含方法覆盖的类层次结构时,你的日志可能会充满看起来像这样的行:

13:44:42.654 - AbstractFooService [INFO] : I have a: foo
13:44:42.656 - AbstractFooService [INFO] : I have bar-d my: foo

你会问自己,你正在处理的是什么具体的服务实现?如果您不知道,您如何确定采用哪种代码路径来获取您的位置?也许在两者之间应该有一个第三个陈述:

13:44:42.655 - SpecialFooService [INFO] : I want to baz this foo to bar

如果包含日志

,则更容易调试
13:44:42.654 - DefaultFooService [INFO] : I have a: foo
13:44:42.656 - DefaultFooService [INFO] : I have bar-d my: foo

因为那时你可以告诉 你正在使用错误的foo服务

答案 2 :(得分:-1)

这可能是显而易见的,但如果您不希望继承Logging特征,则可以简单地使用私有变量而不是混合特征。

class A {
  private val log = Logger(this)
}

class B extends A with Logging {
}

class A extends Logging {
}

class B extends A {
  override lazy val log = // ...
}