Configuration de Tomcat avec logback

Michael Schneider

Ce document pourrait en fait s'appeler « Configuration de n'importe quel logger sur Tomcat 6 » ou plutôt encore « Configuration d'un logger compatible slf4j sur Tomcat 6 ».

Tout est venu du fait de la « pauvreté » du logger JULI utilisé de base par Tomcat et de l'envie de ne pas utiliser log4j apparemment remplacé par logback.

De nombreuses heures de recherches infructueuses sur Internet m'ont conduit à rédiger ce document. Après, j'ai peut-être mal cherché…

- Titre : Configuration de Tomcat avec logback

- Auteur : Michael Schneider

- Parution : 27 février 2009

- Mise à jour : 22 février 2020

- Licence :

Sommaire

- I. Références

- II. Procédure pas à pas

- II-A. Prérequis

- II-B. Modification du « fonctionnement » de Tomcat

- II-B-1. Installation de Tomcat

- II-B-2. Compilation des extras

- II-B-3. « Mise à jour » de Tomcat

- II-C. Mise en place des bibliothèques de logging

- III. Pourquoi ça marche ?

- III-A. tomcat-juli.jar

- III-B. tomcat-juli-adapters.jar

- III-C. log4j-over-slf4j-VERSION.jar et slf4j-api-VERSION.jar

- III-D. logback-core-VERSION.jar et logback-classic-VERSION.jar

- IV. Conclusion

- V. Configuration d'un logger par application

- V-A. Mise en place d'un ContextSelector

- V-B. Gestion du log en cours de production

I - Références

