web-dev-qa-db-fra.com

Log4j, configuration d'une application Web pour utiliser un chemin relatif

J'ai une Webapp Java qui doit être déployée sur des machines Windows ou Linux. Je souhaite maintenant ajouter log4j pour la journalisation et utiliser un chemin relatif pour le fichier journal, comme je l'ai déjà fait. ne voulez pas changer le chemin du fichier à chaque déploiement, le conteneur sera probablement Tomcat mais pas nécessairement.

Quelle est la meilleure façon de faire cela?

80
Iker Jimenez

Je l'ai finalement fait de cette façon.

Ajout d'un ServletContextListener qui effectue les tâches suivantes:

public void contextInitialized(ServletContextEvent event) {
    ServletContext context = event.getServletContext();
    System.setProperty("rootPath", context.getRealPath("/"));
}

Puis dans le fichier log4j.properties:

log4j.appender.file.File=${rootPath}WEB-INF/logs/MyLog.log

En procédant de cette manière, Log4j écrit dans le bon dossier tant que vous ne l'utilisez pas avant que la propriété système "rootPath" ait été définie. Cela signifie que vous ne pouvez pas l'utiliser à partir de ServletContextListener lui-même, mais que vous devriez pouvoir l'utiliser depuis n'importe où ailleurs dans l'application.

Il doit fonctionner sur tous les conteneurs Web et systèmes d'exploitation, car il ne dépend pas d'une propriété système spécifique à un conteneur et n'est pas affecté par les problèmes de chemin d'accès spécifiques à un système d'exploitation. Testé avec les conteneurs Web Tomcat et Orion, ainsi que sous Windows et Linux, et tout fonctionne correctement jusqu'à présent.

Qu'est-ce que tu penses?

53
Iker Jimenez

Tomcat définit une propriété système catalina.home. Vous pouvez l'utiliser dans votre fichier de propriétés log4j. Quelque chose comme ça:

log4j.rootCategory=DEBUG,errorfile

log4j.appender.errorfile.File=${catalina.home}/logs/LogFilename.log

Sur Debian (y compris Ubuntu), ${catalina.home} _ ne fonctionnera pas car cela pointe vers/usr/share/Tomcat6 et n’a pas de lien vers/var/log/Tomcat6. Ici, il suffit d'utiliser ${catalina.base}.

Si vous utilisez un autre conteneur, essayez de trouver une propriété système similaire ou définissez la vôtre. La définition de la propriété système varie en fonction de la plate-forme et du conteneur. Mais pour Tomcat sous Linux/Unix, je créerais un fichier setenv.sh dans le répertoire CATALINA_HOME/bin. Il contiendrait:

export Java_OPTS="-Dcustom.logging.root=/var/log/webapps"

Alors votre log4j.properties serait:

log4j.rootCategory=DEBUG,errorfile

log4j.appender.errorfile.File=${custom.logging.root}/LogFilename.log
99
Steve K

Si vous utilisez Spring, vous pouvez:

1) créez un fichier de configuration log4j, par exemple "/WEB-INF/classes/log4j-myapp.properties" NE LE NOMMEZ PAS "log4j.properties"

Exemple:

log4j.rootLogger=ERROR, stdout, rollingFile

log4j.appender.stdout=org.Apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.Apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n

log4j.appender.rollingFile=org.Apache.log4j.RollingFileAppender
log4j.appender.rollingFile.File=${myWebapp-instance-root}/WEB-INF/logs/application.log
log4j.appender.rollingFile.MaxFileSize=512KB
log4j.appender.rollingFile.MaxBackupIndex=10
log4j.appender.rollingFile.layout=org.Apache.log4j.PatternLayout
log4j.appender.rollingFile.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.rollingFile.Encoding=UTF-8

Nous définirons "myWebapp-instance-root" plus tard sur point (3)

2) Spécifiez l'emplacement de configuration dans web.xml:

<context-param>
  <param-name>log4jConfigLocation</param-name>
  <param-value>/WEB-INF/classes/log4j-myapp.properties</param-value>
</context-param>

3) Spécifiez un nom de variable unique pour la racine de votre application Web, par exemple. "myWebapp-instance-root"

<context-param>
  <param-name>webAppRootKey</param-name>
  <param-value>myWebapp-instance-root</param-value>
</context-param>

4) Ajoutez un Log4jConfigListener:

<listener>
  <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>

Si vous choisissez un nom différent, n'oubliez pas de le changer également dans log4j-myapp.properties.

Voir mon article (en italien uniquement ... mais cela devrait être compréhensible): http://www.megadix.it/content/configurare-path-relativi-log4j-utilizzando-spring

UPDATE (2009/08/01) J'ai traduit mon article en anglais: http://www.megadix.it/node/136

14
Megadix

Juste un commentaire sur la solution Iker .

ServletContext est une bonne solution à votre problème. Mais je ne pense pas que ce soit bon pour les entretiens. La plupart du temps, les fichiers journaux doivent être sauvegardés longtemps.

Puisque ServletContext crée le fichier sous le fichier déployé, il sera supprimé lorsque le serveur sera redéployé. Ma suggestion est d’aller avec le dossier parent de rootPath au lieu de l’enfant.

6
lizi

Log4j n'utilise-t-il pas simplement le répertoire racine de l'application si vous ne spécifiez pas de répertoire racine dans la propriété path de votre FileAppender? Donc, vous devriez juste pouvoir utiliser:

log4j.appender.file.File = logs/MyLog.log

Cela fait longtemps que je n’ai pas fait Java développement web, mais cela semble être le plus intuitif, et n’entre pas en collision avec d’autres journaux malheureusement nommés écrivant dans $ {catalina.home} répertoire/logs.

