NLog: règles et filtres

NLog: règles et filtres


Chez Confirmit, nous utilisons la bibliothèque NLog pour nous connecter à nos applications .NET. Bien qu'il existe de la documentation pour cette bibliothèque, il m'a été difficile de comprendre comment tout cela fonctionne. Dans cet article, je vais essayer d'expliquer comment les règles et les filtres sont appliqués dans NLog. Commençons.


Comment configurer NLog


Et nous commencerons par un petit rappel de ce que nous pouvons faire avec la configuration NLog. Dans le cas le plus simple, cette configuration est un fichier XML (par exemple, NLog.config):


<?xml version="1.0" encoding="utf-8" ?> <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <targets> <target name="target1" xsi:type="ColoredConsole" layout="Access Log|${level:uppercase=true}|${logger}|${message}"> <highlight-row condition="true" foregroundColor="red"/> </target> <target name="target2" xsi:type="ColoredConsole" layout="Common Log|${level:uppercase=true}|${logger}|${message}"> <highlight-row condition="true" foregroundColor="green"/> </target> <target name="target3" xsi:type="ColoredConsole" layout="Yellow Log|${level:uppercase=true}|${logger}|${message}"> <highlight-row condition="true" foregroundColor="yellow"/> </target> </targets> <rules> <logger name="*" minlevel="Warn" writeTo="target1,target2,target3" /> </rules> </nlog> 

Vous pouvez télécharger ce fichier avec une ligne de code:


 LogManager.Configuration = new XmlLoggingConfiguration("NLog.config"); 

Que pouvons-nous en faire? Nous pouvons définir plusieurs destinataires de messages (cible) selon la règle:


 <rules> <logger name="*" minlevel="Warn" writeTo="target1,target2,target3" /> </rules> 

Nous pouvons déterminer pour quels niveaux de journalisation cette règle est appliquée:


 <rules> <logger name="*" minlevel="Warn" writeTo="target1" /> <logger name="*" levels="Debug,Warn,Info" writeTo="target2" /> </rules> 

Nous pouvons définir des filtres pour chaque règle:


 <rules> <logger name="*" minlevel="Info" writeTo="target1"> <filters defaultAction='Log'> <when condition="contains('${message}','Common')" action="Ignore" /> </filters> </logger> </rules> 

Et enfin, nous pouvons définir des règles imbriquées:


 <rules> <logger name="*" minlevel="Info" writeTo="target1"> <logger name="*" minlevel="Warn" writeTo="target2" /> </logger> </rules> 

Il est temps de découvrir comment tout cela fonctionne.


Création d'une configuration d'enregistreur


Lorsque vous demandez une instance d'enregistreur,


 var commonLogger = LogManager.GetLogger("Common"); 

NLog en prend un existant dans le cache ou en crée un nouveau (voir ici ). Dans ce dernier cas, une configuration est également créée pour l'enregistreur avec le nom donné. Regardons le processus de création.


En bref, la configuration de l'enregistreur est une chaîne distincte de récepteurs et de filtres correspondants pour chaque niveau d'enregistrement ( Trace , Debug , Info , Warn , Error , Fatal ) (voir ici ). Je vais maintenant vous montrer comment ces chaînes sont construites.


La principale méthode responsable de la création de ces chaînes est GetTargetsByLevelForLogger de la classe LogFactory . Voilà comment ça marche. Toutes les règles spécifiées dans la configuration NLog sont sélectionnées tour à tour. Tout d'abord, il vérifie si le nom de la règle correspond au nom de l'enregistreur. Les noms de règles peuvent contenir des caractères génériques, tels que ceux que nous utilisons pour les objets du système de fichiers:


  • * - une séquence arbitraire de caractères
  • ? - n'importe quel caractère

Ainsi, le nom de règle « * » correspond à n'importe quel nom d'enregistreur et « Common* » correspond à tous les enregistreurs dont les noms commencent par « Common ».


Si le nom de la règle ne correspond pas au nom de l'enregistreur, cette règle est supprimée avec toutes les règles intégrées. Sinon, la méthode GetTargetsByLevelForLogger obtient tous les niveaux de journalisation pour lesquels cette règle est activée. Pour chacun de ces niveaux, NLog ajoute tous les récepteurs de messages spécifiés dans la règle aux chaînes de récepteurs correspondantes ainsi que des filtres pour cette règle.


Il existe une autre caractéristique importante dans la construction de chaînes réceptrices. Si la règle actuelle est marquée comme final et que son nom correspond au nom de l'enregistreur, alors NLog termine la construction des chaînes pour tous les niveaux de journalisation inclus pour cette règle. Cela signifie que ni les règles imbriquées ni les règles ultérieures n'ajoutent quoi que ce soit à ces chaînes réceptrices. Leur création est entièrement terminée et ils ne changeront pas. Il s'ensuit que cela n'a pas de sens d'écrire quelque chose comme ceci:


 <rules> <logger name="*" minlevel="Info" writeTo="target1" final="true"> <logger name="*" minlevel="Warn" writeTo="target2" /> </logger> </rules> 

