Enregistreur de bobines Slf4j alternatif

Salutations, chers amis!

Je veux partager mes réflexions sur le sujet de l'exploitation forestière et ce à quoi elles ont conduit.

Peut-être en raison d'un manque de recherche théorique, l'exploitation forestière a toujours été une zone de turbulence dans le monde Java. Au fil du temps, cela a provoqué l'émergence de plusieurs bibliothèques de journalisation, telles que:

  • Log4j
  • Journalisation de Java Util
  • Journalisation de Commons
  • Déconnexion
  • Log4j2

En essayant de réduire le reste du reste, malheureusement, chacun d'eux a présenté ses propres lacunes.

Et si du point de vue de la normalisation du code, la situation s'est améliorée après l'apparition de Slf4j - en tant que couche d'abstraction pour la journalisation, des problèmes non résolus sont toujours présents dans les implémentations existantes.

En tant que communauté Open Source, nous prenons l'initiative de proposer une nouvelle approche révolutionnaire - et de créer un enregistreur léger (mais en même temps riche en fonctionnalités), en utilisant les derniers développements, tels que les scripts.

Les problèmes


- Les implémentations existantes ne fournissent qu'une prise en charge partielle des scripts dans les paramètres


Cela conduit à une programmation déclarative dans les fichiers de configuration de l'enregistreur (XML, JSON, YAML), bien qu'il serait beaucoup plus simple d'interpréter dynamiquement les valeurs de configuration lors de l'exécution à l'aide de scripts impératifs.

Prenons un exemple de configuration de filtre dans Logback, pour enregistrer uniquement les messages avec le niveau de journalisation INFO:

<filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> 

Il s'agit d'un exemple typique de programmation XML déclarative.

(oui, Logback prend en charge un filtre utilisant Groovy, mais il ne s'applique qu'à des ajouts spécifiques, pas à l'enregistreur)

Mais le support de script pour formater la chaîne est complètement manquant.

- Configuration compliquée et trop longue


Prenez Logback et Log4j2:

Il n'y a aucun moyen de configurer le niveau de journalisation pour un appender spécifique.

Les appendeurs sont configurés séparément des enregistreurs et les enregistreurs font référence aux appendeurs à l'aide de l'attribut «AppenderRef» - ​​tandis que seuls les enregistreurs prennent en charge la définition du niveau de journalisation et des noms de classe.

Supposons que nous devons exclure les messages de débogage d'une classe Foo d'un fichier journal spécifique sans affecter les autres fichiers journaux et classes.

Dans Logback, cela est possible en utilisant le filtre Groovy Script sur l'appender - mais si nous avons de nombreux appenders, la taille de la configuration augmente de façon exponentielle.

- À chaque niveau de journalisation - un fichier séparé!


Nous n'avons pas pu trouver la possibilité d'un tel paramètre dans lequel les messages sont regroupés dans des fichiers par niveau de message (débogage, info, etc.)

Les fonctionnalités existantes nécessitent la duplication d'appendants à chaque niveau de journalisation.

- Définition du filtrage par nom de classe dans l'enregistreur racine lui-même


L'enregistreur racine prend en charge la définition uniquement du niveau de journalisation, mais il n'y a aucune possibilité de contrôle centralisé des classes à enregistrer.

- Il existe une déconnexion conceptuelle entre la façon dont les données de journal sont générées dans l'application et la façon dont ces données sont consommées par l'enregistreur.


La pratique historique est telle que les enregistreurs (et leur configuration) sont plus centrés sur la classe que s'ils étaient centrés sur les fichiers.

Cela contredit la perception humaine, qui perçoit plus logiquement les attentes concernant le contenu final des fichiers journaux, plutôt que de se soucier de la configuration de chaque classe individuelle.

En pratique, ce paradoxe est à l'origine des limitations fonctionnelles des implémentations existantes:

  • Configuration de nom de fichier compliquée
  • Configuration irrationnelle de l'enregistreur, par exemple:

Logback prend en charge un maximum de 1 «discriminateur» dans «SiftingAppender».
SiftingAppender a des limites dans les paramètres de stratégie pour l'archivage
Redessiné RoutingAppender dans Log4j2

Solution


- Prise en charge complète des scripts dans la configuration


Bobbin utilise la configuration comme localisateur pour les scripts Groovy qui déterminent le comportement de l'enregistreur lors de l'exécution de l'application.

Voici à quoi ressemble l'exemple du «filtre»:

 { "levels": "['info'].contains(level)" } 

Chaque aspect de l'enregistreur prend en charge la personnalisation à l'aide de scripts:

  • Niveaux de journalisation
  • Noms de classe
  • Format du message
  • Noms de fichiers

- Configuration simple et concise


La canette ne nécessite pas d'encodeurs, de modèles, de filtres, de discriminateurs et de nombreuses autres choses inutiles.

Il est configuré avec seulement quelques paramètres de base:

  • Niveaux
  • Cours
  • Fichiers
  • Format de ligne

Fichiers séparés pour chaque niveau de journalisation: il suffit de mettre "$ {level}" dans le masque de nom de fichier dans Bobbin.json (fichier de configuration).

Exemple de fichier de configuration:

 { "levels": "['debug', 'info', 'warn', 'error'].contains(level)", "destinations": [ { "name": "io.infinite.bobbin.destinations.FileDestination", "properties": { "fileName": "\"./LOGS/PLUGINS/INPUT/${className}/${level}/${className}_${level}.log\"" }, "classes": "className.contains('conf.plugins.input')" }, { "name": "io.infinite.bobbin.destinations.FileDestination", "properties": { "fileName": "\"./LOGS/PLUGINS/OUTPUT/${className}/${level}/${threadName}_${level}_${date}.log\"" }, "classes": "className.contains('conf.plugins.output')" }, { "name": "io.infinite.bobbin.destinations.FileDestination", "properties": { "fileName": "\"./LOGS/THREADS/${threadGroupName}/${threadName}/${level}/${threadName}_${level}_${date}.log\"" }, "classes": "className.contains('io.infinite.')" }, { "name": "io.infinite.bobbin.destinations.FileDestination", "properties": { "fileName": "\"./LOGS/ALL/WARNINGS_AND_ERRORS_${date}.log\"" }, "levels": "['warn', 'error'].contains(level)" }, { "name": "io.infinite.bobbin.destinations.ConsoleDestination", "levels": "['warn', 'error'].contains(level)" } ] } 

Essayez Bobbin maintenant:

 Gradle: compile "io.infinite:bobbin:2.0.0" 

* Bobbin est un projet Open Source sous licence Apache.

Source: https://habr.com/ru/post/fr442232/


All Articles