CodeGym /Blog Java /Random-FR /Logging : quoi, comment, où et avec quoi ?
John Squirrels
Niveau 41
San Francisco

Logging : quoi, comment, où et avec quoi ?

Publié dans le groupe Random-FR
Bonjour à tous dans la communauté CodeGym ! Logging : quoi, comment, où et avec quoi ?  - 1 Aujourd'hui, parlons de la journalisation :
  1. Qu'est-ce que c'est, pourquoi il existe, quand l'utiliser, quand l'éviter.
  2. Quelles implémentations de journalisation sont disponibles en Java et ce que vous devez faire avec toutes ces options de journalisation.
  3. Et les niveaux de journalisation. Nous verrons ce qu'est l'appender et comment le configurer correctement.
  4. Noeuds de journalisation et comment les configurer correctement pour que tout fonctionne comme nous le souhaitons.
Ce matériel est destiné à un large public. Il sera clair pour tous ceux qui commencent à connaître Java, ainsi que pour les personnes qui travaillent déjà mais qui n'ont fait qu'explorer logger.info("log something"); Let's go !

Pourquoi avez-vous besoin d'une journalisation ?

Examinons quelques cas réels où la journalisation peut résoudre un problème. Voici un exemple tiré de mon travail. Il y a des points où une application s'intègre à d'autres services. J'utilise la journalisation à ces points pour établir une sorte "d'alibi" : si l'intégration ne fonctionne pas, il devient facile de déterminer de quel côté se trouve le problème. Il est également souhaitable de consigner les informations importantes stockées dans une base de données. Par exemple, la création d'un utilisateur admin. C'est précisément le genre de chose qu'il serait bon de consigner.

Outils de journalisation en Java

Parmi les solutions de journalisation bien connues en Java, nous pouvons souligner les suivantes :
  • Log4j
  • JUIL — java.util.logging
  • JCL — Jakarta Commons Logging
  • Retour de session
  • SLF4J - Façade de journalisation simple pour Java
Nous ferons un tour d'horizon de chacun d'entre eux. Ensuite, nous prendrons une liaison slf4j - log4j comme base d'une discussion pratique. Cela peut sembler étrange maintenant, mais ne vous inquiétez pas : à la fin de l'article, tout sera clair.

System.err.println

Au début, il y avait System.err.println (affichant les entrées du journal sur la console). Aujourd'hui encore, cette technique est utilisée pour rapidement un journal lors du débogage. Bien sûr, il n'y a pas de paramètres à discuter ici, alors souvenez-vous simplement de cette méthode et nous passerons à autre chose.

Log4j

Il s'agit d'une solution complète que les développeurs ont créée par nécessité. Le résultat est un outil vraiment intéressant que vous pouvez utiliser. En raison de diverses circonstances, cette solution ne s'est pas retrouvée dans le JDK, ce qui a grandement bouleversé toute la communauté. Log4j a des options de configuration qui vous permettent d'activer la journalisation dans le com.example.typepackage et de la désactiver dans le com.example.type.genericsous-package. Cela permet d'exclure rapidement le code qui n'a pas besoin d'être journalisé. Il est important de noter ici qu'il existe deux versions de Log4j : 1.2.x et 2.xx, et qu'elles sont incompatibles entre elles . Log4j a ajouté les concepts d' appender(un outil utilisé pour écrire des journaux) et mise en page (formatage des journaux). Cela vous permet de consigner uniquement ce dont vous avez besoin et de le consigner exactement comme vous en avez besoin. Nous parlerons davantage d'appender un peu plus tard.

JUIL — java.util.logging

L'un des principaux avantages de cette solution est que JUL est inclus dans le JDK (Java Development Kit). Malheureusement, lors de son développement, ses créateurs ne l'ont pas basé sur le populaire utilitaire Log4j, mais plutôt sur une solution d'IBM. Cette décision a eu des conséquences. La réalité est que personne n'utilise JUL maintenant. Les niveaux de journalisation dans JUL diffèrent de ceux de Logback, Log4j et Slf4j. Cela rend plus difficile pour eux de se comprendre. La création d'un enregistreur est plus ou moins similaire. Pour ce faire, vous devez faire une importation :

