2011-01-03 3 views
1

Ich habe eine gemeinsame Jar, die mehrere Web-Anwendungen verwenden. Alle Webanwendungen verwenden log4j. Jeder hat seine eigene log4j xml-Konfigurationsdatei, die im Wesentlichen die gleiche ist. Ich würde gerne eine gemeinsame log4j-Konfiguration in die mitgelieferte JAR-Datei und in jedes einzelne Web-Projekt legen, in dieser log4j-Konfiguration würde ich gerne in der Lage sein, einfach auf den in der JAR-Datei zu verweisen.bezieht sich auf Log4j-Konfigurationsdatei aus einer Log4j-Konfigurationsdatei im Klassenpfad

Ich sehe nichts in der Dokumentation, die ausdrücklich besagt, dass dies möglich ist. Ich frage mich, ob ich nur die Konfigurationsdatei aus den Webprojekten entfernen und sie in den allgemeinen jar einkleben könnte, wenn sie automatisch geladen würde, da sie auf dem Klassenpfad ist?

Am Ende möchte ich die Protokollierung einer bestimmten Anwendung für Debugging und Fehlerbehebung anpassen, ohne die allgemeine Konfiguration in der JAR-Datei zu ändern.

Antwort

1

Ich war an einem Projekt, wo ich brauchte Dutzende von Web-Anwendungen zu verwalten. Jede der Apps protokollierte etwas anders und es war ein großer Fehler, sie zu verwalten. Ich habe eine Strategie verwendet, die der von Ihnen beschriebenen ähnlich ist, um sie auf log4j zu standardisieren, und es hat sich sehr gut bewährt.

Grundsätzlich habe ich eine einzige common.jar erstellt, die gemeinsamen Code enthält. Diese JAR-Datei enthält eine Datei log4j.xml, die die Protokollebene auf INFO setzt und den Standard-Appender auf stdout für common.jar setzt. Diese log4j-Konfiguration wird als Basis für alle anderen Apps verwendet.

Für dieses Beispiel diese Klasse vorgeben ist innen common.jar:

public class ThirdPartyLib 
{ 
    protected static final Logger log = LogManager.getLogger("third-party-lib"); 
    public void doSomething() 
    { 
     log.debug("Third Party App is about to Do something!"); 
     log.info("Third Party App just did something"); 
    } 
} 

nun alle anderen Web-Anwendungen einfach auf common.jar verlassen können. Zum Beispiel so tun, als diese Klasse in myapp.war ist:

public class MyApp 
{ 
    public void CallThirdParty() 
    { 
     ThirdPartyLib lib = new ThirdPartyLib(); 
     lib.doSomething(); 
    } 
} 

Seit log4j.xml innerhalb common.jar ist, wird dieser Code so etwas wie dies loggt sein. Mit anderen Worten, es gibt keine Notwendigkeit log4j.xml innerhalb myapp.war zu setzen:

2011-01-03 15:49:22,451 [main] INFO third-party-lib - Third Party App just did something 

Nun, wenn Sie wollen/müssen, um die Protokollierung in myapp.war zu steuern, dann einfach eine log4j.xml innen myapp.war platzieren und überschreiben Einstellungen von common.jar. Zum Beispiel könnten Sie die Ebene DEBUG, eingestellt und dann werden Sie sehen:

2011-01-03 16:03:22,928 [main] DEBUG third-party-lib - Third Party App is about to Do something! 
2011-01-03 16:03:22,928 [main] INFO third-party-lib - Third Party App just did something 

UPDATE - Ist es möglich, jede Webapp zu konfigurieren, um separate Datei zu protokollieren?

Ja, definitiv. Beispielsweise können Sie Protokolle an einen RollingFileAppender anstelle von stdout in log4j.xml für myapp.war leiten. Dies ist praktisch, da Sie dann jedes einzelne Webapp-Protokoll in einer eigenen separaten Datei speichern können.

Zusätzlich habe ich einen Servlet-Filter geschrieben (ähnlich dem, was gigadot vorgeschlagen hat), der log4j konfiguriert, um zu prüfen, ob eine log4j.xml auf einem externen Pfad existiert (außerhalb jedes Webapps). Auf diese Weise sind die log4j.xml-Dateien auch außerhalb der Kriege zugänglich und wir können Protokollebenen einstellen, ohne den Servlet-Container neu zu starten (in diesem Fall Tomcat). Wenn die externe Datei log4j.xml nicht vorhanden ist, verwendet sie standardmäßig die Datei log4j.xml für jeden Klassenpfad der Anwendung.

+0

