3

似乎 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

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

4

3 回答 3

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")
}
于 2010-11-26T15:03:02.153 回答
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 服务

于 2010-11-27T12:44:28.423 回答
-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 = // ...
}
于 2010-11-26T15:47:18.030 回答