Aucun message n'atteindra target2 . Mais il est possible d'écrire quelque chose comme ceci:


 <rules> <logger name="*" minlevel="Warn" writeTo="target1" final="true"> <logger name="*" minlevel="Info" writeTo="target2" /> </logger> </rules> 

Étant donné que la règle externe n'est pas activée pour le niveau Info , la chaîne de récepteurs pour ce niveau ne se terminera pas sur la règle externe. Par conséquent, tous les messages avec le niveau Info tomberont dans target2 .


Une fois tous les récepteurs de cette règle ajoutés aux chaînes correspondantes, la méthode traite récursivement toutes les règles imbriquées de la règle actuelle selon le même algorithme. Cela se produit quels que soient les niveaux de journalisation activés pour la règle parent.


Au total, la configuration de l'enregistreur est prête. Il contient des chaînes de récepteurs avec des filtres pour chaque niveau d'enregistrement possible:


Chaîne de réception


Il est temps de voir comment cette configuration est utilisée.


Utilisation de la configuration de l'enregistreur


Commençons par des choses simples. La classe Logger possède une méthode IsEnabled et les propriétés IsXXXEnabled associées ( IsDebugEnabled , IsInfoEnabled , ...). Comment fonctionnent-ils? En fait, ils vérifient simplement si les chaînes réceptrices pour un niveau de journalisation donné contiennent au moins un lien (voir ici ). Cela signifie que les filtres n'affectent jamais les valeurs de ces propriétés.


Ensuite, laissez-moi vous expliquer ce qui se passe lorsque vous essayez de sécuriser un message. Comme vous l'avez peut-être deviné, l'enregistreur prend une chaîne de récepteurs pour le niveau d'enregistrement de ce message. Puis il commence à traiter les maillons de cette chaîne l'un après l'autre. Pour chaque lien, l'enregistreur décide s'il faut écrire le message au destinataire spécifié dans le lien et s'il doit continuer à traiter la chaîne par la suite. Ces décisions sont prises à l'aide de filtres. Permettez-moi de vous montrer comment fonctionnent les filtres dans NLog.


Voici comment les filtres sont configurés:


 <rules> <logger name="*" minlevel="Info" writeTo="target1"> <filters defaultAction='Log'> <when condition="contains('${message}','Common')" action="Ignore" /> </filters> </logger> </rules> 

Habituellement, un filtre contient une condition booléenne. Ici, vous pouvez décider si le filtre renvoie true ou false pour chaque message. Mais ce n'est pas le cas. Le résultat de leur travail est une valeur de type FilterResult . Si la condition de filtre renvoie true , le résultat du filtre devient la valeur spécifiée dans l'attribut action (dans notre exemple, il s'agit de Ignore ). Si la condition retourne false , le résultat du filtre sera Neutral . Cela signifie que le filtre ne veut pas décider quoi faire avec le message.


Vous pouvez voir comment la chaîne de réception est traitée ici . Pour chaque récepteur, le résultat des filtres correspondants dans la méthode GetFilterResult est GetFilterResult . Il est égal au résultat du premier filtre qui est retourné non Neutral . Cela signifie que si certains filtres renvoient une valeur autre que Neutral , tous les filtres suivants ne sont pas exécutés.


Mais que se passe-t-il si tous les filtres renvoient Neutral ? Dans ce cas, la valeur par défaut sera utilisée. Cette valeur est définie à l'aide de l'attribut defaultAction de l'élément filters pour la règle. defaultAction vous, quelle est la valeur par défaut de defaultAction ? Vous avez raison si vous pensez que c'est Neutral . C'est-à-dire que la chaîne de filtres entière peut retourner Neutral en conséquence. Dans ce cas, NLog se comporte de la même manière que la réception du Log . Le message sera écrit au destinataire (voir ici ).


Comme vous l'avez peut-être deviné, si un filtre renvoie Ignore ou IgnoreFinal , le message ne sera pas écrit sur le récepteur. Si le résultat du filtre est Log ou LogFinal , le message sera enregistré. Mais quelle est la différence entre Ignore et IgnoreFinal et entre Log ou LogFinal ? C'est simple. Dans le cas d' IgnoreFinal et LogFinal NLog arrête de traiter la chaîne de réception et n'écrit rien sur les récepteurs contenus dans les liens suivants.


Conclusion


L'analyse du code NLog m'a aidé à comprendre le fonctionnement des règles et des filtres. J'espère que cet article vous sera utile. Bonne chance

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


All Articles