2014-09-15 10 views
7

Ich mache ein Projekt in Scala und ich verwende Slf4j mit Logback für die Protokollierung. Jetzt scheint die Protokollierungsinitialisierung nicht Thread-sicher zu sein. Als eine Lösung erzeugt slf4j Ersatzlogger, d. H. NoOp-Logger, die Protokollanweisungen, die während der Initialisierung gemacht werden, verschlucken. The slf4j homepage Staaten zu diesem Thema:SLF4J Initialisierung - Ersatz Logger

Ersatzlogger wurden während der Standardkonfiguration Phase des zugrunde liegenden Protokollsystem erstellt

Hoch konfigurierbare Protokollierungssysteme wie logback und log4j Komponenten erstellen können, die Logger während ihrer eigenen Initialisierung aufrufen. Siehe Ausgabe LOGBACK-127 für ein typisches Auftreten. Da der Bindungsprozess mit SLF4J jedoch noch nicht abgeschlossen ist (weil das zugrunde liegende Protokollierungssystem noch nicht vollständig in den Arbeitsspeicher geladen wurde), können diese Anforderungen für die Protokollerstellung nicht berücksichtigt werden.

Um dieses Henne-und-Ei-Problem zu vermeiden, erstellt SLF4J Ersatzlogger während dieser Phase (Initialisierung). Anrufe, die während dieser Phase an die Ersatzlogger gesendet werden, werden einfach verworfen. Nach Abschluss der Initialisierung wird der Ersatzprotokollierer Protokollierungsaufrufe an die entsprechende Protokollimplementierung delegieren und ansonsten wie jeder andere von LoggerFactory zurückgegebene Protokollierer funktionieren.

Wenn ein Ersatzlogger erstellt werden muss, gibt SLF4J eine Liste solcher Logger aus. Diese Liste soll Sie darüber informieren, dass Protokollierungsaufrufe, die während der Initialisierung an diese Protokollierer gesendet wurden, gelöscht wurden.

Es gibt auch eine noch ungelöste issue beschreibt das Problem.

Für mich trat das Problem auf, als ich prüfte, wie Teile der Anwendung zusammenarbeiten. Log-Anweisungen eines Produzenten, die in einem eigenen Thread laufen, gingen verloren, weil sie an einen Ersatz-Logger gesendet wurden. Das Hinzufügen einer Protokollanweisung kurz vor dem Erstellen des Erzeuger-Threads schien dabei zu helfen, den Logger rechtzeitig zu initialisieren. Ich würde jedoch gerne wissen, ob ein beliebiger Aufruf von LoggerFactory.getLogger als erste Anweisung in der Anwendung garantiert, dass ich mich nie an einen Ersatzlogger anmelden werde.

Kurz gesagt, meine Fragen sind:

  • Does LoggerFactory.getLogger (classof [A]) alle Logger instanziiert, oder könnte es, dass zwei Jahre später sein, gleichzeitige Anrufe zu LoggerFactory.getLogger (classof [B ]) wird einen Ersatzlogger ergeben?

  • Gibt es eine Möglichkeit, eine Garantie zu erhalten, das heißt, um zu überprüfen, dass ein Logger initialisiert wurde (ich kann nicht den Typ des Loggers überprüfen, da sie durch die slf4j Fassade versteckt) bearbeiten: Eigentlich Ich habe gerade gedacht, dass ich den Typ des Loggers überprüfen könnte. Könnten die folgenden Gedanken zu einer nützlichen Lösung ?: führen

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

    Das Problem, das ich mit diesem Ansatz ist, dass es auf einer Implementierung spezifische Klasse abhängt, das heißt NOPLogger SubstituteLogger.

Nachtrag: Ich bin nicht sicher, ob dies von Bedeutung für diese Frage, aber ich bin mit dem slf4j Logger in einer Klasse Verpackung, die für jeden Protokollkontext instanziiert wird (context = die Klasse, die anruft, der Logger).Außerdem gibt es ein Objekt, das Instanzen dieses Wrappers erstellt, der als implizites Konstruktorargument an jede Klasse übergeben wird, die die Protokollierung durchführen möchte. Ich gebe den Logger als Argument weiter, anstatt mich auf ein statisches Objekt einzuloggen (oder ein Merkmal zu mischen), um die Weitergabe eines speziellen Loggers in den Komponententests zu ermöglichen.

+0

Wir waren gerade dies mit Akka ... Es wurde wegen der Logger Initialisierung gemacht wurde mehrmals gleichzeitig (zum ersten Mal einen Logger zugreifen). Das Hinzufügen eines Dummy-Logs beim Start der App hat das Problem behoben. – LMeyer

Antwort

0

Ich stieß auf das gleiche Problem, weil mehrere Abhängigkeiten ihre eigenen doppelten Kopien des NoOp Loggers brachten. Die Lösung war in meinem Fall ausdrücklich die inhereted depencency auf slf4j-log4j12 über:

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