5
Spencer Kormos

En tant que commentaire supplémentaire sur https://stackoverflow.com/a/218037/22792 - cela peut échouer, si l'application Web démarre implicitement d'autres ServletContextListener, qui peuvent être appelés plus tôt et qui tentent déjà de les utiliser. log4j - dans ce cas, la configuration log4j sera lue et analysée avant que la propriété déterminant le répertoire racine du journal ne soit définie => les fichiers journaux apparaîtront quelque part sous le répertoire actuel (le répertoire actuel lors du démarrage de Tomcat).

Je ne pouvais penser qu'à la solution suivante à ce problème: - renommez votre fichier log4j.properties (ou logj4.xml) en quelque chose que log4j ne lira pas automatiquement. - Dans votre filtre de contexte, après avoir défini la propriété, appelez la classe d'assistance DOM/PropertyConfigurator pour vous assurer que votre log4j -. {Xml, propriétés} est lu - Réinitialisez la configuration log4j (IIRC dispose d'une méthode pour le faire)

C’est un peu la force brute, mais il me semble que c’est le seul moyen de le rendre étanche.

2
Wolfgang Liebich

Ma solution est similaire à celle d'Iker Jimenez solution , mais au lieu d'utiliser System.setProperty(...), j'utilise org.Apache.log4j.PropertyConfigurator.configure(Properties). Pour cela, j’ai également besoin que log4j ne puisse pas trouver sa configuration par elle-même et je la charge manuellement (les deux points décrits dans réponse de Wolfgang Liebich).

Cela fonctionne pour Jetty et Tomcat, autonome ou exécuté à partir de l'EDI, ne nécessite aucune configuration, permet de mettre les journaux de chaque application dans leur propre dossier, quel que soit le nombre d'applications contenues dans le conteneur (ce qui est le problème avec le solution basée sur System). De cette façon, vous pouvez également placer le fichier de configuration log4j n'importe où dans l'application Web (par exemple, dans un projet, nous avions tous les fichiers de configuration dans WEB-INF/).

Détails:

  1. J'ai mes propriétés dans le fichier log4j-no-autoload.properties Dans le classpath (par exemple, dans mon projet Maven, il est à l'origine dans src/main/resources, Il est emballé dans WEB-INF/classes),
  2. Le fichier appender est configuré comme par exemple:

    log4j.appender.MyAppFileAppender = org.Apache.log4j.FileAppender
    log4j.appender.MyAppFileAppender.file = ${webAppRoot}/WEB-INF/logs/my-app.log
    ...
    
  3. Et j'ai un auditeur de contexte comme celui-ci (il est beaucoup plus court avec la syntaxe "try-with-resource" de Java 7):

    @WebListener
    public class ContextListener implements ServletContextListener {
        @Override
        public void contextInitialized(final ServletContextEvent event) {
            Properties props = new Properties();
            InputStream strm =
                ContextListener.class.getClassLoader()
                    .getResourceAsStream("log4j-no-autoload.properties");
            try {
                props.load(strm);
            } catch (IOException propsLoadIOE) {
                throw new Error("can't load logging config file", propsLoadIOE);
            } finally {
                try {
                    strm.close();
                } catch (IOException configCloseIOE) {
                    throw new Error("error closing logging config file", configCloseIOE);
                }
            }
            props.put("webAppRoot", event.getServletContext().getRealPath("/"));
            PropertyConfigurator.configure(props);
            // from now on, I can use LoggerFactory.getLogger(...)
        }
        ...
    }
    
1
starikoff

Ma suggestion est que le fichier journal doit toujours être enregistré au-dessus du contexte racine de l'application Web. Par conséquent, si nous redéployons l'application Web, nous ne voulons pas remplacer les fichiers journaux existants.

1
user553633

Si vous utilisez Maven, j'ai une excellente solution pour vous:

  1. Editez votre fichier pom.xml pour inclure les lignes suivantes:

    <profiles>
        <profile>
            <id>linux</id>
            <activation>
                <os>
                    <family>unix</family>
                </os>
            </activation>
            <properties>
                <logDirectory>/var/log/Tomcat6</logDirectory>
            </properties>
        </profile>
        <profile>
            <id>windows</id>
            <activation>
                <os>
                    <family>windows</family>
                </os>
            </activation>
            <properties>
                <logDirectory>${catalina.home}/logs</logDirectory>
            </properties>
        </profile>
    </profiles>
    

    Ici, vous définissez la propriété logDirectory spécifiquement à la famille du système d'exploitation.

  2. Utilisez la propriété logDirectory déjà définie dans log4j.properties fichier:

    log4j.appender.FILE=org.Apache.log4j.RollingFileAppender
    log4j.appender.FILE.File=${logDirectory}/mylog.log
    log4j.appender.FILE.MaxFileSize=30MB
    log4j.appender.FILE.MaxBackupIndex=10
    log4j.appender.FILE.layout=org.Apache.log4j.PatternLayout
    log4j.appender.FILE.layout.ConversionPattern=%d{ISO8601} [%x] %-5p [%t] [%c{1}] %m%n
    
  3. C'est ça!

P.S.: Je suis sûr que cela peut être réalisé en utilisant Ant, mais malheureusement, je n'ai pas assez d'expérience avec cela.

1
alex.antaniuk

Vous pouvez spécifier le chemin relatif du fichier journal à l’aide de répertoire de travail:

appender.file.fileName = ${sys:user.dir}/log/application.log

Ceci est indépendant du conteneur de servlet et n'exige pas la transmission de variable personnalisée à l'environnement système.

1
Dimitar II