java.util.logging.Logger log = java.util.logging.Logger.getLogger(LoggingJul.class.getName());
Le nom de la classe est passé, nous savons donc d'où viendra notre journalisation. À partir de Java 8, vous pouvez passer Supplier<String>. Cela nous aide à lire et à créer une ligne uniquement lorsque nous en avons vraiment besoin, plutôt qu'à chaque fois, comme c'était le cas auparavant. Ce n'est qu'avec la sortie de Java 8 que les développeurs ont finalement résolu des problèmes importants et rendu JUL vraiment utilisable. À savoir, les méthodes avec un Supplier<String> msgSupplierparamètre, comme indiqué ci-dessous :

public void info(Supplier<String> msgSupplier) {
   log(Level.INFO, msgSupplier);
}

JCL — Jakarta Commons Logging

Parce qu'il n'y avait pas de norme industrielle concernant la journalisation depuis longtemps et que de nombreuses personnes créaient leurs propres enregistreurs personnalisés, la décision a été prise de publier JCL, un wrapper général pouvant être utilisé par-dessus d'autres. Pourquoi? Parfois, les dépendances ajoutées au projet utilisaient un enregistreur différent de celui du projet. Pour cette raison, ils ont été ajoutés au projet en tant que dépendances transitives, ce qui a créé de réels problèmes lors de la tentative de tout assembler. Malheureusement, l'emballage n'était pas très fonctionnel et n'ajoutait rien. Ce serait probablement pratique si tout le monde utilisait JCL. Mais ce n'est pas ce qui s'est passé, donc utiliser JCL n'est pas la meilleure idée pour le moment.

Retour de session

Le chemin de l'open source est épineux... Le même développeur qui a écrit Log4j a également écrit Logback comme framework de journalisation successeur. Il était basé sur la même idée que Log4j. Les différences dans Logback sont :
  • performance améliorée
  • ajout du support natif pour Slf4j
  • options de filtrage étendues
Par défaut, Logback ne nécessite aucune configuration et enregistre tous les événements au niveau DEBUG et supérieur. Si vous avez besoin d'une personnalisation, vous pouvez l'obtenir via une configuration XML :

<configuration> 
    <appender name="FILE" class="ch.qos.logback.core.FileAppender"> 
        <file>app.log</file> 
        <encoder> 
            <pattern>%d{HH:mm:ss,SSS} %-5p [%c] - %m%n</pattern> 
        </encoder> 
    </appender> 
    <logger name="org.hibernate.SQL" level="DEBUG" /> 
    <logger name="org.hibernate.type.descriptor.sql" level="TRACE" /> 
    <root level="info"> 
        <appender-ref ref="FILE" /> 
    </root> 
</configuration>

SLF4J - Façade de journalisation simple pour Java

En 2006, l'un des pères fondateurs de Log4j a quitté le projet et a créé Slf4j (Simple Logging Facade for Java), un wrapper pour Log4j, JUL, common-logging et Logback. Comme vous pouvez le voir, nous avons avancé au point de créer un wrapper sur un wrapper... Dans ce cas, il est divisé en deux parties : une API qui est utilisée dans l'application, et une implémentation qui est ajoutée avec des dépendances pour chaque type de journalisation. Par exemple, slf4j-log4j12.jaret slf4j-jdk14.jar. Vous devez brancher la bonne implémentation et c'est tout : tout votre projet l'utilisera. Slf4j prend en charge toutes les dernières fonctionnalités, telles que le formatage des chaînes pour la journalisation. Auparavant, il y avait un tel problème. Disons que nous créons une entrée de journal comme celle-ci :

log.debug("User " + user + " connected from " + request.getRemoteAddr());
Grâce à l'opérateur de concaténation, l' userobjet devient silencieusement une chaîne grâce à user.toString(). Cela prend du temps et ralentit le système. Et cela peut être OK si nous déboguons l'application. Nous commençons à rencontrer des problèmes si le niveau de journalisation de cette classe est INFO ou supérieur. En d'autres termes, nous ne devrions pas écrire cette entrée de journal (pour INFO ou supérieur) et nous ne devrions pas utiliser la concaténation de chaînes. En théorie, la bibliothèque de journalisation elle-même devrait résoudre ce problème. En l'occurrence, cela s'est avéré être le plus gros problème de la première version de Log4j. Il n'a pas fourni de solution décente, mais a plutôt suggéré de faire quelque chose comme ceci:

if (log.isDebugEnabled()) {
    log.debug("User " + user + " connected from " + request.getRemoteAddr());
}
Autrement dit, au lieu d'une ligne de code pour la journalisation, ils ont suggéré d'en écrire 3 ! La journalisation devrait minimiser les modifications de code, et les trois lignes violent clairement cette approche générale. Slf4j n'avait aucun problème de compatibilité avec le JDK et l'API, donc une belle solution a immédiatement émergé :

log.debug("User {} connected from {}", user, request.getRemoteAddr());
{}désigne des espaces réservés pour les arguments passés à la méthode. Autrement dit, le premier {}correspond à user, et le second {}correspond à request.getRemoteAddr(). En procédant de cette façon, nous n'effectuerons la concaténation de chaînes que si le niveau de journal nous oblige à écrire l'entrée de journal. Après cela, Sjf4j a commencé à gagner rapidement en popularité. Actuellement, c'est la meilleure solution. Par conséquent, examinons la journalisation à l'aide d'une slf4j-log4j12liaison.

Ce qui doit être enregistré

Bien sûr, vous ne devez pas tout enregistrer. Ce n'est souvent pas nécessaire et parfois même dangereux. Par exemple, si vous enregistrez les données personnelles de quelqu'un et qu'elles sont divulguées d'une manière ou d'une autre, il y aura de vrais problèmes, en particulier dans les projets axés sur les marchés occidentaux. Mais il y a aussi des choses que vous devez absolument enregistrer :
  1. Début/fin de l'application. Nous devons savoir si l'application a vraiment commencé et s'est terminée comme prévu.
  2. Les problèmes de sécurité. Ici, il serait bon de consigner les tentatives de deviner le mot de passe de quelqu'un, les cas où les administrateurs se connectent, etc.
  3. Certains états d'application . Par exemple, le passage d'un état à un autre dans un processus métier.
  4. Certaines informations de débogage ainsi que le niveau de journalisation correspondant.
  5. Certains scripts SQL. Il existe des cas réels où cela est nécessaire. Mais encore une fois, en ajustant habilement les niveaux de journalisation, vous pouvez obtenir d'excellents résultats.
  6. Les threads en cours d'exécution peuvent être enregistrés lors de la vérification du bon fonctionnement des éléments.

Erreurs courantes dans la journalisation

Il y a beaucoup de nuances ici, mais nous ferons une mention spéciale de quelques erreurs courantes :
  1. Journalisation excessive. Vous ne devez pas consigner toutes les étapes qui pourraient théoriquement être importantes. Voici une bonne règle empirique : les journaux ne doivent pas dépasser 10 % de la charge. Sinon, il y aura des problèmes de performances.
  2. Enregistrement de toutes les données dans un seul fichier. À un moment donné, cela rendra très difficile la lecture/écriture du journal, sans parler du fait que certains systèmes ont des limites sur la taille des fichiers.
  3. Utilisation de niveaux de journalisation incorrects. Chaque niveau de journal a des limites claires et elles doivent être respectées. Si une limite n'est pas claire, vous pouvez vous mettre d'accord sur le niveau à utiliser.

Niveaux de journalisation

