2011-01-03 4 views
1

J'ai un pot commun que plusieurs applications Web utilisent. Toutes les applications Web utilisent log4j. Chacun a son propre fichier de configuration log4j xml qui sont fondamentalement les mêmes. Je voudrais mettre une configuration log4j commune dans le fichier jar inclus et dans chaque projet web individuel, dans cette configuration log4j, j'aimerais pouvoir me référer simplement à celle du fichier jar.se référant au fichier de configuration log4j à partir d'un fichier de configuration log4j sur le chemin de classe

Je ne vois rien dans la documentation qui indique explicitement que cela soit possible. Je me demande si je pourrais juste enlever le fichier de configuration des projets Web et le coller dans le pot commun s'il serait chargé automatiquement puisqu'il est sur le chemin de la classe? En fin de compte, je voudrais la possibilité d'ajuster la journalisation sur une application particulière pour le débogage et le dépannage sans modifier la configuration commune dans le fichier JAR.

Répondre

1

J'étais sur un projet où je devais gérer des dizaines d'applications Web. Chacune des applications se connectait légèrement différemment et c'était une grosse peine à gérer. J'ai utilisé une stratégie similaire à celle que vous décrivez pour standardiser sur log4j et cela a plutôt bien fonctionné.

Fondamentalement, j'ai créé un common.jar unique qui contient du code partagé. Ce fichier contient un fichier log4j.xml qui définit le niveau de journalisation sur INFO et définit l'appender par défaut sur stdout pour common.jar. Cette configuration log4j est utilisée comme référence pour toutes les autres applications.

Pour cet exemple, faire semblant cette classe est à l'intérieur 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"); 
    } 
} 

Maintenant, toutes les autres applications Web peuvent simplement dépendre common.jar. Par exemple, faire semblant cette classe est à l'intérieur myapp.war:

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

Depuis log4j.xml est à l'intérieur common.jar, ce code enregistrera quelque chose comme ça. En d'autres termes, il n'y a pas besoin de mettre à l'intérieur log4j.xml myapp.war:

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

Maintenant, si vous voulez/besoin de contrôler l'exploitation forestière dans myapp.war, puis placez simplement un log4j.xml intérieur myapp.war et remplacer les paramètres de common.jar. Par exemple, vous pouvez définir le niveau DEBUG, et vous verrez:

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 

MISE À JOUR - Est-il possible de configurer chaque webapp pour se connecter au fichier séparé?

Oui, définitivement. Par exemple, vous pouvez diriger les journaux vers un RollingFileAppender au lieu de stdout à l'intérieur de log4j.xml pour myapp.war. C'est pratique parce que vous pouvez avoir chaque journal webapp individuel dans son propre fichier séparé. En outre, j'ai écrit un filtre de servlet (semblable à ce que le gigadot a suggéré) qui configure log4j pour vérifier si un fichier log4j.xml existe sur un chemin externe (en dehors de la guerre de chaque webapp). De cette façon, les fichiers log4j.xml sont accessibles en dehors des guerres et nous sommes en mesure de définir les niveaux de journalisation sans redémarrer le conteneur de servlet (tomcat, dans ce cas). Si le fichier log4j.xml externe n'existe pas, il utilise par défaut le fichier log4j.xml sur chaque chemin de classe d'applications.

+0

C'est dans le sens de ce que je pensais, cependant, pour compliquer davantage les choses, chaque application web a un appender qui se connecte à un fichier différent basé sur la webapp. Si je réduis mes configurations de projet individuelles à ces seules informations, va-t-il remplacer ou remplacer la configuration de ThirdPartyLib? – Casey

+0

Hey Casey, toutes les configs à l'intérieur de log4j.xml dans chaque application individuelle remplaceront les choses à l'intérieur de log4j.xml à l'intérieur du common.jar. Par conséquent, l'ajout d'un appender dans le fichier log4j.xml de chaque application devrait fonctionner correctement. J'ai mis à jour ma réponse avec plus d'infos. En espérant que ça aide, bonne chance! – Upgradingdave

+0

Merci, aussi la remarque sur les stocker en dehors des guerres que je trouve intéressant car j'ai rencontré ce problème, ayant besoin de déboguer quelque chose en production mais ne voulant pas laisser le niveau de journalisation en débogage etc. mettre à jour un seul fichier serait génial. – Casey

0

je ne suis pas sûr qui peut aider, mais vous pouvez définir l'emplacement du fichier de propriété comme celui-ci,

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

Oui, ça ne va pas vraiment m'aider ici. Merci quand même. – Casey

1

Si vous avez plusieurs fichiers jar/war, chaque fichier possède son propre fichier log4j.xml et vous ne voulez pas vous inquiéter de savoir quel fichier log4j.xml est chargé, vous pouvez charger explicitement la configuration vous-même.

Pour un projet webapp, placez le programme d'écoute de contexte suivant en tant que premier écouteur dans votre fichier web.xml Ceci chargera log4j à partir de votre chemin de préférabilité.

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

Mise en œuvre de Log4JInitServletContextListener.

Remarque: si vous avez plusieurs fichiers log4j.xml dans le même chemin (ce qui est possible pour plusieurs fichiers jar), il sera difficile de savoir lequel sera chargé. Essayez donc d'avoir un nom de paquet unique pour la ressource de configuration dans votre pot commun.

Comme vous pouvez le voir, vous pouvez utiliser cette méthode pour charger par programme log4j.xml en fonction de la condition.

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

Approche différente, intéressante. Je voulais en quelque sorte éviter une approche programmatique, mais cela pourrait résoudre un autre problème irritant que j'ai sur mon lieu de travail avec des environnements différents et des répertoires de sortie de journal (DEV/PROD). Si je crée un écouteur et charge manuellement la configuration, je peux remplacer les propriétés en fonction de la valeur des variables d'environnement. – Casey

+0

À l'heure actuelle, nous configurons une propriété dans notre serveur weblogic pour indiquer dans quel environnement nous sommes dans le fichier log4j comme $ {env}. – Casey

+0

Oui, j'ai chargé mon log4j en fonction du chemin de configuration que j'ai défini dans l'environnement système. J'ai examiné plusieurs approches pour résoudre mon problème, qui est le même que le vôtre, et c'est le mieux que je puisse faire. Au début, j'ai utilisé maven plugin pour exclure tous les autres fichiers log4.xml mais c'est un peu dur dans certains cas. Log4j n'a pas la fonctionnalité pour traiter ce problème directement. – gigadot

Questions connexes