Journalisation avec SLF4J
Date de publication : 20 Janvier 2010 , Date de mise à jour : 29 Janvier 2010
Par
Baptiste Wicht (Mon site) (Blog)
Cet article va vous présenter SLF4J qui est une couche d'abstraction de journalisation. Cette API a plusieurs avantages
qui seront présentés dans cet article ainsi que les différentes fonctionnalités de cette librairie.
I. Introduction
2. Sélection de l'implémentation de journalisation
3. Redirection des appels depuis d'autres implémentations
4. Utilisation de l'API
5. Les Marker
6. Accès au MDC
7. Conclusion
7.1. Remerciements
I. Introduction
SLF4J est une couche d'abstraction pour les API de journalisation Java. Le principe est à peu près similaire à celui de
Jakarta Commons Logging. Les avantages de l'utilisation d'une telle couche d'abstraction permettent de s'abstraire de l'implémentation
utilisée. Ainsi, il est possible de changer facilement d'implémentation de journalisation sans avoir à toucher la base de code. Au plus,
la configuration de l'implémentation de journalisation doit être modifiée. Et enfin, dans le cas de la conception d'une librairie, cela permet
de laisser à l'utilisateur de cette librairie le choix du système de journalisation.
Vous me direz : si Commons Logging fait déjà cela, pourquoi un autre framework d'abstraction de logging ? Tout simplement parce que
Commons Logging a ses défauts. Le premier gros défaut de Commons Logging concerne le chargement de l'implémentation de journalisation. En effet,
la recherche de l'implémentation se fait dynamiquement à l'implémentation via un système de classloader. Or cette méthode peut poser problèmes dans
certaines situations, par exemple lorsque l'application utilise des classloaders personnalisés ou alors au sein d'une architecture OSGi. De plus,
l'implémentation utilisée par Commons Logging peut causer des fuites mémoires.
En outre, Commons Logging nous contraint à tester si un niveau de log est activé ou non avant de faire des logs contenant des concaténations
pouvant se révéler lourdes au long de l'application.
Nous allons voir que SLF4J permet de résoudre ces problèmes de manière efficace.
Vous pouvez télécharger la distribution officielle sur le
site de SLFJ4J.
2. Sélection de l'implémentation de journalisation
Contrairement à Commons Logging, SLF4J ne résout pas l'implémentation de journalisation à l'exécution mais à la compilation à l'aide d'une
API de bridging. En plus du JAR de l'API de SLF4J, il faut inclure les JAR suivants : celui qui fait office de pont entre SLF4J et
l'implémentation et celui de l'implémentation utilisée. Voici ce que cela pourrait donner avec Log4J :

Sélection d'une implémentation
Tout cela effectué uniquement par l'ajout de JAR au classpath. Aucun besoin de configurer quoi que ce soit mise à part l'implémentation. Il faut cependant
veiller à n'utiliser que l'interface de SLF4J sans quoi l'utilisation d'une couche d'abstraction n'a plus aucun intérêt.
3. Redirection des appels depuis d'autres implémentations
En plus de permettre une abstraction de la couche de journalisation, SLF4J offre également la possibilité de rediriger des appels à une implémentation
vers SLF4j qui lui-même les redirigera vers l'implémentation choisie.
Pour cela, il suffit d'utiliser le JAR xxx-to-slf4j.jar qui va intercepter les appels de xxx pour les rediriger vers l'API SLF4J.
Le diagramme suivant montre exactement comment sont redirigés les appels :

Redirection des appels
 |
Il faut bien entendu ne pas mettre dans le classpath le JAR de l'implémentation que vous voulez rediriger. Et plus important encore,
il ne faut surtout pas utiliser la redirection d'une API tout en utilisant cette API
comme implémentation de journalisation car cela créerait un cycle infini qui ferait planter votre programme à coup sûr.
|
4. Utilisation de l'API
L'API de SLF4J n'est pas très compliquée et ressemble beaucoup à celles des autres implémentations ou abstractions telles que Log4J ou Jakarta Commons Logging.
Voici comment récupérer un logger :
org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(HelloWorld.class);
|
Ensuite, vous pouvez l'utiliser comme les autres implémentations à l'aide des méthodes debug(), info(), warn(), trace() et error(). Par exemple :
logger.info("Hello World");
|
Mais ce n'est pas là que réside la force de SLF4J. Prenons un exemple simple de logging :
logger.debug("Info : x = " + info.getX() + ", y = " + info.getY() + ", str = " + infos.getStr());
|
Cela veut dire qu'à chaque fois que cette ligne de code sera exécutée, une concaténation sera faite. Cela peut vite s'avérer être lourd si la méthode est
exécutée de manière régulière. C'est pourquoi il faut préalablement tester si le niveau est activé :
if(logger.isDebugEnabled()){
logger.debug("Info : x = " + info.getX() + ", y = " + info.getY() + ", str = " + infos.getStr());
}
|
Cette fois, les performances sont garanties, mais ce genre de code n'est pas du tout esthétique et devient rapidement lourd. D'autant plus que le
test est déjà fait dans la méthode debug qui n'affichera rien si le niveau n'est pas activé. Alors pourquoi faire le travail deux fois ?
SLF4J propose donc une nouvelle alternative assez équivalente à la méthode printf de Java :
logger.debug("Info : x = {}, y = {}, str = {}", new Object[]{info.getX(), info.getY(), infos.getStr()});
|
Les {} vont être remplacés par les valeurs passées en paramètres. Ainsi, la concaténation va se faire uniquement si le niveau de log
est activé. De plus, esthétiquement, ce code est beaucoup plus propre que les deux précédents.
 |
