Articles

Comment Fonctionne Log4J2: 10 Façons d’en tirer le meilleur parti

Log4j2 est la version mise à jour de la bibliothèque log4j populaire et influente, largement utilisée dans l’écosystème Java depuis de nombreuses années. Version 2.x conserve toutes les fonctionnalités de journalisation de son prédécesseur et s’appuie sur cette base avec quelques améliorations significatives, en particulier dans le domaine des performances.

Et bien sûr, étant donné à quel point la journalisation est instrumentale pour n’importe quelle application, à la fois à des fins d’audit et de débogage, le choix d’une bibliothèque de journalisation solide est une décision assez importante.

Dans les sections suivantes, nous allons examiner pourquoi la bibliothèque log4j2 est un excellent choix pour cette décision et comment nous pouvons l’utiliser dans une application.

Configuration de base de Log4j2

Pour commencer à utiliser log4j2 dans votre projet, il vous suffit d’ajouter la dépendance log4j-core. Si vous utilisez Maven, vous pouvez ajouter la dépendance suivante à votre pom.fichier xml:

Et si vous travaillez avec Gradle, vous devez ajouter la dépendance à la génération.fichier gradle:

dependencies { compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.8.2'}

Prêt à l’emploi, log4j2 fournira automatiquement une configuration simple, si vous n’en définissez pas explicitement vous-même. La configuration par défaut se connecte à la console à un niveau d’ERREUR ou supérieur.

Pour démarrer la journalisation des messages à l’aide de cette configuration de base, il vous suffit d’obtenir une instance de Logger à l’aide de la classe LogManager:

private static Logger logger = LogManager.getLogger(MyService.class);

Ensuite, vous pouvez utiliser l’objet logger avec des méthodes correspondant au niveau de journal souhaité :

logger.error("This is an error message");

Personnalisation de la configuration Log4j2

Une configuration log4j2 personnalisée peut être créée par programme ou via un fichier de configuration.

La bibliothèque prend en charge les fichiers de configuration écrits en XML, JSON, YAML, ainsi que le.format des propriétés. Ici, nous allons utiliser XML pour discuter de tous les exemples principalement.

Tout d’abord, vous pouvez remplacer la configuration par défaut en créant simplement un log4j2.fichier xml sur le chemin de classe:

Examinons de plus près les balises utilisées dans cette configuration simple :

  • Configuration : l’élément racine d’un fichier de configuration log4j2 ; l’attribut status représente le niveau auquel les événements log4j internes doivent être enregistrés
  • Appenders : cet élément contient une liste d’appenders ; dans notre exemple, un appender correspondant à la console système est défini
  • Loggers : cet élément contient une liste d’instances de Logger. L’élément racine est un enregistreur standard qui génère tous les messages

Il est important de comprendre que l’enregistreur racine est obligatoire dans chaque configuration. Comme indiqué, si vous n’en fournissez pas, il sera automatiquement configuré par défaut avec un appender de console et le niveau du journal des ERREURS.

Configuration des Appenders

Dans l’architecture log4j2, un appender est essentiellement responsable de l’envoi de messages de journal à une certaine destination de sortie.

Voici quelques-uns des types d’appenders les plus utiles fournis par la bibliothèque:

  • ConsoleAppender – enregistre les messages sur la console système
  • FileAppender – écrit les messages de journal dans un fichier
  • RollingFileAppender – écrit les messages dans un fichier journal roulant
  • JDBCAppender – utilise une base de données relationnelle pour les journaux
  • AsyncAppender – contient une liste d’autres appenders et détermine les journaux à écrire dans un thread séparé

Pour mieux comprendre le fonctionnement des appenders, examinons quelques exemples de configuration.

Le RollingFileAppender

Tout consigner dans un seul fichier n’est bien sûr pas idéal. Il est généralement préférable de parcourir régulièrement le fichier journal actif – ce que fait exactement le RollingFileAppender.

Vous pourrez également aller au-delà des bases avec ce type d’appender et configurer à la fois une stratégie de déclenchement personnalisée et une stratégie de roulement.

La stratégie de déclenchement détermine quand le fichier journal est lancé, ce qui signifie qu’un nouveau fichier est créé, tandis que la stratégie de basculement détermine comment le fichier est lancé.

À titre d’exemple rapide, configurons un appender qui crée un nouveau fichier journal basé sur 3 stratégies:

  • OnStartupTriggeringPolicy – un nouveau fichier journal est créé chaque fois que la JVM démarre
  • TimeBasedTriggeringPolicy – le fichier journal est roulé en fonction d’un modèle de date / heure
  • SizeBasedTriggeringPolicy – le fichier est roulé lorsqu’il atteint une certaine taille

La configuration utilisera la stratégie DefaultRolloverStrategy:

Vous pouvez voir à quel point ce style de configuration est flexible et comment vous pouvez ajuster la sémantique exacte de votre stratégie de journalisation – jusque dans les moindres détails.

Le JDBCAppender

Comme son nom l’indique, cet appender utilise JDBC pour écrire des journaux dans une base de données relationnelle.

Pour cette configuration, vous devez définir une ConnectionSource, qui peut être une source de données JNDI ou une ConnectionFactory personnalisée. L’enregistreur utilise la source de connexion pour obtenir des connexions JDBC, c’est pourquoi il est important d’utiliser un pool de connexions pour de meilleures performances.

Pour configurer l’appender dans le fichier de configuration XML, vous pouvez utiliser la balise JDBC:

Comme vous pouvez le voir, la source de données JNDI est simplement spécifiée à l’aide de l’attribut jndiName de la balise DataSource. Avec la source de connexion, vous pouvez définir la table et les colonnes à utiliser pour stocker les données du journal.

Le FailoverAppender

Enfin, jetons un coup d’œil au FailoverAppender; cela définit un appender principal et une liste de sauvegardes qui interviendront pour gérer la journalisation au cas où le principal échouerait.

Par exemple, vous pouvez configurer un JDBCAppender principal, avec un secondaire les appenders RollingFile et Console au cas où une connexion à la base de données ne pourrait pas être établie :

Dans un environnement de production, avoir une stratégie de basculement pour votre mécanisme de journalisation est toujours une bonne idée.

Configuration des mises en page

Alors que les appenders sont responsables de l’envoi des messages de journal vers une destination, les mises en page sont utilisées par les appenders pour définir la façon dont un message de journal sera formaté.

Voici une brève description de certaines des mises en page les plus couramment utilisées proposées par log4j2:

  • PatternLayout – configure les messages selon un motif de chaîne
  • JsonLayout – définit un format JSON pour les messages de journal
  • CsvLayout – peut être utilisé pour créer des messages au format CSV

Le PatternLayout

Le premier type de mise en page que nous allons examiner est le PatternLayout. C’est une solution assez flexible qui vous donne beaucoup de contrôle sur la sortie finale du message de journal.

Le mécanisme est principalement piloté par un modèle de conversion qui contient des spécificateurs de conversion. Chaque spécificateur commence par le signe %, suivi de modificateurs qui contrôlent des éléments tels que la largeur et la couleur du message, et d’un caractère de conversion qui représente le contenu, tel que la date ou le nom du thread.

Regardons un exemple de configuration d’un PatternLayout qui configure les lignes de journal pour afficher la date, le thread, le niveau de journal et le message de journal avec des couleurs différentes pour différents niveaux de journal :

Ces spécificateurs méritent d’être compris en détail, alors regardons de plus près :

  • %d {HH:mm:ss.SSS} – affiche la date de l’événement de journal dans le format spécifié
  • %t – affiche le nom du thread
  • %level – affiche le niveau de journal du message
  • %highlight{%level} – est utilisé pour définir les couleurs du motif entre accolades
  • %msg%n – affiche le message de journal

La sortie affichera les niveaux de journal avec différentes couleurs:

Vous pouvez en savoir plus sur l’ensemble complet des options pour définir des modèles dans la documentation log4j2 sur PatternLayout.

La journalisation des données JsonLayout

au format JSON présente des avantages significatifs, tels que la facilité d’analyse et de traitement des journaux par des outils de journalisation sur la ligne.

Pour configurer le JSONLayout dans log4j2, vous pouvez simplement définir la balise correspondante :

<JSONLayout complete="true" compact="false"/>

Setting complete=true produira un document JSON bien formé :

Pour pouvoir produire du JSON, vous devez également ajouter la bibliothèque jackson-databind au chemin de classe:

Configuration des filtres

Les filtres dans log4j2 sont utilisés pour déterminer si un message de journal doit être traité ou ignoré.

Un filtre peut être configuré pour l’ensemble de la configuration ou au niveau de l’enregistreur ou de l’appender.

La bibliothèque fournit plusieurs types de filtres qui peuvent être utilisés:

  • BurstFilter – contrôle le nombre d’événements de journal autorisés
  • DynamicThresholdFilter – filtre les lignes de journal en fonction de certains attributs
  • RegexFilter – filtre les messages en fonction de leur correspondance avec une expression régulière

Vous pouvez, par exemple, contrôler le débit avec lequel l’application est autorisée à enregistrer des données.

Pour ce faire, vous pouvez configurer un BurstFilter et l’appliquer aux messages d’INFORMATION:

<Filters> <BurstFilter level="INFO" rate="10" maxBurst="100"/></Filters>

Cela ignorera sélectivement le contrôle du trafic des messages de niveau INFO et ci-dessous tout en vous assurant de ne perdre aucun des messages les plus importants ci-dessus INFO.

Dans ce cas, rate définit les messages de journaux moyens à traiter par seconde, et maxBurst contrôle la taille globale de la salve de trafic avant que le filtre ne commence à éliminer les entrées de journal.

De même, nous pouvons configurer l’appender uniquement pour accepter les messages de journal qui correspondent à une expression régulière spécifique:

<Appenders> <JDBC name="JDBCAppender"> <RegexFilter regex="*jdbc*" onMatch="ACCEPT" onMismatch="DENY"/> </JDBC></Appenders>

Dans l’ensemble, ce mécanisme de filtrage peut être utilisé avec une grande précision pour s’assurer que chaque appender de votre configuration de journalisation globale suit les bonnes informations. La capacité de ne consigner que des informations très spécifiques et pertinentes conduit généralement à une analyse très rapide des causes profondes, en particulier dans les systèmes complexes – en particulier lorsqu’elle est couplée à un puissant outil de visualisation des journaux.

Configuration des enregistreurs

En plus de l’enregistreur racine, nous pouvons également définir des éléments d’enregistreur supplémentaires avec différents niveaux de journal, ajouts ou filtres. Chaque enregistreur nécessite un nom qui peut être utilisé plus tard pour le référencer :

<Loggers> <Logger name="RollingFileLogger"> <AppenderRef ref="RollingFileAppender" /> </Logger></Loggers>

Pour écrire des messages de journal à l’aide de cet Enregistreur particulier, vous pouvez en obtenir une référence à l’aide de la classe LogManager :

Logger rfLogger = LogManager.getLogger("RollingFileLogger");rfLogger.info("User info updated");

Une autre façon très courante de structurer la hiérarchie de ces enregistreurs est basée sur la classe Java :

Logger rfLogger = LogManager.getLogger("RollingFileLogger");rfLogger.info("User info updated");

Logger logger = LogManager.getLogger(MyServiceTest.class);

Utiliser des recherches

Les recherches représentent un moyen d’insérer des valeurs externes dans la configuration log4j2. Nous avons déjà vu un exemple de recherche de date dans la configuration RollingFileAppender:

<RollingFile name="RollingFileAppender" fileName="logs/app.log" filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">

La recherche ${date:aaaa-MM} insérera la date actuelle dans le nom de fichier, tandis que le précédent $ est un caractère d’échappement, pour insérer l’expression de recherche dans l’attribut filePattern.

Vous pouvez également insérer des valeurs de propriétés système dans la configuration log4j2 en utilisant le format{{sys:property_name}:

<File name="ApplicationLog" fileName="${sys:path}/app.log"/>

Un autre type d’informations que vous pouvez rechercher et insérer est les informations d’environnement Java:

<PatternLayout header="${java:version} - ${java:os}"> <Pattern>%d %m%n</Pattern></PatternLayout>

Vous pouvez trouver plus de détails sur le type de données que vous pouvez insérer documentation log4j2.

Configuration programmatique

Outre les fichiers de configuration, log4j2 peut également être configuré par programmation. Il existe plusieurs façons de le faire :

  • créer une ConfigurationFactory personnalisée
  • utiliser la classe Configurator
  • modifier la configuration après l’initialisation
  • combiner les fichiers de propriétés et la configuration programmatique

Voyons comment configurer une mise en page et un appender par programmation :

Ensuite, vous pouvez définir un enregistreur à l’aide de la classe LoggerConfig, y associer l’appender, et mettre à jour la configuration:

Ensuite, vous pouvez commencer à utiliser l’enregistreur comme d’habitude:

Logger pLogger = LogManager.getLogger("programmaticLogger");pLogger.info("Programmatic Logger Message");

Ce style d’API fluide peut conduire à un développement et à une itération plus rapides sur des configurations de journalisation plus complexes car vous bénéficiez maintenant des avantages de travailler directement avec du code Java.

Cependant, étant donné que XML peut toujours être plus lisible et compact, vous pouvez souvent développer la configuration par programme, puis la convertir en XML lorsque tout est terminé.

Niveaux de journal personnalisés

Les niveaux de journal intégrés pour log4j2 sont:

  • OFF
  • FATAL
  • ERROR
  • WARN
  • INFO
  • DEBUG
  • TRACE
  • ALL

En plus de ceux-ci, vous pouvez également définir un niveau de journal personnalisé en fonction des besoins de votre application.

Par exemple, pour définir ce nouveau niveau de journal, vous pouvez utiliser le Niveau.API forName() – spécifie le nouveau nom de niveau et un entier qui représente la place du niveau dans la hiérarchie des niveaux de journal:

Level myLevel = Level.forName("NEW_LEVEL", 350);

Pour déterminer quelle valeur entière utiliser, vous pouvez consulter les valeurs définies pour les autres niveaux de log dans la documentation log4j2 :

La valeur 350 place le niveau entre WARN et INFO, ce qui signifie que les messages seront affichés lorsque le niveau est défini sur INFO ou au-dessus.

Pour enregistrer un message au niveau personnalisé, vous devez utiliser la méthode log() :

logger.log(myLevel, "Custom Level Message");

La configuration XML équivalente peut être :

<CustomLevels> <CustomLevel name="NEW_XML_LEVEL" intLevel="350" /></CustomLevels>

Ensuite, elle peut être utilisée via l’API de journal standard:

logger.log(Level.getLevel("NEW_XML_LEVEL"),"Custom XML Level Message");

Les nouveaux niveaux personnalisés seront affichés de la même manière que les niveaux standard :

11:28:23.558 NEW_LEVEL - Custom Level Message11:28:23.559 NEW_XML_LEVEL - Custom XML Level Message

Migrant depuis Log4j 1.x

Si vous migrez une application à l’aide du 1.x version de la bibliothèque au courant 2.version x, il y a quelques routes que vous pouvez suivre:

  • utilisez le log4j 1.x bridge
  • mettre à jour manuellement l’API et la configuration

En utilisant le pont est triviale. Il vous suffit de remplacer la dépendance log4j par la bibliothèque log4j-1.2-api:

Bien qu’il s’agisse de la méthode la plus rapide, elle présente l’inconvénient d’être limitée dans le type de configuration pouvant être convertie.

La méthode manuelle est, bien sûr, plus de travail, mais conduira éventuellement à une solution de journalisation plus flexible et plus puissante.

Voici quelques-uns des types de modifications les plus courants que vous devrez effectuer:

Conclusion

Les fichiers journaux sont essentiels dans n’importe quel environnement de production, et choisir une bonne solution de journalisation peut faire la différence entre passer 5 minutes et passer une journée complète à comprendre un problème en production.

Log4j2 est une solution de journalisation puissante et robuste pour les applications Java modernes, avec une large gamme d’options de configuration.

Il permet de configurer facilement les meilleures pratiques de journalisation avancées telles que les fichiers en continu, différents types de destinations de sortie de journalisation, la prise en charge de formats de journalisation structurés tels que JSON ou XML, l’utilisation de plusieurs enregistreurs et filtres et des niveaux de journalisation personnalisés.

Enfin, lorsque vous devez aller au-delà de l’analyse manuelle des données de journal, consultez certainement les fonctionnalités de journalisation incluses dans Retrace APM.