- La documentation (« légère » sur ce coup-là) de Tomcat 6(http://tomcat.apache.org/tomcat-6.0-doc/logging.html).

- La documentation et le source code de SLF4J(www.slf4j.org), LOG4J(logging.apache.org/log4j/1.2/index.html) et de Commons-logging(commons.apache.org/logging/)

II - Procédure pas à pas

II-A - Prérequis

- Télécharger la distribution binaire de Tomcat 6.0.18(testé uniquement avec cette version).

- Télécharger les sources de Tomcat 6.0.18.

- Télécharger Ant.

- Télécharger la distribution de SLF4J.

- Télécharger la distribution de LogBack.

II-B - Modification du « fonctionnement » de Tomcat

Cette partie est directement reprise de la documentation de Tomcat (chapitre Logging).

II-B-1 - Installation de Tomcat

Rien de particulier, suivre les instructions d'Apache…

II-B-2 - Compilation des extras

- Décompresser les sources de Tomcat.

- Exécuter la commande suivante : ant -f extras.xml.

- Cela génère des fichiers dans un répertoire output.

II-B-3 - « Mise à jour » de Tomcat

- Remplacer le fichier tomcat-juli.jar du répertoire bin de votre installation de Tomcat par celui généré (TOMCATSRC/output/).

- Copier le fichier tomcat-juli-adapters.jar dans le répertoire lib de Tomcat.

II-C - Mise en place des bibliothèques de logging

Copier dans le répertoire lib de Tomcat les jars suivants :

- log4j-over-slf4j-VERSION.jar (distribution de SFL4J) ;

- slf4j-api-VERSION.jar (distribution de SFL4J) ;

- logback-core-VERSION.jar (distribution de LogBack) ;

- logback-classic-VERSION.jar (distribution de LogBack).

Comme cela, cela devrait déjà marcher, mais la configuration basique de logback est en mode DEBUG, ce qui fait que Tomcat génère énormément de log, donc un simple fichier de configuration peut être utilisé : logback.xml (à mettre dans le répertoire lib de Tomcat) :

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<contextName>Tomcat</contextName>
<jmxConfigurator contextName="Tomcat" />
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<File>${catalina.home}\logs\tomcat.log</File>
<Append>true</Append>
<BufferedIO>false</BufferedIO>
<ImmediateFlush>true</ImmediateFlush>
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%d{yyyy-MM-dd HH:mm:ss} [%-5p] - %m%n</Pattern>
</layout>
</appender>
<root>
<level value="INFO" />
<appender-ref ref="FILE" />
</root>
</configuration>

III - Pourquoi ça marche ?

L'explication peut paraitre simpliste, mais finalement, le fait que ça marche est essentiellement du bon sens (je me demande d'ailleurs pourquoi j'y ai passé deux jours entiers…). En fait, le principe est le « truchement de classloader » ou polymorphisme (je crois en langage professionnel…). Voici donc le cheminement d'un log Tomcat depuis la ligne de code originelle à son fichier (par exemple).

III-A - tomcat-juli.jar

La nouvelle version du fichier qui est mis en place ne contient plus l'« hardcodage » du logger JULI, à la place il propose des interfaces sur org.apache.juli.logging, mais pas d'implémentation.

III-B - tomcat-juli-adapters.jar

Ce jar contient une implémentation du LoggerFactory, qui en fait cherche dans le classpath une implémentation de logging JDK ou log4j. Évidemment, s'il cherchait du slf4j, cela simplifierait bien des choses.

III-C - log4j-over-slf4j-VERSION.jar et slf4j-api-VERSION.jar

C'est justement pour cela que l'on met ces archives. En fait elle remplace une éventuelle bibliothèque log4j.jar, et place l'environnement dans une position : « je choisis le logger que je trouve ». Ce qui est exactement le rôle de slf4j (Standard Logging Facage for Java).

III-D - logback-core-VERSION.jar et logback-classic-VERSION.jar

Enfin, notre choix se porte sur l'implémentation LogBack, ce qui nous conduit à l'utilisation de ces deux archives, qui contiennent le code pour écrire finalement nos logs.

IV - Conclusion

Enfin, notre choix se porte sur l'implémentation LogBack, ce qui nous conduit à l'utilisation de ces deux archives, qui contiennent le code pour écrire finalement nos logs.

V - Configuration d'un logger par application

V-A - Mise en place d'un ContextSelector

- Rajout de -Dlogback.ContextSelector=JNDI dans le lancement de Tomcat.

- Rajout dans le web.xml de chaque application :

<env-entry>
<env-entry-name>logback/context-name</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>TestLog</env-entry-value>
</env-entry>

- Le fichier de paramétrage devra s'appeler logback-TestLog.xml et être mis dans le répertoire WEB-INF/classes de l'application.

- Le contexte de chaque application doit être nettoyé lorsque l'application s'arrête. Pour cela, il faut rajouter la configuration suivante dans le web.xml :

<listener>
<listener-class>ch.qos.logback.classic.selector.servlet.ContextDetachingSCL</listener-class>
</listener>

- Lors de la récupération du contexte, la requête JNDI peut être longue. En rajoutant, le filtre suivant dans le web.xml, cette requête est évitée, car le contexte est stocké dans un Thread local à chaque requête http :

<filter>
<filter-name>LoggerContextFilter</filter-name>
<filter-class>ch.qos.logback.classic.selector.servlet.LoggerContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoggerContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

V-B - Gestion du log en cours de production

L'idée de base est de pouvoir changer en exploitation le niveau de trace des applications. La première version de ce que j'avais imaginé était d'avoir plusieurs fichiers de config, et de proposer une servlet permettant de switcher de fichier de configuration.

Finalement, l'option retenue est d'utiliser les fonctions JMX du serveur Tomcat et de la bibliothèque LogBack. Pour cela, il faut tout d'abord autoriser Tomcat à utiliser JMX. Il suffit de rajouter ces paramètres à la chaîne de lancement de Tomcat :

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=8888
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false

Ensuite dans une commande DOS, il suffit de lancer l'application jconsole, de se connecter en remote sur le port 8888, d'aller sur l'onglet MBeans et de sélectionner la bibliothèque de logging logback. Dans les différents écrans, il est possible de modifier en « live » le niveau de debug des applications.

Pour finir, il faut, comme pour le JNDI, nettoyer la mémoire lorsque l'application est arrêtée. Pour cela, il suffit de créer une classe du style :

package home.devcom.servlet.context;

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

import org.slf4j.LoggerFactory;

import ch.qos.logback.classic.LoggerContext;

public class ContextListener implements ServletContextListener
{
public void contextDestroyed(ServletContextEvent sce)
{
System.out.println("ContextListener::contextDestroyed");
// Code repris de la documentation de logback :
//  http://logback.qos.ch/manual/jmxConfig.html
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
lc.stop();
}

public void contextInitialized(ServletContextEvent sce)
{}
}

Compiler et transformer en fichier jar et le mettre dans le WEB-INF/lib de vos applications puis de rajouter les lignes suivantes au web.xml :

<listener>
<listener-class>home.devcom.servlet.context.ContextListener</listener-class>
</listener>