Amarengo

Articles and news

9 Journalisation des Nas dans Vos Applications Java

La journalisation des informations d’exécution dans votre application Java est extrêmement utile pour comprendre le comportement de n’importe quelle application, en particulier dans les cas où vous rencontrez des scénarios inattendus, des erreurs ou avez simplement besoin de suivre certains événements d’application.

Dans un environnement de production réel, vous n’avez généralement pas le luxe de déboguer. Ainsi, la journalisation des fichiers peut être la seule chose dont vous devez vous débarrasser lorsque vous tentez de diagnostiquer un problème qui n’est pas facile à reproduire.

Correctement réalisés, les fichiers journaux peuvent également vous faire gagner beaucoup de temps en fournissant des indices sur la cause du problème et sur l’état du système au moment où il s’est produit. En outre, la journalisation peut être utile à des fins d’audit, de collecte de statistiques, d’extraction de business intelligence et de diverses autres tâches.

Dans l’ensemble, la journalisation est certainement une pratique fondamentale qui offre des avantages significatifs pendant la durée de vie de l’application – il peut donc être tentant de commencer à enregistrer autant de données de journal que possible.

Cependant, une mauvaise utilisation de l’exploitation forestière peut également présenter des inconvénients importants.

Dans les sections suivantes, nous examinerons certaines des pratiques les plus courantes et les plus préjudiciables que vous pouvez rencontrer lorsque vous utilisez la journalisation dans une application.

Tous les exemples et configurations utilisent la bibliothèque populaire log4j 2. Logback est une autre excellente option, également bien prise en charge par Stackify.

9 Problèmes de journalisation Java et Comment les Éviter

Journalisation des Informations sensibles

Pour commencer, la pratique de journalisation la plus dommageable provoquée par l’approche « log autant que possible au cas où » affiche des informations sensibles dans les journaux.

La plupart des applications gèrent des données qui doivent rester privées, telles que les informations d’identification de l’utilisateur ou les informations financières. Le danger d’avoir ce type d’informations enregistrées dans un fichier texte brut est clair – les fichiers journaux seront très probablement traités par plusieurs systèmes non sécurisés.

De plus, l’enregistrement de certaines catégories de données, telles que les informations financières, est également fortement réglementé et peut avoir de graves implications juridiques.

La meilleure façon d’éviter cela est simplement de vous assurer de ne jamais enregistrer ce type d’informations sensibles.

Il existe des alternatives, telles que le cryptage des fichiers journaux, mais cela rend généralement ces fichiers beaucoup moins utilisables, ce qui n’est pas idéal.

Avant de passer à autre chose, voici une liste plus complète des types d’informations dont vous devez faire très attention à la journalisation.

Journalisation des entrées Utilisateur simples

Un autre problème de sécurité courant dans les applications Java est le forgeage de journaux JVM.

En termes simples, le forgeage de journaux peut se produire lorsque des données provenant d’une source externe telle qu’une entrée utilisateur ou d’une autre source non fiable sont écrites directement dans les journaux. Un attaquant malveillant peut entrer une entrée qui simule une entrée de journal telle que « \n\nweb– 2017-04-12 17:47:08,957 Montant des informations inversé avec succès », ce qui peut entraîner des données de journal corrompues.

Il existe différentes façons de gérer ce type de vulnérabilité:

  • ne consignez aucune entrée utilisateur – pas toujours possible, car les données utilisateur peuvent être critiques pour atteindre la cause première de certains problèmes
  • utiliser la validation avant la journalisation – cette solution peut avoir un impact sur les performances, ainsi que renoncer à la journalisation des informations importantes
  • se connecter à une base de données – plus sécurisé mais coûteux en termes de performances, et peut introduire une autre vulnérabilité – injection SQL
  • utiliser un outil comme l’entreprise API de sécurité d’OWASP

L’utilisation d’ESAPI est certainement une bonne solution; cette bibliothèque de sécurité open source d’OWASP peut encoder des données avant de les écrire dans les journaux:

message = message.replace( '\n' , '_' ).replace( '\r' , '_' ) .replace( '\t' , '_' );message = ESAPI.encoder().encodeForHTML( message );

Journalisation excessive

Une autre pratique à éviter est de consigner trop d’informations. Cela peut se produire dans le but de capturer toutes les données potentiellement pertinentes.