x : Visible
FATAL ERREUR AVERTIR INFO DÉBOGUER TRACE TOUS
DÉSACTIVÉ
FATAL X
ERREUR X X
AVERTIR X X X
INFO X X X X
DÉBOGUER X X X X X
TRACE X X X X X X
TOUS X X X X X X X
Que sont les niveaux de journalisation ? Afin de créer en quelque sorte une hiérarchie des entrées de journal, certaines conventions et délimitations sont nécessaires. C'est pourquoi les niveaux de journalisation ont été introduits. Le niveau est défini dans l'application. Si une entrée est inférieure à un niveau spécifié, elle n'est pas enregistrée. Par exemple, nous avons des journaux que nous utilisons lors du débogage de l'application. Pendant le fonctionnement normal (lorsque l'application est utilisée conformément à sa destination), ces journaux ne sont pas nécessaires. Par conséquent, le niveau de journalisation est plus élevé que pour le débogage. Examinons les niveaux de journalisation à l'aide de Log4j. Hormis JUL, d'autres solutions utilisent les mêmes niveaux de journalisation. Les voici par ordre décroissant :
  • OFF : aucune entrée de journal n'est enregistrée ; tout est ignoré.
  • FATAL : Une erreur qui empêche l'exécution de l'application. Par exemple, "Erreur de manque de mémoire JVM".
  • ERREUR : les erreurs à ce niveau indiquent des problèmes qui doivent être résolus. L'erreur n'arrête pas l'application dans son ensemble. D'autres requêtes peuvent fonctionner correctement.
  • AVERTISSEMENT : entrées de journal qui représentent un avertissement. Quelque chose d'inattendu s'est produit, mais le système a pu faire face et a répondu à la demande
  • INFO : entrées de journal indiquant des actions importantes dans l'application. Ce ne sont pas des erreurs ou des avertissements. Ce sont des événements système attendus.
  • DEBUG : les entrées de journaux doivent déboguer l'application. Pour s'assurer que l'application fait exactement ce qui est attendu, ou pour décrire les actions entreprises par l'application, c'est-à-dire "Méthode saisie 1".
  • TRACE : entrées de journal de priorité inférieure pour le débogage. Le niveau de journalisation le plus bas.
  • ALL : un niveau de journalisation pour l'écriture de toutes les entrées du journal de l'application.
Si le niveau de journalisation INFO est activé quelque part dans l'application, les entrées de chaque niveau seront enregistrées, de INFO à FATAL. Si le niveau de journal FATAL est défini, seules les entrées de journal avec ce niveau seront écrites.

Journalisation et envoi de journaux : Appender

Voyons comment tout cela fonctionne lorsque nous utilisons Log4j, qui offre de nombreuses opportunités pour écrire/envoyer des journaux :
  • écrire dans un fichier —DailyRollingFileAppender
  • pour écrire des informations sur la console —ConsoleAppender
  • pour écrire des journaux dans une base de données —JDBCAppender
  • pour gérer l'envoi des logs sur TCP/IP —TelnetAppender
  • pour s'assurer que la journalisation n'a pas d'impact négatif sur les performances —AsyncAppender
Il existe quelques autres implémentations : une liste complète est disponible ici . Au fait, si l'appender dont vous avez besoin n'existe pas, ce n'est pas un problème. Vous pouvez écrire votre propre appender en implémentant l' interface Appender , prise en charge par Log4j.

Nœuds de journalisation

À des fins de démonstration, nous utiliserons une interface Slf4j, avec une implémentation de Log4j. La création d'un logger est très simple : dans une classe nommée MainDemo, qui effectuera une journalisation, nous devons ajouter ce qui suit :

org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(MainDemo.class);
Cela créera un enregistreur pour nous. Pour créer une entrée de journal, il existe plusieurs méthodes disponibles dont les noms reflètent le niveau de journalisation qui sera utilisé. Par exemple:

logger.trace("Method 1 started with argument={}", argument);
logger.debug("Database updated with script = {}", script);
logger.info("Application has started on port = {}", port);
logger.warn("Log4j didn't find the log4j.properties file. Please fix this.");
logger.error("Connection refused to host = {}", host);
Bien que nous passions la classe, le nom final est le nom complet de la classe, y compris les packages. Ceci est fait pour que vous puissiez ensuite diviser la journalisation en nœuds et configurer le niveau de journalisation et l'appender pour chaque nœud. Par exemple, le logger a été créé dans la com.github.romankh3.logginglecture.MainDemoclasse. Le nom fournit la base pour créer une hiérarchie de nœuds de journalisation. Le nœud principal est RootLogger de niveau supérieur . Il s'agit du nœud qui reçoit toutes les entrées de journal pour l'ensemble de l'application. Les nœuds restants peuvent être représentés comme indiqué ci-dessous : Logging : quoi, comment, où et avec quoi ?  - 3Les appenders sont configurés pour des nœuds de journalisation spécifiques. Nous allons maintenant examiner le fichier log4j.properties pour voir un exemple de configuration.

Un guide étape par étape du fichier log4j.properties

Nous allons tout configurer une étape à la fois et voir ce qui est possible :

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
Cette ligne indique que nous enregistrons l'appender CONSOLE, qui utilise l'implémentation org.apache.log4j.ConsoleAppender. Cet appender écrit des informations sur la console. Ensuite, nous enregistrons un autre appender. Celui-ci écrira dans un fichier :

log4j.appender.FILE=org.apache.log4j.RollingFileAppender
Il est important de noter que les appenders eux-mêmes doivent encore être configurés. Une fois que nous avons enregistré nos appenders, nous pouvons déterminer quels niveaux de journalisation et quels appenders seront utilisés au niveau des nœuds.

log4j.rootLogger=DEBUG, CONSOLE, FICHIER

  • log4j.rootLogger signifie que nous configurons le nœud racine, qui contient toutes les entrées de journal
  • Le premier mot après le signe égal indique le niveau de log minimum à écrire (dans notre cas, il s'agit de DEBUG)
  • Après la virgule, nous indiquons tous les appendices à utiliser.
Pour configurer un nœud de journalisation plus spécifique, vous utiliseriez une entrée comme celle-ci :

log4j.logger.com.github.romankh3.logginglecture=TRACE, OWN, CONSOLE
log4j.logger.est utilisé pour référencer un nœud spécifique. Dans notre cas, com.github.romankh3.logginglecture. parlons maintenant de la configuration de l'appender CONSOLE :

# CONSOLE appender customization
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.threshold=DEBUG
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[%-5p] : %c:%L : %m%n
Ici, nous voyons qu'il est possible de définir le niveau spécifique auquel l'appender commencera à fonctionner. Voici un exemple de ce qui se passe réellement : supposons qu'un message avec le niveau INFO est reçu par le nœud de journalisation et transmis à l'appender qui lui est affecté. Si le seuil de l'appender est défini sur WARN, il reçoit l'entrée de journal mais ne fait rien avec. Ensuite, nous devons décider quelle mise en page le message utilisera. J'utilise PatternLayout dans l'exemple, mais il existe de nombreuses autres options. Nous ne les aborderons pas dans cet article. Exemple de configuration de l'appender FILE :

# File appender customization
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE.File=./target/logging/logging.log
log4j.appender.FILE.MaxFileSize=1MB
log4j.appender.FILE.threshold=DEBUG
log4j.appender.FILE.MaxBackupIndex=2
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=[ %-5p] - %c:%L - %m%n
Vous pouvez configurer le fichier spécifique dans lequel les entrées de journal seront écrites, comme on peut le voir sur cette ligne :

log4j.appender.FILE.File=./target/logging/logging.log
L'entrée est écrite dans le logging.logfichier. Pour éviter les problèmes de taille de fichier, vous pouvez configurer le maximum, qui dans ce cas est de 1 Mo. MaxBackupIndexindique le nombre de fichiers journaux de ce type. Si nous devons créer plus de fichiers que cela, le premier fichier sera supprimé. Pour regarder un exemple réel où la journalisation est configurée, vous pouvez accéder au référentiel public sur GitHub.

Renforcez ce dont nous avons discuté

Essayez par vous-même de faire tout ce que nous avons décrit :
  • Créez votre propre projet similaire à notre exemple ci-dessus.
  • Si vous savez utiliser Maven, utilisez-le. Si ce n'est pas le cas, lisez ce tutoriel, qui décrit comment connecter la bibliothèque.

En résumé

  1. Nous avons parlé des solutions de journalisation qui existent en Java.
  2. Presque toutes les bibliothèques de journalisation bien connues ont été écrites par une seule personne :D
  3. Nous avons appris ce qui devrait et ne devrait pas être enregistré.
  4. Nous avons déterminé les niveaux de journalisation.
  5. Nous avons été initiés aux nœuds de journalisation.
  6. Nous avons examiné ce qu'est un appender et à quoi il sert.
  7. Nous avons créé un fichier log4j.proterties étape par étape.

Matériaux additionnels

  1. CodeGym : leçon sur l'enregistreur
  2. Geekly hebdomadaire : journalisation Java. Bonjour le monde
  3. Coder l'horreur : le problème de la journalisation
  4. YouTube : Comprendre Java Logging Hell - Les bases. Java Logging Hell & Comment rester en dehors de ça
  5. Log4j : Appendice
  6. Log4j : mise en page
Voir aussi mon autre article :
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION