Ich versuche, die log4j2-Konfigurationstutorials in einem SBT 0.12 zu befolgen. 1 Projekt. Hier ist meine build.sbt :
%Vor% Ich habe zwei getrennte Hauptklassen. Die erste ist logtest.ScalaTest
in src / main / scala / logtest / ScalaTest.scala :
und der zweite ist logtest.JavaTest
in src / main / java / logtest / JavaTest.java :
Wenn ich logtest.ScalaTest.main()
von innerhalb von sbt ausfühle, bekomme ich die Ausgabe, die ich erwartet habe, da src / main / resources / log4j2.xml die Root-Protokollierungsebene auf Trace setzt:
Wenn ich jedoch logtest.JavaTest.main()
von sbt aus starte, bekomme ich eine andere Ausgabe
Soweit ich das beurteilen kann, ist ERROR StatusLogger Unable to ...
normalerweise ein Zeichen dafür, dass sich log4j-core nicht in meinem Klassenpfad befindet. Das Fehlen von TRACE-Nachrichten scheint anzuzeigen, dass sich meine Einstellungen von log4j2.xml auch nicht im Klassenpfad befinden. Warum sollte es Unterschiede im Klassenpfad geben, wenn ich Foo.main im Gegensatz zu LoggerTest.main verwende? Oder gibt es noch etwas, das dieses Verhalten verursacht?
Ich habe SBT Assembly verwendet, um ein Fat-Jar dieses Projekts zu erstellen, und logtest.JavaTest als Hauptklasse angegeben. Das Ausführen von der Befehlszeile erzeugte korrekte Ergebnisse:
%Vor%Dem Vorschlag von Edmondo1984 folgend, habe ich ein komplettes Beispiel zusammengestellt und auf github gestellt.
Diese Art von Problemen sind sehr oft auf Klassenladeunterschiede zurückzuführen und in diesem Fall ist der Unterschied nicht trivial.
Während dieser Initialisierungsphase wird der statische Initiator LogManager
aufgerufen, wenn die Klasse zum ersten Mal geladen wird. Wenn Sie in den statischen Initialisierer schauen, sehen Sie:
Später im Code sehen Sie eine Schleife über die Enum-Ressourcen, um die Logger-Kontext-Factory zu erstellen.
Wenn Sie jedoch die Scala-Klasse ausführen, gibt enumResources.hasMoreElements()
true zurück, während Sie beim Ausführen der Java-Klasse false zurückgeben (also keinen Logger-Kontext und keine Logger) überhaupt zum LogManager hinzugefügt).
Wenn Sie weiter untersuchen, werden Sie sehen, dass die Variable Wenn Sie den Anfang des statischen Initialisierers betrachten, sehen Sie folgende Aussage: Vielleicht möchten Sie sich also die Methode In beiden Fällen, da der SecurityManager nicht null ist, wird der aktuelle Threadkontextklassenlader zurückgegeben. Was für Ihre Java-Klasse und Ihre Scala-Klasse anders ist. cl
tatsächlich ein Klassenlader ist, der im Fall der Java-Klasse eine Instanz von sun.misc.Launcher$AppClassLoader
ist, während für die Scala-Klasse eine Instanz sbt.classpath.ClasspathUtilities$$anon
findClassLoader()
ansehen: