2. Le logging est une activité technique utile et nécessaire dans une application pour :
• Déboguer
• Faciliter la recherche d'une source d'anomalie (stacktrace, ...)
• Obtenir des traces d'exécution (démarrage/arrêt, informations, avertissements,
erreurs d'exécution, ...
• Comprendre ou vérifier le flux des traitements exécutés : traces des
entrées/sorties dans les méthodes, affichage de la pile d'appels, ...
Introduction
3. • Les bonnes pratiques de développement déconseillent l’utilisation des méthodes
System.out.print* et System.err.print* pour afficher des messages et recommandent
plutôt l’utilisation d’un logger tel Log4j apportant plus de souplesse.
• Le développeur préférera envoyer le message qu’il souhaite afficher ou enregistrer au
logger en lui assignant un certain niveau de criticité
• Une API de logging permet un contrôle sur le format des messages en proposant un
format standard pouvant inclure des données telles que la date/heure, la classe, le
thread, ...
• Une API de logging permet de gérer différentes cibles de stockage des messages
• log4j permet d'activer ou de désactiver certains messages en fonction des besoins.
Seule la configuration du logging doit changer.
Pourquoi log4j
4. La bibliothèque log4j met trois sortes de composants à disposition du
programmeur :
• les loggers écrire les messages
• les appenders sélectionner la destination des messages,
• les layouts mettre en forme les messages.
Composant offerts par log4j
5. La classe Logger
Le Logger est l’entité de base pour effectuer la journalisation, il est mis en œuvre par le
biais de la classe org.apache.log4j.Logger.
L’obtention d’une instance de Logger se fait en appelant la méthode statique
Logger.getLogger :
package com.exemple;
import org.apache.log4j.Logger;
public class MaClasse {
private static Logger logger = LoggerFactory.getLogger(MaClasse.class);…
}
6. • la classe Logger fournie une méthode statique getLogger() qui attend en paramètre le
nom du logger.
• Si un logger existe déjà avec le nom fourni, alors la méthode getLogger() renvoie une
instance sur ce logger.
• Il est possible de donner un nom arbitraire au Logger.
• Pour des raisons de facilité, on peut utiliser le nom de la classe.
La méthode getLogger()
7. • le Root Logger est le logger racine de tous les loggers.
• Pour obtenir une instance de ce logger racine, utiliser
Logger rootLogger =
LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
• Le rootLogger a deux caractéristiques distinctives par rapport aux autres loggers :
• Il existe toujours
• Il n'a pas de nom
le logger racine
private static Logger logger1 = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
8. La hiérarchie des loggers.
• chaque logger, à l’exception du logger racine, a un ou plusieurs ancêtres.
• Le logger racine est l’ancêtre de tous les loggers nommés.
• un logger est un ancêtre d’un autre logger si le nom de l’ancêtre suivi d’un point est un
préfixe du nom du logger descendant.
• Par exemple, un logger nommé ma est un ancêtre d’un logger nommé ma.ensa. Les
loggers ma et ma.ensa sont tous deux les ancêtres d’un logger nommé ma.ensa.validate.
9. Cette hiérarchie est importante pour deux raisons
• Quand aucun niveau n’a été attribué à un logger, il hérite du niveau de son parent
• Quand une requête de log est validée, tous les appenders attachés au logger et à ses
ancêtres sont appelés Ces deux fonctions offrent une grande souplesse d’organisation
et de contrôle du logging dans une grande application.
La hiérarchie des loggers.
10. Les niveaux de journalisation
• Le logger associe à chaque message à journaliser un niveau de priorité
• La notion de niveau de journalisation ou de priorité d’un message représente l’importance du
message à journaliser.
• Elle est représentée par la classe org.apache.log4j.Level
• Un message n’est journalisé que si sa priorité est supérieure ou égale à la priorité du Logger
effectuant la journalisation.
• L’API Log4j définit 5 niveaux de logging présentés ici par gravité décroissante :
• FATAL : journaliser une erreur grave pouvant mener à l’arrêt prématuré de l’application.
• ERROR : journaliser une erreur qui n’empêche cependant pas l’application de fonctionner.
• WARN : journaliser un avertissement, il peut s’agir par exemple d’une incohérence dans
la configuration.
• INFO : journaliser des messages à caractère informatif.
• DEBUG : générer des messages pouvant être utiles au débogage.
11. • La journalisation d’un message à un niveau donné se fait au moyen de la méthode :
log(Priority,Message).
logger.log(Level.INFO, "mon message");
logger.info("mon message");
logger.info("je souhaite logger {}" , "ce message");
• Si vous avez besoin de niveaux supplémentaires, vous pouvez créer les vôtres en
sous-classant
org.apache.log4j.Level.
12. Cible de message : Appenders
L’enregistrement des événements de journalisation est délégué à des objets spécifiques
appelés Appenders,
Ces objets implémentent l’interface org.apache.log4j.Appender
Log4j propose une série d’Appenders
• org.apache.log4j.ConsoleAppender : Effectue la journalisation vers la console
• org.apache.log4j.FileAppender : Journalise dans un fichier
• org.apache.log4j.DailyRollingFileAppender : Journalise dans un fichier qui tourne régulièrement
(contrairement à ce que son nom suggère, ce n’est pas forcément tous les jours) ;
• org.apache.log4j.RollingFileAppender : Journalise dans un fichier, celui-ci est renommé lorsqu’il
atteint une certaine taille et la journalisation reprend dans un nouveau fichier
• org.apache.log4j.jdbc.JDBCAppender : Effectue la journalisation vers une base de données
• org.apache.log4j.net.JMSAppender : Utilise JMS pour journaliser les événements
13. • Les Layouts sont utilisés pour mettre en forme les différents événements de
journalisation avant qu’ils ne soient enregistrés.
• Ils sont utilisés en conjugaison avec les Appenders.
Mise en forme de message : Layouts
14. Les Layouts fournis par log4j sont les suivants
• org.apache.log4j.SimpleLayout : Comme son nom l’indique, il s’agit du Layout le plus
simple, les événements journalisés ont le format Niveau
Message[Retour à la ligne] ;
• org.apache.log4j.PatternLayout : Layout le plus flexible, le format du message est
spécifié par un motif (pattern) composé de texte et de séquences d’échappement
indiquant les informations à afficher.
• org.apache.log4j.XMLLayout : Comme son nom l’indique, formate les données de
l’événement de journalisation en XML (à utiliser en conjugaison avec un Appender de la
famille des FileAppenders) ;
• org.apache.log4j.HTMLLayout : Les événements sont journalisés au format HTML.
Chaque nouvelle session de journalisation (réinitialisation de Log4j) donne lieu à un
document HTML complet (ie. préambule DOCTYPE, <html>, etc).
15. Le PatternLayout permet de préciser le format du fichier de log grâce à des motifs
qui sont dynamiquement remplacés par leur valeur à l'exécution. Les motifs
commencent par un caractère % suivi d'une lettre :
PatternLayout
Motif Role
%c le nom du logger qui a émis le message
%C le nom de la classe qui a émis le message
%d le timestamp de l'émission du message
%m le message
%n un retour chariot
%p la priorité du message
%r
le nombre de milliseconde écoulé entre le lancement de l'application et l'émission du
message
%t le nom du thread
%F Le nom du fichier émettant le message
%% le caractère %
16. Il est possible de préciser le formattage de chaque motif grâce à un alignement et/ou une
troncature. Dans le tableau ci dessous, la caractère # représente une des lettres du tableau
ci dessus, n représente un nombre de caractères.
Motif Role
%# aucun formattage (par défaut)
%n#
alignement à droite, des blancs sont ajoutés si la taille
du motif est inférieure à n caractères
%-n#
alignement à gauche, des blanc sont ajoutés si la taille du
motif est inférieure à n caractères
%.n tronque le motif si il est supérieur à n caractères
%-n.n#
alignement à gauche, taille du motif obligatoirement de n
caractères (troncature ou complément avec des blancs)
formattage de chaque motif
17. Configuration de logger
La configuration de logger peut se faire via :
• un fichier properties classique (clé=valeur(s))
• un fichier XML
• par programmation, si vous procédez de cette façon, vous devez
appeler la méthode activateOptions() de chaque Appender une fois
que vous lui avez fourni tous ses paramètres.
22. La vulnérabilité de Log4j est une faille de sécurité découverte en décembre 2021 dans la
bibliothèque de journalisation de Log4j, qui est largement utilisée dans de nombreuses
applications Java.
La vulnérabilité permet à un attaquant de provoquer l'exécution de code malveillant à
distance en exploitant une fonctionnalité de Log4j appelée "lookups" (recherche de valeurs
de configuration dynamiques). L'exploitation de cette vulnérabilité peut permettre à un
attaquant de prendre le contrôle d'un système et d'y exécuter des commandes à distance.
La communauté de la sécurité informatique a pris des mesures pour remédier à cette
vulnérabilité en publiant des correctifs et des mises à jour pour les logiciels affectés. Les
utilisateurs sont fortement encouragés à mettre à jour leurs systèmes et leurs applications
avec les derniers correctifs de sécurité pour se protéger contre les attaques exploitant cette
vulnérabilité.
La vulnérabilité de Log4j
23. Les lookups Log4j sont des mécanismes permettant d'insérer des valeurs dynamiques dans les
messages de journalisation.
Plus précisément, les lookups Log4j sont des expressions de texte entourées de ${} qui sont évaluées
dynamiquement lors de la génération d'un message de journalisation.
${date:MM-dd-yyyy}.
${docker:containerName}
${env:JAVA_HOME}
${java:runtime} - ${java:vm} - ${java:os}
Les lookups Log4j
${jndi:ldap://127.0.0.1:389/resource}
Date Lookup
Docker Lookup
Environnement Lookup
java Lookup
Jndi Lookup
24. il est possible de désactiver complètement les lookups dans Log4j en modifiant la configuration
du framework de logging.
log4j2.formatMsgNoLookups=true
<Configuration formatMsgNoLookups="true">
<!-- Définir les appenders, les loggers et les niveaux de logging ici -->
</Configuration>
Log2j.xml
Log2j.properties
Désactiver les lookup log4j