Lors du développement d'applications Java robustes, le choix d'un framework de journalisation adéquat est fondamental. Plusieurs options coexistent, chacune avec ses forces et ses particularités. Voici un examen comparatif des principaux frameworks.
Log4j
Log4j est un projet open source historique d'Apache. Il permet de contrôler la destination des messages de log (console, fichiers, base de données), leur format et leur niveau. Il définit sept niveaux de sévérité : TRACE, DEBUG, INFO, WARN, ERROR, FATAL et OFF. Sa configuration repose sur trois composants : Logger, Appender et Layout.
Exemple de configuration de base (log4j.properties) :
# Configuration principale
log4j.rootLogger = INFO, sortieConsole
# Appender pour la console
log4j.appender.sortieConsole = org.apache.log4j.ConsoleAppender
log4j.appender.sortieConsole.layout = org.apache.log4j.PatternLayout
log4j.appender.sortieConsole.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
Écriture dans un fichier journal avec rotation :
# Ajout d'un appender fichier
log4j.rootLogger = INFO, sortieConsole, fichierJournal
log4j.appender.fichierJournal = org.apache.log4j.DailyRollingFileAppender
log4j.appender.fichierJournal.File = /var/log/mon_app.log
log4j.appender.fichierJournal.DatePattern = '.'yyyy-MM-dd
log4j.appender.fichierJournal.layout = org.apache.log4j.PatternLayout
log4j.appender.fichierJournal.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
Journalisation vers une base de données MySQL :
log4j.rootLogger = INFO, sortieConsole, appenderBDD
log4j.appender.appenderBDD = org.apache.log4j.jdbc.JDBCAppender
log4j.appender.appenderBDD.driver = com.mysql.cj.jdbc.Driver
log4j.appender.appenderBDD.URL = jdbc:mysql://localhost:3306/base_logs
log4j.appender.appenderBDD.user = utilisateur
log4j.appender.appenderBDD.password = motdepasse
log4j.appender.appenderBDD.sql = INSERT INTO logs (niveau, logger, message, horodatage) VALUES ('%p','%c','%m','%d')
Une dépendance au connecteur JDBC est requise, ainsi que la création de la table correspondante.
Intégration dans Spring Boot :
Pour utiliser Log4j (et non Logback par défaut), il faut exclure spring-boot-starter-logging et ajouter spring-boot-starter-log4j. Notez que ce starter est obsolète et qu'il est préférable d'utiliser Log4j2 pour les versions récentes de Spring Boot.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
</dependency>
Le fichier de configuration (log4j.properties) est ensuite placé dans src/main/resources, et son chemin peut être précisé via logging.config dans application.properties.
Log4j2
Log4j2 est une réécriture majeure de Log4j 1.x, offrant des performances supérieures et des fonctionnalités avancées. Ses avantages clés incluent une architecture modulaire, des configurations plus flexibles (XML, JSON, YAML), un support amélioré de la concurrence grâce à Java 5, et un système de journalisation asynchrone performant basé sur la bibliothèque LMAX Disruptor.
Mode asynchrone complet :
Uniquement, il suffit d'ajouter une propriété système au démarrage de l'application.
System.setProperty("Log4jContextSelector", "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector");
Mode asynchrone hybride :
Dans le fichier de configuration XML, on utilise les éléments <AsyncLogger> ou <AsyncRoot>.
<Loggers>
<AsyncLogger name="com.example.monpackage" level="trace" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="FichierPrincipale"/>
</AsyncLogger>
<AsyncRoot level="info">
<AppenderRef ref="Console"/>
</AsyncRoot>
</Loggers>
L'utilisation de la journalisation asynchrone nécessite la dépendance com.lmax:disruptor.
Intégration dans Spring Boot :
La configuration est similaire à Log4j, mais avec le starter spring-boot-starter-log4j2. Le fichier de configuration standard est log4j2.xml.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Properties>
<Property name="REPERTOIRE_LOGS">logs/</Property>
<Property name="NOM_FICHIER">application</Property>
</Properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<RollingFile name="FichierPrincipale" fileName="${REPERTOIRE_LOGS}/${NOM_FICHIER}.log"
filePattern="${REPERTOIRE_LOGS}/$${date:yyyy-MM}/${NOM_FICHIER}-%d{yyyy-MM-dd}-%i.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
<Policies>
<SizeBasedTriggeringPolicy size="50 MB"/>
<TimeBasedTriggeringPolicy interval="1"/>
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="FichierPrincipale"/>
</Root>
</Loggers>
</Configuration>
SLF4J (Simple Logging Facade for Java)
SLF4J n'est pas une implémentation de journalisation, mais une façade (interface abstraite). Il fournit une API unifiée, permettant de découpler le code applicatif d'une implémentation spécifique (Log4j, Log4j2, Logback, java.util.logging, etc.). L'implémentation réelle est liée au moment de la compilation ou du déploiement via des bibliothèques adaptatrices (bridges).
Utilisation typique :
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MonService {
private static final Logger journal = LoggerFactory.getLogger(MonService.class);
public void executer() {
journal.info("Traitement en cours...");
}
}
Avantage principal :
Le changement d'implémentation sous-jacente se fait sans modifier le code applicatif, seulement en changeant les dépendances et la configuration. C'est particulièrement utile pour les bibliothèques, qui ne doivent pas imposer un framework de journalisation aux applications hôtesses.
Logback
Logback est l'implémentation native conçue pour fonctionner avec SLF4J. Il est présenté comme le successeur légitime de Log4j 1.x. Il se compose de trois modules : logback-core, logback-classic (implémente SLF4J) et logback-access (pour les conteneurs Servlet).
Raisons de son adoption :
Performance accrue et consommation mémoire réduite par rapport à Log4j 1.x. Configuration possible en XML ou en Groovy. Rechargement dynamique de la configuration. Gestion avancée de la rotation et de la compression des fichiers journaux. Support conditionnel (<if>, <then>, <else>) dans les fichiers de configuration.
Configuration dans Spring Boot :
Logback est le framework par défaut. Pour une configuration personnalisée, créer un fichier logback-spring.xml dans src/main/resources. Ce fichier peut utiliser des balises spécifiques à Spring pour des profils d'environnement.
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true">
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<logger name="com.example.monapplication" level="DEBUG"/>
<springProfile name="dev">
<root level="DEBUG">
<appender-ref ref="CONSOLE"/>
</root>
</springProfile>
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="FILE"/>
</root>
</springProfile>
</configuration>
Les propriétés de journalisation dans application.properties (comme logging.level.root=WARN, logging.file.name=app.log, logging.pattern.console=...) surchargent les valeurs du fichier XML.
Autres implémentations
Apache Commons Logging (JCL) : Une autre façade similaire à SLF4J, plus ancienne. Elle utilise une découverte dynamique de l'implémentation au moment de l'exécution, ce qui peut être source de problèmes dans des environnements complexes comme les serveurs d'applications.
java.util.logging (JUL) : Le framework intégré au JDK. Sa configuration est plus verbose et il manque généralement de fonctionnalités avancées par rapport aux alternatives tierces, mais il ne nécessite aucune dépendance externe.
Synthèse et conseils
L'écosystème se compose de façades (SLF4J, Commons Logging) et d'implémentations (Log4j, Log4j2, Logback, JUL).
Pour un nouveau projet Spring Boot, Logback est un choix solide et intégré par défaut. Log4j2 offre des performances asynchrones de pointe et une flexibilité de configuraton étendue. SLF4J doit être utilisé comme API de journalisation dans le code pour préserver la portabilité.
Pour maintenir la cohérence, il est recommandé de n'avoir qu'une seule implémentasion sur le classpath, et d'utiliser des ponts (bridges) pour rediriger les appels d'autres façades (comme Commons Logging) vers SLF4J.