Dans le cas où la récupération des informations à journaliser serait lourde, il faudrait néanmoins utiliser la première technique consistant
à tester si le niveau de log est activé avant de faire la journalisation. Par exemple, nous pourrions imaginer une méthode getDebugInfos() sur
un objet qui fait beaucoup d'opérations pour récupérer des informations. Cette méthode ne doit pas être exécutée si le niveau de log n'est pas activé.
|
5. Les Marker
Les Marker permettent essentiellement d'associer des tags à des logs. Ces tags permettent ensuite aux différents appenders de
prendre en charge différemment certains logs. Imaginons par exemple un appender qui écrirait de manière cryptée les données et qui ne devrait
être utilisé que sur les données markées comme confidentielles. Les Marker vont nous permettre d'implémenter une telle chose.
Cette fonctionnalité n'est accessible qu'avec l'implémentation LogBack : il s'agit en effet de la seule qui implémente les Marker. Néanmoins, vous pourrez
utiliser les Marker avec les autres implémentations, bien que cela n'aura aucun effet.
Imaginons par exemple un appender nommé CryptAppender qui encode le log selon un algorithme quelconque. Nous pourrions le configurer ainsi :
<appender name="CRYPTED" class="CryptAppender">
<layout class="ch.qos.logback.classic.html.HTMLLayout">
<pattern>%date%-5level%logger%msg</pattern>
<throwableRenderer class="ch.qos.logback.classic.html.DefaultThrowableRenderer" />
</layout>
<evaluator class="ch.qos.logback.classic.boolex.OnMarkerEvaluator">
<marker>CONFIDENTIAL</marker>
</evaluator>
</appender>
|
Le OnMarkerEvaluator permet de ne sélectionner que les logs ayant été markés avec un certain tag. Dans notre cas, il faut marker les
logs confidentiels avec CONFIDENTIAL. Voici comment procéder :
Marker confidentialMarker = MarkerFactory.getMarker("CONFIDENTIAL");
logger.error(confidentialMarker, "C'est confidentiel !");
|
Cela n'affichera donc pas le log directement, mais le log de manière cryptée.
Une autre utilisation de cette fonctionnalité pourrait, par exemple, concerner l'envoi par email de certains logs.
Vous pouvez bien entendu configurer plusieurs appenders pour le même tag. Vous pouvez également créer une hiérarchie de Marker.
Marker parentMarker = MarkerFactory.getMarker(“parent”);
Marker childMarker = MarkerFactory.getMarker(“child”);
parentMarker.add(childMarker);
|
Ce faisant, tout ce qui est journalisé avec parentMarker ou childMarker sera traité dans les appenders configurés pour parent tandis que
les appenders configurés pour child ne verront que ce qui est journalisé avec child.
6. Accès au MDC
Le "Mapped Diagnostic Context" (MDC) est, en résumé, une simple map (ensemble clés-valeurs) maintenue par le framework de journalisation dans
laquelle l'application peut insérer des couples clés-valeurs qui pourront ensuite être utilisés pour ajouter des informations dans le système de log.
Imaginons que nous traitons des informations sur des personnes et que nous les affichons en logging. Le nom et le prénom
de la personne devront être affichés sur chacune des lignes de logging. Nous pourrions automatiser l'inclusion du nom et du prénom
dans les logs avec MDC.
Il est possible d'ajouter des valeurs dans le MDC avec la méthode put :
MDC.put("prenom", "Baptiste");
MDC.put("nom", "Wicht");
|
Ensuite, il faut les prendre en compte dans le layout de journalisation. Ce layout se configure au niveau de l'implémentation qui doit supporter MDC.
Les implémentations qui supportent MDC sont Log4J, JUL et Logback. Voici un layout prenant en compte MDC :
%X{prenom} %X{nom} - %m%n
|
Désormais pour afficher des informations, il suffit de faire :
logger.info("Age {}", age);
logger.info("Localisation {}", localisation);
|
Ce qui pourrait donner :
Baptiste Wicht - Age 22
Baptiste Wicht - Localisation Suisse
|
Enfin, si le MDC est modifié entre 2 instructions de logging, cela va directement changer la journalisation :
logger.info("Age {}", age);
MDC.put("prenom", "Jacques");
logger.info("Localisation {}", localisation);
|
affichera :
Baptiste Wicht - Age 22
Jacques Wicht - Localisation Suisse
|
Cela peut donc se révéler très pratique pour stocker et afficher des informations globales à l'application. Par exemple un login, un id de session ou
n'importe quelle autre donnée.
7. Conclusion
En conclusion, SLF4J se révèle être une très bonne couche d'abstraction de journalisation. Elle se révèle très puissante, tout en étant
très simple à utiliser et restant dans le même style que les autres systèmes de journalisation existants.
L'auteur de SLF4J conseille d'utiliser l'implémentation de journalisation LogBack qui est l'implémentation de référence de SLF4J.
Si vous avez des commentaires sur cet article, n'hésitez pas à vous exprimer sur le forum :
10 commentaires
Ou alors directement sur le site avec le formulaire de commentaire au bas de cette page.
7.1. Remerciements
Un grand merci à
eusebe19 et
à
Wachter pour leur correction orthographique.