我正在使用Scala进行项目开发,使用slf4j和Logback进行日志记录。现在,日志初始化似乎不是线程安全的。作为解决方案,slf4j正在创建替代日志记录器,即NoOp-日志记录器,在初始化期间吞噬日志语句。 slf4j主页 在这个问题上有所说明:
替代日志记录器是在底层日志记录系统的默认配置阶段创建的。高度可配置的日志记录系统,如logback和log4j,可能会创建在其自身初始化期间调用日志记录器的组件。参见问题LOGBACK-127以获得典型情况。然而,由于与SLF4J的绑定过程尚未完成(因为底层日志记录系统尚未完全加载到内存中),因此无法满足此类日志记录器创建请求。为避免这个鸡生蛋的问题,SLF4J在此阶段(初始化)创建替代日志记录器。在此阶段对替代日志记录器进行的调用将被简单地丢弃。初始化完成后,替代日志记录器将委托日志记录调用到适当的日志记录器实现,并且否则将像LoggerFactory返回的任何其他日志记录器一样运行。如果必须创建任何替代日志记录器,则SLF4J将发出此类日志记录器的列表。此列表旨在让您知道在初始化期间对这些日志记录器进行的任何日志记录调用都已被删除。还有一个尚未解决的issue描述了这个问题。
对我来说,问题出现在我测试应用程序的部分如何协同工作时。由于发送到替代记录器,所以运行在其自己的线程中的生产者的日志记录语句丢失了。似乎在创建生产者线程之前添加一个日志记录语句有助于及时初始化记录器。但是,我想知道作为应用程序中第一条语句的任意调用LoggerFactory.getLogger是否保证我永远不会记录到替代记录器。
简而言之,我的问题是:
Does LoggerFactory.getLogger(classOf[A]) instantiate all loggers, or could it be that two later, concurrent calls to LoggerFactory.getLogger(classOf[B]) will yield one substitute logger?
Is there a way to obtain a guarantee, i.e., to check, that a logger has been initialized (I cannot check the type of the logger, since it is hidden by the slf4j facade) Edit: Actually, I just figured that I might be able to check the type of the logger. Could the following thoughts lead to a useful solution?:
def logger(context: Class[_]) = { log = LoggerFactory.getLogger(context) if (log.isInstanceOf[SubstituteLogger]) logger(context) else log
The problem I see with this approach is that it depends on one implementation specific class, i.e.,
NOPLoggerSubstituteLogger.
补充: 我不确定这是否与此问题相关,但我正在将slf4j记录器包装在一个类中,该类为每个日志记录上下文(上下文=调用记录器的类)实例化。另外,有一个对象创建此包装器的实例,并作为隐式构造函数参数传递给每个要进行记录的类。我将记录器作为参数传递而不是记录到静态对象(或混合特征),以便在单元测试中传递特殊记录器。
log
是SubstituteLogger时的问题。 - mauhiz