Dies ist in der Linie von dem, was ich dachte, um die Angelegenheit noch komplizierter zu machen, hat jede Web-App einen Appender, der auf einer anderen Datei basierend auf der Webapp protokolliert. Wenn ich meine individuellen Projektkonfigurationen auf genau diese Informationen reduziere, überschreibt oder ersetzt sie die Konfiguration von der ThirdPartyLib? – Casey

+0

Hey Casey, alle Konfigurationen innerhalb von log4j.xml in jeder einzelnen App überschreiben das Zeug in log4j.xml innerhalb der common.jar. Das Hinzufügen eines Dateiappenders in Log4j.xml jeder Anwendung sollte also gut funktionieren. Ich habe meine Antwort mit weiteren Informationen aktualisiert. Hoffe, das hilft, viel Glück! – Upgradingdave

+0

Danke, auch der Hinweis darüber, sie außerhalb der Kriege zu speichern, finde ich interessant, da ich auf dieses Problem gestoßen bin, etwas in der Produktion debuggen muss, aber das Protokolllevel nicht verlassen möchte, um Fehler zu beheben usw. Jemand in unserem Team zu haben eine einzelne Datei zu aktualisieren wäre großartig. – Casey

0

Ich bin nicht sicher, dass helfen kann, aber Sie können wie diese Eigenschaft Speicherort der Datei gesetzt,

java -Dlog4j.configuration=jar:file:/full/path/to/app.jar!/log4j.properties -jar app.jar 
+0

Ja, das hilft mir hier nicht wirklich. Trotzdem danke. – Casey

1

Wenn Sie mehrere jar/war-Dateien haben, jede Datei ihre eigene log4j.xml hat und Sie sich nicht darum kümmern müssen, welche log4j.xml geladen wird, können Sie die Konfiguration explizit selbst laden.

Legen Sie für ein Webapp-Projekt den folgenden Context-Listener als ersten Listener in Ihrer web.xml fest. Dadurch wird log4j von Ihrem bevorzugten Pfad geladen.

<listener> 
    <listener-class>mycompany.server.listener.Log4JInitServletContextListener</listener-class> 
</listener> 

Implementierung von Log4JInitServletContextListener.

Hinweis: Wenn Sie mehrere log4j.xml im selben Pfad haben (was für mehrere JAR-Dateien möglich ist), wird es verwirrend sein, welcher geladen wird. Versuchen Sie also, einen eindeutigen Paketnamen für die Konfigurationsressource in Ihrem allgemeinen Jar zu haben.

Wie Sie sehen, können Sie diese Methode verwenden, um log4j.xml abhängig von der Bedingung zu laden.

package mycompany.server.listener; 

import javax.servlet.ServletContextEvent; 
import javax.servlet.ServletContextListener; 

import org.apache.log4j.xml.DOMConfigurator; 

public class Log4JInitServletContextListener implements ServletContextListener { 

    @Override 
    public void contextInitialized(ServletContextEvent sce) { 
     org.w3c.dom.Element log4jConfigElement = parseFromInputStream(getClass().getResourceAsStream("/unique/package/name/in/common/jar/log4j.xml");); 
     DOMConfigurator.configure(log4jConfigElement); 
    } 

    // omit the rest and implementation of parseFromInputStream method 
} 
+0

Unterschiedlicher Ansatz, interessant. Ich wollte irgendwie einen programmatischen Ansatz vermeiden, aber dies könnte ein weiteres irritierendes Problem lösen, das ich an meinem Arbeitsplatz mit unterschiedlichen Umgebungen und Log-Output-Verzeichnissen (DEV/PROD) habe. Wenn ich einen Listener erstelle und die Konfiguration manuell lade, kann ich die Eigenschaften basierend auf dem Wert der Umgebungsvariablen überschreiben. – Casey

+0

Im Moment konfigurieren wir eine Eigenschaft in unserem Weblogic-Server, um anzugeben, in welcher Umgebung wir uns in der log4j-Datei als $ {env} befinden können. – Casey

+0

Ja, ich habe mein log4j entsprechend dem in der Systemumgebung eingestellten Kongregationspfad geladen. Ich habe viele Ansätze untersucht, um mein Problem zu lösen, das ist das gleiche wie Ihres, und das ist das Beste, was ich tun kann. Zuerst habe ich das maven-Plugin benutzt, um alle anderen log4.xml auszuschließen, aber in einigen Fällen ist es etwas schwierig. Log4j verfügt nicht über die Funktionalität, um direkt mit diesem Problem umzugehen. – gigadot

Verwandte Themen