NLog: Regeln und Filter

NLog: Regeln und Filter


Bei Confirmit verwenden wir die NLog- Bibliothek zum Anmelden in unseren .NET-Anwendungen. Obwohl für diese Bibliothek Dokumentation vorhanden ist, war es für mich schwierig zu verstehen, wie alles funktioniert. In diesem Artikel werde ich versuchen zu erklären, wie Regeln und Filter in NLog angewendet werden. Fangen wir an.


So konfigurieren Sie NLog


Und wir beginnen mit einer kleinen Erinnerung daran, was wir mit der NLog-Konfiguration tun können. Im einfachsten Fall handelt es sich bei dieser Konfiguration um eine XML-Datei (z. B. 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> 

Sie können diese Datei mit einer Codezeile herunterladen:


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

Was können wir damit machen? Wir können mehrere Nachrichtenempfänger (Ziel) auf die Regel setzen:


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

Wir können bestimmen, für welche Protokollierungsstufen diese Regel angewendet wird:


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

Wir können Filter für jede Regel festlegen:


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

Und schließlich können wir verschachtelte Regeln definieren:


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

Es ist Zeit herauszufinden, wie das alles funktioniert.


Erstellen einer Logger-Konfiguration


Wenn Sie eine Logger-Instanz anfordern,


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

NLog nimmt entweder eine vorhandene aus dem Cache oder erstellt eine neue (siehe hier ). Im letzteren Fall wird auch eine Konfiguration für den Logger mit dem angegebenen Namen erstellt. Schauen wir uns den Prozess der Erstellung an.


Kurz gesagt, die Logger-Konfiguration besteht aus einer separaten Kette von Empfängern und entsprechenden Filtern für jede Protokollierungsstufe ( Trace , Debug , Info , Warn , Error , Fatal ) (siehe hier ). Jetzt werde ich Ihnen zeigen, wie diese Ketten aufgebaut sind.


Die Hauptmethode zum Erstellen dieser Ketten ist GetTargetsByLevelForLogger der LogFactory- Klasse. So funktioniert es. Alle in der NLog-Konfiguration angegebenen Regeln werden nacheinander ausgewählt. Zunächst wird überprüft, ob der Regelname mit dem Loggernamen übereinstimmt. Regelnamen können Platzhalter enthalten, z. B. solche, die wir für Dateisystemobjekte verwenden:


  • * - eine beliebige Folge von Zeichen
  • ? - ein einzelnes Zeichen

Daher stimmt der Regelname ' * ' mit jedem Loggernamen überein, und ' Common* ' stimmt mit allen Loggern überein, deren Namen mit ' Common ' beginnen.


Wenn der Regelname nicht mit dem Loggernamen übereinstimmt, wird diese Regel mit allen darin eingebetteten Regeln verworfen. Andernfalls GetTargetsByLevelForLogger die GetTargetsByLevelForLogger Methode alle Protokollierungsstufen ab, für die diese Regel aktiviert ist. Für jede dieser Ebenen fügt NLog alle in der Regel angegebenen Nachrichtenempfänger zusammen mit Filtern für diese Regel zu den entsprechenden Empfängerketten hinzu.


Es gibt ein weiteres wichtiges Merkmal beim Aufbau von Empfängerketten. Wenn die aktuelle Regel als final markiert ist und ihr Name mit dem Namen des Protokollierers übereinstimmt, schließt NLog die Erstellung von Ketten für alle für diese Regel enthaltenen Protokollierungsstufen ab. Dies bedeutet, dass weder die verschachtelten Regeln noch nachfolgende Regeln diesen Empfängerketten etwas hinzufügen. Ihre Erstellung ist vollständig abgeschlossen und sie werden sich nicht ändern. Daraus folgt, dass es keinen Sinn macht, so etwas zu schreiben:


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

Keine Nachrichten erreichen target2 . Aber es ist möglich, so etwas zu schreiben:


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

Da die externe Regel für die Info Ebene nicht aktiviert ist, endet die Empfängerkette für diese Ebene nicht mit der externen Regel. Daher fallen alle Nachrichten mit der Info Ebene in target2 .


Nachdem alle Empfänger dieser Regel zu den entsprechenden Ketten hinzugefügt wurden, verarbeitet das Verfahren alle verschachtelten Regeln der aktuellen Regel rekursiv nach demselben Algorithmus. Dies geschieht unabhängig von den für die übergeordnete Regel aktivierten Protokollierungsstufen.


Insgesamt ist die Konfiguration für den Logger fertig. Es enthält Empfängerketten mit Filtern für jede mögliche Protokollierungsstufe:


Empfängerkette


Es ist Zeit zu sehen, wie diese Konfiguration verwendet wird.


Verwenden der Logger-Konfiguration


Beginnen wir mit einfachen Dingen. Die Logger Klasse verfügt über eine IsEnabled Methode und zugehörige IsXXXEnabled Eigenschaften ( IsDebugEnabled , IsInfoEnabled , ...). Wie arbeiten sie? Tatsächlich prüfen sie einfach, ob die Empfängerketten für eine bestimmte Protokollierungsstufe mindestens ein Glied enthalten (siehe hier ). Dies bedeutet, dass Filter niemals die Werte dieser Eigenschaften beeinflussen.


Lassen Sie mich als Nächstes erklären, was passiert, wenn Sie versuchen, eine Nachricht zu sichern. Wie Sie vielleicht vermutet haben, nimmt der Logger eine Empfängerkette für die Protokollierungsstufe dieser Nachricht. Dann beginnt er, die Glieder dieser Kette nacheinander zu verarbeiten. Für jede Verbindung entscheidet der Logger, ob die Nachricht an den in der Verbindung angegebenen Empfänger geschrieben werden soll und ob die Kette danach weiter verarbeitet werden soll. Diese Entscheidungen werden mithilfe von Filtern getroffen. Lassen Sie mich Ihnen zeigen, wie Filter in NLog funktionieren.


So werden die Filter konfiguriert:


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

Normalerweise enthält ein Filter eine boolesche Bedingung. Hier können Sie entscheiden, ob der Filter für jede Nachricht true oder false zurückgibt. Aber das ist nicht so. Das Ergebnis ihrer Arbeit ist ein Wert vom Typ FilterResult . Wenn die Filterbedingung true zurückgibt, wird das Ergebnis des Filters zu dem im action angegebenen Wert (in unserem Beispiel ist dies Ignore ). Wenn die Bedingung false zurückgibt, ist das Ergebnis des Filters Neutral . Dies bedeutet, dass der Filter nicht entscheiden möchte, was mit der Nachricht geschehen soll.


Hier können Sie sehen, wie die Empfängerkette verarbeitet wird. Für jeden Empfänger wird das Ergebnis der entsprechenden Filter in der GetFilterResult Methode GetFilterResult . Dies entspricht dem Ergebnis des ersten Filters, der nicht Neutral . Dies bedeutet, dass nicht alle nachfolgenden Filter ausgeführt werden, wenn ein Filter einen anderen Wert als Neutral zurückgibt.


Aber was passiert, wenn alle Filter Neutral ? In diesem Fall wird der Standardwert verwendet. Dieser Wert wird mithilfe des defaultAction Attributs des defaultAction für die Regel festgelegt. Was ist Ihrer Meinung nach der Standardwert für defaultAction ? Sie haben Recht, wenn Sie denken, dass dies Neutral . Das heißt, die gesamte Filterkette kann dadurch Neutral . In diesem Fall verhält sich NLog genauso wie das Empfangen von Log . Die Nachricht wird an den Empfänger geschrieben (siehe hier ).


Wie Sie vielleicht vermutet haben, wird die Nachricht nicht in den Empfänger geschrieben, wenn ein Filter Ignore oder IgnoreFinal zurückgibt. Wenn das Ergebnis des Filters Log oder LogFinal , wird die Nachricht aufgezeichnet. Aber was ist der Unterschied zwischen Ignore und IgnoreFinal und zwischen Log oder LogFinal ? Das ist einfach. Im Fall von IgnoreFinal und LogFinal NLog die Verarbeitung der Empfängerkette und schreibt nichts in die in den nachfolgenden Links enthaltenen Empfänger.


Fazit


Durch die Analyse des NLog-Codes konnte ich besser verstehen, wie Regeln und Filter funktionieren. Ich hoffe, dieser Artikel wird Ihnen nützlich sein. Viel Glück

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


All Articles