Gérer les logs avec log4j

Par défaut, l'exécution d'un programme Java génère pas mal de messages dans la console, surtout si vous utilisez Hibernate. Log4j permet de gérer de façon assez fine les messages, pour déterminer quoi enregistrer ou afficher, et où.

Installer log4j avec Maven

Déclarez la dépendance suivante dans votre fichier pom.xml :

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.7</version>
</dependency>

Paramétrer log4j

Dans Eclipse, éditez le fichier /src/main/resources/log4j.xml :

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration PUBLIC "-//LOGGER"
"http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd" >
<log4j:configuration>
    <appender name="console" class="org.apache.log4j.ConsoleAppender">
        <param name="Threshold" value="debug"/>
        <param name="Target" value="System.out"/>
        <layout class="org.apache.log4j.PatternLayout">
           <param name="ConversionPattern"
          value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
        </layout>
    </appender>
    <appender name="rolling-file" class="org.apache.log4j.RollingFileAppender">
        <param name="file" value="monAppli.log"/>
        <param name="MaxFileSize" value="500KB"/>
        <param name="MaxBackupIndex" value="4"/>
        <layout class="org.apache.log4j.PatternLayout">
           <param name="ConversionPattern"
          value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
        </layout>
    </appender>
     <logger name="monAppli" additivity="false">
        <level value="info"/>
        <appender-ref ref="console"/>
    </logger>
    <logger name="org.hibernate" additivity="false">
        <level value="error" />
    </logger>
<logger name="org.hibernate.SQL" additivity="false">
    <level value="warn"/>
</logger>
   <!-- ALL | DEBUG | INFO | WARN | ERROR | FATAL | OFF -->
    <root>
        <level value ="error" />
        <appender-ref ref="console" />
        <appender-ref ref="rolling-file" />
    </root>
</log4j:configuration>

Les Appender correspondent aux destinations de sortie des logs, en général la console ou un fichier. Ici, les logs sont formatées pour afficher la date-heure de survenue de l'événement, ce qui peut être pratique pour analyser les traces stockées dans un fichier.

Les Logger correspondent aux enregistreurs définis pour une classe ou pour un paquetage (arborescence), le niveau de traitement des logs étant définis par classe ou par paquetage.

Remplacez la valeur de monAppli.log par le nom de votre application... Vous pouvez adapter la configuration en fonction de ce que vous voulez tracer ou voir dans la console.

Les niveaux sont cumulatifs : ALL permet de visualiser tous les messages, alors qu'ERROR n'affichera que les messages d'erreur et ceux définis comme fatals. Ainsi, dans cet exemple, les messages d'Hibernate ne seront affichés que pour les erreurs, sauf pour les commandes SQL, qui seront visibles à partir de l'avertissement (level warn). L'ensemble des messages de l'application sera affiché à partir du niveau info.

Paramétrer log4j dans l'application

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
public class App {
static Logger logger = Logger.getLogger(App.class);
   
    public static void main(String[] args) {
        DOMConfigurator.configure("param/log4j.xml"); // a ajouter si le fichier de configuration n'est pas present dans le chemin par defaut
        BasicConfigurator.configure();
        [...]
    }
}

Utiliser les logs de façon adéquate

Plutôt que de parsemer le code de commandes System.out.println("texte à afficher"), il est plus intéressant de s'appuyer sur log4j pour gérer les messages. Pour cela, dans la classe pour laquelle vous voulez afficher des informations :

public class DbObject {
    static Logger logger = Logger.getLogger(DbObject.class);
    (...)
    void maFonction() {
            String sql = "select * from ma_table";
            logger.debug(sql);
            try {
                query = connection.createStatement();
                rs = query.executeQuery(sql);
            } catch (Exception e) {
                logger.error(e);
            }

Avec ce mécanisme, deux messages sont générés : le premier affiche la commande sql, le second le message d'erreur Java en cas de problème. Mais ces messages ne seront visibles qu'en fonction du paramétrage du fichier log4j.xml : si le niveau d'affichage est défini à error, seuls les messages d'erreur seront traités. Si le niveau est défini à debug, les commandes sql seront également affichées.

Ainsi, il est facile de déterminer des messages d'erreur et leur mode de traitement : il suffit de modifier le fichier log4j.xml pour adapter la manière dont ils seront vus, selon le contexte défini.

En production, le niveau error est en général retenu. En développement, le niveau info ou debug, selon ce que l'on cherche, peut être sélectionné.

Il est également possible de traiter les messages selon la classe qui les génère : il suffit de créer une entrée <logger /> pour une classe pour déterminer un niveau de traitement des logs spécifique. Attention toutefois : il n'est pas possible de définir deux logger pour la même classe, par exemple stocker les messages d'erreur dans un fichier, et ne conserver à l'écran que les messages de débogage. Un seul niveau peut être défini par classe, avec une seule destination (console, fichier, console + fichier).