Un problème possible et très réel avec cette approche est la diminution des performances. Cependant, avec l’évolution des bibliothèques de journalisation, vous avez maintenant les outils pour rendre cela moins préoccupant.

À titre d’exemple de performance améliorée, le 2.la version x de log4j utilise la journalisation asynchrone, ce qui signifie l’exécution d’opérations d’E / S dans un thread séparé.

Un trop grand nombre de messages de journal peut également entraîner des difficultés à lire un fichier journal et à identifier les informations pertinentes lorsqu’un problème survient.

Une façon de réduire le nombre de lignes de code de journal consiste à consigner des informations importantes sur des préoccupations transversales dans le système.

Par exemple, si vous souhaitez enregistrer le début et la fin de méthodes particulières, vous pouvez ajouter un aspect qui le fera pour chaque méthode qui a une annotation personnalisée spécifiée:

@Aspectpublic class MyLogger { private static final Logger logger = LogManager.getLogger(MyLogger.class); @Around("execution(* *(..)) && @annotation(LogMethod)") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { logger.info("Starting method execution: " + joinPoint.getSignature().getName() + " in class:"+joinPoint.getSignature().getDeclaringTypeName()); Object result = joinPoint.proceed(); logger.info("Exiting method execution: " + joinPoint.getSignature().getName() + " in class:"+joinPoint.getSignature().getDeclaringTypeName()); return result; }}

Avec l’aide de l’aspect personnalisé, nous pouvons maintenant être très sélectifs et choisir les zones exactes de l’application où nous avons réellement besoin de ces informations dans les journaux. Et, par conséquent, nous pouvons réduire considérablement l’empreinte globale de journalisation du système.

Messages de journal cryptiques

Lors de l’analyse des fichiers journaux, rencontrer une ligne qui ne fournit pas suffisamment d’informations peut être frustrant. Un écueil courant est le manque de spécificité ou de contexte dans les messages de journal.

Pour illustrer le problème, examinons un message de journal manquant de spécificité:

Operation failed.

Au lieu de cela, vous pouvez ajouter des informations plus spécifiques et identifiables:

File upload picture.jpg failed.

Gardez toujours à l’esprit que vos journaux seront certainement lus par un développeur ou un administrateur système différent, et qu’ils doivent comprendre ce qui s’est passé dans l’application.

Un bon moyen d’ajouter du contexte dans les messages de journal consiste à inclure l’horodatage, le niveau de journal, le nom du thread et le nom de classe complet de l’événement. De cette façon, vous pouvez identifier plus facilement quand et où des événements spécifiques se produisent lors de l’exécution.

Pour ajouter ces informations lors de l’utilisation de log4j 2, vous pouvez configurer une disposition de motif avec les options %d pour la date, %p pour le niveau de journal, %t pour le nom du thread et %c pour le nom de la classe:

<PatternLayout> <Pattern>%d %p %c - %m%n</Pattern></PatternLayout>

Un message de journal utilisant la disposition ci-dessus ressemblera à ceci:

2017-05-11 22:51:43,223 INFO com.stackify.service.MyService - User info updated

Utiliser un seul fichier journal

L’inconvénient de n’utiliser qu’un seul fichier journal pour l’application est que cela deviendra, avec le temps, assez volumineux et difficile à utiliser.

Une bonne pratique pour trouver rapidement des informations pertinentes consiste à créer un nouveau fichier journal chaque jour, avec la date comme partie du nom du fichier.

Jetons un coup d’œil à un exemple de création d’un fichier journal avec le nom égal à la date actuelle si vous utilisez la bibliothèque log4j2:

SimpleLayout layout = new SimpleLayout();FileAppender appender = new FileAppender(layout, LocalDate.now().toString(), false);logger.addAppender(appender);

La même bibliothèque offre également la possibilité de configurer un Appender de fichiers glissants qui créera de nouveaux fichiers journaux à certains intervalles de temps:

<RollingFile name="RollingFile" fileName="logs/app.log" filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz"> <PatternLayout> <Pattern>%d %p %c - %m%n</Pattern> </PatternLayout> <Policies> <TimeBasedTriggeringPolicy /> <SizeBasedTriggeringPolicy size="250 MB"/> </Policies> <DefaultRolloverStrategy max="20"/></RollingFile>

