SLF4J初始化 - 替代记录器

时间:2014-09-15 09:07:59

标签: scala logging slf4j logback race-condition

我在Scala中正在做一个项目,我正在使用slf4j和Logback进行日志记录。现在,日志记录初始化似乎不是线程安全的。作为一种解决方案,slf4j正在创建替代记录器,即NoOp-loggers,它吞下初始化期间生成的日志语句。 The slf4j homepage就此事发表声明:

  

替代记录器是在底层记录系统的默认配置阶段创建的

     

高度可配置的日志记录系统(如logback和log4j)可以创建在自己的初始化期间调用记录器的组件。有关典型事件,请参阅问题LOGBACK-127。但是,由于SLF4J的绑定过程尚未完成(因为底层日志记录系统尚未完全加载到内存中),因此无法遵守此类记录器创建请求。

     

为了避免这种鸡和蛋问题,SLF4J在此阶段(初始化)创建替代记录器。在此阶段对替代记录器进行的调用将被删除。初始化完成后,替代记录器会将日志记录调用委托给相应的记录器实现,否则将像LoggerFactory返回的任何其他记录器一样运行。

     

如果必须创建任何替代记录器,SLF4J将发出此类记录器的列表。此列表旨在让您知道在初始化期间对这些记录器进行的任何日志记录调用都已被删除。

还有一个尚未解决的issue描述了这个问题。

对我来说,当我测试部分应用程序如何协同工作时,问题就出现了。在自己的线程中运行的生产者的日志语句丢失了,因为它们被发送到替代记录器。在创建生产者线程之前添加日志语句似乎有助于及时初始化记录器。但是,我想知道对应用程序中的第一个语句的LoggerFactory.getLogger的任意调用是否保证我永远不会记录到替换记录器。

简而言之,我的问题是:

  • LoggerFactory.getLogger(classOf [A])是否实例化所有记录器,或者可能是后来两次对LoggerFactory.getLogger(classOf [B])的并发调用会产生一个替代记录器?

  • 有没有办法获得保证,即检查记录器是否已初始化(我无法检查记录器的类型,因为它被slf4j外观隐藏)编辑< / strong>:实际上,我只是想我可以检查记录器的类型。以下想法能否带来有用的解决方案?:

    def logger(context: Class[_]) = {
      log = LoggerFactory.getLogger(context)
      if (log.isInstanceOf[SubstituteLogger]) logger(context) else log
    

    我用这种方法看到的问题是它依赖于一个特定于实现的类,即 NOPLogger SubstituteLogger。

附录: 我不确定这是否与这个问题有关,但我将slf4j记录器包装在一个类中,该类为每个日志记录上下文实例化(context =调用记录器的类)。此外,还有一个对象创建此包装器的实例,该实例作为隐式构造函数参数传递给要进行日志记录的每个类。我将记录器作为参数传递,而不是记录到静态对象(或混合在特征中)以启用在单元测试中传递特殊记录器。

1 个答案:

答案 0 :(得分:0)

我遇到了同样的问题,因为多个依赖项带来了他们自己的NoOp Logger的重复副本。在我的案例中,解决方案明确表达了slf4j-log4j12通过以下方面的内在依赖性:

libraryDependencies = Seq(
  ...
  ).map(_.exclude("org.slf4j", "slf4j-log4j12" ))