在 scala 中定义 Logging Trait 时出现问题

发布于 2024-10-04 18:11:27 字数 1023 浏览 7 评论 0原文

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

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

It seems that common logging pattern in scala is to use a Logging trait which is mixed with concrete class (cf. open source projects like Liftweb, akka, ...).

Something like that:

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

This is exactly what I'm using right know, but I'm stuck with a problem because of this pattern. Indeed if the Logging trait is mixed by a class that is derived, the Logger will be used with the name of the most derived class.

Here is an example to clarify myself:

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
  }
}

When I run this program I got:

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

Instead of:

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

Has anyone found a solution to this problem ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

空气里的味道 2024-10-11 18:11:27

我可以使用伴随对象中的记录器来实现这种效果:

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")
}

I could achieve this effect using loggers in companion objects:

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")
}
日暮斜阳 2024-10-11 18:11:27

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

当您有一些包含方法重写的类层次结构时,您的日志可能充满如下行:

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 服务

It is my experience that this is most definitely not the behaviour that you want.

When you have some class hierarchy which contains method overriding, your logs might be full of lines which look like:

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

And you will be asking yourself what concrete service implementation were you dealing with? If you don't know, how can you be sure what code path was taken to get where you are? Maybe there should have been a 3rd statement nestling inbetween the two:

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

Much easier to debug if the logs contained

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

Because then you can tell immediately that you are using the wrong foo service

丑丑阿 2024-10-11 18:11:27

这可能是显而易见的,但如果您不希望继承 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 = // ...
}

This might be obvious, but if you don’t want the Logging trait to be inherited, you could simply use a private variable instead of mixing in a trait.

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

class B extends A with Logging {
}

or

class A extends Logging {
}

class B extends A {
  override lazy val log = // ...
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文