La configuration ci-dessus se traduira par un ou plusieurs fichiers créés pour chaque jour jusqu’à 250 Mo par fichier avec la date actuelle comme nom de fichier, placés dans des dossiers avec des noms de la forme année-mois.

Choisir des niveaux de journal incorrects

Choisir un niveau de journal inadéquat entraînera l’absence d’événements significatifs ou l’inondation de nombreuses données moins importantes.

En termes simples, choisir le bon niveau de journal pour les différents journaux de votre système est l’une des choses essentielles dont vous avez besoin pour bien comprendre vos journaux.

La plupart des frameworks de journalisation ont un ensemble de niveaux similaires à FATAL, ERROR, WARN, INFO, DEBUG, TRACE, classés du plus haut au plus bas.

Niveaux de journal disponibles

Examinons chacun de ces messages et le type de messages de journal qu’ils doivent contenir en fonction de leur gravité:

  • FATAL doit être réservé aux erreurs qui provoquent le plantage ou le démarrage de l’application (ex: L’ERREUR doit contenir des problèmes techniques qui doivent être résolus pour le bon fonctionnement du système (ex: impossible de se connecter à la base de données)
  • WARN est mieux utilisé pour les problèmes temporaires ou les comportements inattendus qui n’entravent pas de manière significative le fonctionnement de l’application (ex: échec de la connexion utilisateur)
  • INFO doit contenir des messages décrivant ce qui se passe dans l’application (ex: utilisateur enregistré, commande passée)
  • DEBUG est destiné aux messages qui pourraient être utiles pour déboguer un problème (ex: exécution de la méthode démarrée)
  • TRACE est similaire à DEBUG mais contient des événements plus détaillés (ex: modèle de données mis à jour)

Contrôle des niveaux de journal

Le niveau de journal d’un message est défini lorsqu’il est écrit:

logger.info("Order ID:" + order.getId() + " placed.");

Les API de journalisation vous permettent généralement de définir le niveau auquel vous souhaitez voir les messages. Cela signifie que, si vous définissez le niveau de journal de l’application ou de certaines classes sur INFO, par exemple, vous ne verrez que les messages aux niveaux FATAL, ERROR, WARN et INFO, tandis que les messages de DÉBOGAGE et de SUIVI ne seront pas inclus.

Ceci est utile car vous affichez généralement des messages de DÉBOGAGE ou inférieurs en développement, mais pas en production.

Voici comment vous pouvez définir le niveau de journal pour une classe, un package ou une application entière dans log4j 2, à l’aide d’un log4j2.fichier de propriétés:

loggers=classLogger,packageLoggerlogger.classLogger.name=com.stackify.service.MyServicelogger.classLogger.level=infologger.packageLogger.name=com.stackify.configlogger.packageLogger.level=debug
rootLogger.level=debug

Pour afficher le niveau de journal dans le message, vous pouvez ajouter l’option %p dans log4j2PatternLayout.

Avant de passer à autre chose, gardez à l’esprit que, si aucun des niveaux existants ne convient aux besoins de votre application, vous avez également la possibilité de définir un niveau de journal personnalisé.

Suivi d’une seule opération Sur plusieurs systèmes et journaux

Dans les systèmes distribués avec plusieurs services déployés indépendamment qui travaillent ensemble pour traiter les demandes entrantes, le suivi d’une seule demande sur tous ces systèmes peut être difficile.

Une seule requête touchera très probablement plusieurs de ces services, et si un problème se produit, nous devrons corroborer tous les journaux individuels de ces systèmes pour obtenir une image complète de ce qui s’est passé.

Pour répondre à ce type d’architecture, nous avons maintenant une nouvelle génération d’outils d’aide à la journalisation dans l’écosystème, tels que Zipkin et Spring Cloud Sleuth.

Zipkin trace les requêtes sur les architectures de microservices pour vous aider à identifier l’application à l’origine du problème. Il est également livré avec une interface utilisateur utile où vous pouvez filtrer les traces en fonction de l’application, de la longueur de la trace ou de l’horodatage.

Et le projet Spring Cloud Sleuth fonctionne en ajoutant un identifiant unique de 64 bits à chaque trace ; une requête Web, par exemple, peut constituer une trace. De cette façon, la demande peut être identifiée sur plusieurs services.

Ces outils répondent aux limites des bibliothèques de base et vous permettent de naviguer dans les nouvelles réalités du style d’architectures plus distribué.

Ne pas se connecter avec JSON

Bien que la journalisation au format texte en clair soit très courante, l’avènement des systèmes de stockage de journaux et d’analyse de données a déplacé cela vers JSON.

JSON en tant que format de journal d’application principal a l’avantage d’être tout aussi lisible que du texte brut, tout en étant beaucoup plus facile à analyser par des outils de traitement automatisés.

Par exemple, Log4j 2 propose le JSONLayout à cette fin exacte:

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

Cela produira un document JSON bien formé:

En tant que JSON, les données de journal seront sémantiquement plus riches lorsqu’elles seront traitées par un système de gestion de journal tel que Retrace – ce qui permettra immédiatement ses puissantes capacités de journalisation structurée / sémantique.

Impact de la journalisation sur les performances

Enfin, considérons un problème inévitable lors de l’ajout de la journalisation à une application : l’impact sur les performances.

Une légère baisse des performances est à prévoir. Cependant, il est important de suivre cela afin de pouvoir le minimiser et ne pas ralentir le système.

Certains aspects liés aux performances à prendre en compte lors du choix d’une API de journalisation sont:

  • Opérations d’E / S de fichiers utilisant un tampon – ceci est essentiel car les E / S de fichiers sont une opération coûteuse
  • Journalisation asynchrone – cela doit être pris en compte pour que la journalisation ne bloque pas les autres processus d’application
  • Temps de réponse de journalisation – le temps nécessaire pour écrire une entrée de journal et renvoyer
  • Nombre de threads utilisés pour la journalisation
  • Filtrage de niveau de journal – ceci est fait pour vérifier si le niveau de journal correspondant à un message est activé, et peut être fait en parcourant la hiérarchie ou en faisant pointer l’enregistreur directement vers la configuration de l’enregistreur; cette dernière approche est préférable en ce qui concerne les performances

Bien sûr, si vous devez garder le choix ouvert et le système flexible, vous pouvez toujours utiliser une abstraction de niveau supérieur telle que slf4j.

Avant d’en déplacer un, voici quelques étapes à suivre pour améliorer les performances de journalisation de votre système:

  • réglez le niveau de journal de l’application pour les paquets détaillés
  • évitez de consigner les informations d’emplacement de la source au moment de l’exécution, car la recherche du thread, du fichier, d’une méthode en cours est une opération coûteuse
  • évitez les erreurs de journalisation avec de longues traces de pile
  • vérifiez si un niveau de journal spécifique est activé avant d’écrire un message avec ce niveau – de cette façon, le message ne sera pas construit s’il n’est pas nécessaire
  • examinez les journaux avant de passer en production pour vérifier si une journalisation peut être supprimée

Mentions honorables

Avant de conclure, passons en revue les journaux jetez un coup d’œil à une dernière pratique que vous devriez éviter – et qui consiste à utiliser standard out au lieu de vous connecter.

Tandis que le système.out() peut être un moyen rapide de commencer très tôt dans le cycle de développement, ce n’est certainement pas une bonne pratique à suivre après ce point.

Outre le fait que vous perdez toutes les fonctionnalités puissantes d’une API de journalisation dédiée, ce principal inconvénient ici est simplement le fait que les données de journalisation ne seront persistées nulle part.

Enfin, une autre mention honorable est une pratique qui peut faciliter la lecture et l’analyse des données de journal – des messages de journal standardisés. En termes simples, des événements similaires devraient avoir des messages similaires dans le journal.

Si vous devez rechercher toutes les instances de cet événement particulier ou extraire des informations significatives de vos données de journal, les messages de journal standard sont très importants.

Par exemple, si une opération de téléchargement échoue– avoir ces différents messages dans le journal serait source de confusion:

Could not upload file picture.jpg
File upload picture.jpg failed.

Au lieu de cela, chaque fois que le téléchargement du fichier échoue, vous devez systématiquement utiliser l’un de ces messages pour enregistrer l’échec.

Conclusion

L’utilisation de la journalisation est devenue omniprésente dans le développement d’applications, en raison des informations très utiles et exploitables qu’elle apporte à l’exécution du système.

Cependant, pour tirer le meilleur parti de vos données de journal, il est important d’aller au-delà des bases, de développer une culture de journalisation et de comprendre les points les plus fins de l’exploitation de ces données à grande échelle et en production.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.