如何在*每个实例*中没有*引用记录器的情况下登录Scala *?

时间:2011-06-24 09:53:50

标签: scala logging singleton

我已经看过在Scala中登录的示例,它通常看起来像这样:

import org.slf4j.LoggerFactory

trait Loggable {
  private lazy val logger = LoggerFactory.getLogger(getClass)
  protected def debug(msg: => AnyRef, t: => Throwable = null): Unit =
    {...}
}

这似乎与具体的日志记录框架无关。虽然这样做了,但它还在每个想要进行日志记录的实例中引入了一个无关的延迟val ,这可能是整个应用程序的每个实例。这对我来说似乎太沉重了,特别是如果你有许多特定类型的“小实例”。

有没有办法将记录器放在具体类的对象中,只需使用继承?如果我必须在类的对象中显式声明记录器,并从类/特性中显式地引用它,那么我编写的代码几乎和我根本没有重用的代码一样多。

在非日志记录特定上下文中表示,问题是:

如何在特征中声明实现类必须具有X类型的单例对象,并且必须通过方法def x:X来访问此单例对象?

我不能简单地定义一个抽象方法,因为类中只能有一个实现。我希望在超级类中登录让我获得超类单例,并且登录子类会让我获得子类单例。或者更简单地说,我希望登录Scala能像Java中的传统日志一样工作,使用特定于执行日志记录的类的静态记录器。我目前对Scala的了解告诉我,如果不像Java那样完全相同,这是不可能的,使用“更好”的Scala没有太多好处。

4 个答案:

答案 0 :(得分:12)

过早优化是万恶之源

首先要明确一件事:如果你的特质看起来像这样:

trait Logger { lazy val log = Logger.getLogger }

然后完成的内容如下:

  • 您有 NOT 为您的类型
  • 创建了一个记录器实例
  • 你没有给自己留下记忆或性能问题(除非你有)

  • 您的类型的每个实例中都有一个额外的引用
  • 当您第一次访问记录器时,您可能正在进行一些地图查找

请注意,即使您确实为每个类型的实例创建了一个单独的记录器(我经常这样做,即使我的程序包含数十万个这样的记录器,所以我也很好 - 对我的日志记录的控制,你几乎可以肯定既没有性能也没有内存问题


一个“解决方案”是(当然),以使伴侣对象实现记录器接口:

object MyType extends Logger

class MyType {
  import MyType._
  log.info("Yay")
}

答案 1 :(得分:6)

  

如何在特征中声明   实施班必须有一个   X类型的单例对象,以及   这个单例对象必须是   可通过方法def x:X?

访问

声明必须由伴侣对象实现的特征。

trait Meta[Base] {
  val logger = LoggerFactory.getLogger(getClass)
}

为您的类创建基本特征,子类必须覆盖元方法。

trait Base {
  def meta: Meta[Base]
  def logger = meta.logger
}

一个类与伴侣对象无关:

object Whatever extends Meta[Base]

class Whatever extends Base {
  def meta = Whatever

  def doSomething = {
    logger.log("oops")
  }
}

通过这种方式,您只需要引用元对象。

我们可以使用这样的Whatever类。

object Sample {
  def main(args: Array[String]) {
    val whatever = new Whatever
    whatever.doSomething
  }
}

答案 2 :(得分:0)

我不确定我完全理解你的问题。如果这不是您正在寻找的答案,我会在前面道歉。

如果您将object放入logger,则定义trait,然后创建一个伴随object Loggable { private val logger = "I'm a logger" } trait Loggable { import Loggable._ def debug(msg: String) { println(logger + ": " + msg) } }

scala> abstract class Abstraction
scala> class Implementation extends Abstraction with Loggable
scala> val test = new Implementation
scala> test.debug("error message")
I'm a logger: error message

所以现在你可以像这样使用它:

{{1}}

这会回答你的问题吗?

答案 3 :(得分:0)

我认为您无法自动获取类的相应单例对象或要求存在这样的单例。

一个原因是在定义单例之前你无法知道它的类型。不确定,如果这有帮助或者它是您问题的最佳解决方案,但如果您想要使用特定特征定义某个元对象,您可以定义类似的内容:

trait HasSingleton[Traits] {
  def meta: Traits
}

trait Log {
  def classname: String
  def log { println(classname) }
}

trait Debug {
  def debug { print("Debug") }
}

class A extends HasSingleton[Log] {
  def meta = A // Needs to be defined with a Singleton (or any object which inherits from Log}
  def f {
    meta.log
  }
}
object A extends Log {
  def classname = "A"
}

class B extends HasSingleton[Log with Debug] { // we want to use Log and Debug here
  def meta = B
  def g {
    meta.log
    meta.debug
  }
}
object B extends Log with Debug {
  def classname = "B"
}

(new A).f
// A
(new B).g
// B
// Debug