NLog:ルールとフィルター

NLog:ルールとフィルター


Confirmitでは、 .NETアプリケーションへのログインにNLogライブラリを使用します。 このライブラリにはドキュメントがありますが、すべてがどのように機能するかを理解することは困難でした。 この記事では、NLogでルールとフィルターがどのように適用されるかを説明します。 始めましょう。


NLogを構成する方法


そして、NLog構成で何ができるかを少し思い出してみましょう。 最も単純な場合、この構成はXMLファイル(たとえば、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> 

このファイルは、1行のコードでダウンロードできます。


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

それで何ができますか? いくつかのメッセージレシーバー(ターゲット)をルールに設定できます。


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

このルールが適用されるロギングのレベルを決定できます。


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

各ルールにフィルターを設定できます。


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

最後に、ネストされたルールを定義できます。


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

すべてがどのように機能するかを調べる時が来ました。


ロガー構成の作成


ロガーインスタンスをリクエストすると、


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

NLogはキャッシュから既存のものを取得するか、新しいものを作成します( こちらを参照)。 後者の場合、指定された名前のロガーの構成も作成されます。 それを作成するプロセスを見てみましょう。


要するに、ロガー構成は、レシーバーと、各ロギングレベル( TraceDebugInfoWarnErrorFatal )に対応するフィルターの別個のチェーンです( こちらを参照)。 次に、これらのチェーンがどのように構築されるかを示します。


これらのチェーンを作成する主なメソッドは、LogFactoryクラスのGetTargetsByLevelForLoggerです。 これがその仕組みです。 NLog構成で指定されたすべてのルールが順番に選択されます。 まず、ルール名がロガー名と一致するかどうかを確認します。 ルール名には、ファイルシステムオブジェクトに使用するものと同じワイルドカードを含めることができます。



したがって、ルール名「 * 」は任意のロガー名と一致し、「 Common* 」は名前が「 Common 」で始まるすべてのロガーと一致します。


ルール名がロガー名と一致しない場合、このルールは破棄され、すべてのルールが埋め込まれます。 それ以外の場合、 GetTargetsByLevelForLoggerメソッドは、このルールが有効になっているすべてのログレベルを取得します。 そのようなレベルごとに、NLogは、ルールで指定されたすべてのメッセージレシーバーを、このルールのフィルターとともに対応するレシーバーチェーンに追加します。


レシーバーチェーンの構築には別の重要な機能があります。 現在のルールがfinalとしてマークされ、その名前がロガーの名前と一致する場合、NLogはこのルールに含まれるすべてのログレベルのチェーンの構築を完了します。 これは、ネストされたルールも後続のルールもこれらのレシーバーチェーンに何も追加しないことを意味します。 それらの作成は完全に完了し、変更されません。 したがって、次のようなものを書くのは意味がありません。


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

メッセージはtarget2に到達しません。 しかし、次のようなものを書くことは可能です。


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

Infoレベルでは外部ルールが有効になっていないため、このレベルの受信者のチェーンは外部ルールで終了しません。 したがって、 Infoレベルのすべてのメッセージはtarget2分類されtarget2


このルールのすべてのレシーバーが対応するチェーンに追加された後、メソッドは同じアルゴリズムに従って現在のルールのすべてのネストされたルールを再帰的に処理します。 これは、親ルールで有効になっているログレベルに関係なく発生します。


合計で、ロガーの構成の準備ができました。 ロギングの可能なレベルごとにフィルターを備えたレシーバーのチェーンが含まれています。


レシーバーチェーン


この構成がどのように使用されるかを見てみましょう。


ロガー構成の使用


簡単なことから始めましょう。 Loggerクラスには、 IsEnabledメソッドと関連プロパティIsXXXEnabledIsDebugEnabledIsInfoEnabled 、...)があります。 彼らはどのように機能しますか? 実際、特定のレベルのロギングのレシーバーチェーンに少なくとも1つのリンクが含まれているかどうかを確認するだけです( こちらを参照)。 これは、フィルターがこれらのプロパティの値に影響を与えないことを意味します。


次に、メッセージを保護しようとするとどうなるかを説明します。 ご想像のとおり、ロガーはこのメッセージのログレベルのレシーバーチェーンを取得します。 その後、彼はこのチェーンのリンクを次々に処理し始めます。 ロガーは、リンクごとに、リンクで指定された受信者にメッセージを書き込むかどうか、およびその後のチェーンの処理を続行するかどうかを決定します。 これらの決定は、フィルターを使用して行われます。 NLogでフィルターがどのように機能するかを説明します。


フィルターの設定方法は次のとおりです。


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

通常、フィルターにはブール条件が含まれます。 ここで、フィルターが各メッセージに対してtrueまたはfalseを返すかどうかを決定できます。 しかし、これはそうではありません。 彼らの仕事の結果はFilterResult型の値です。 フィルター条件がtrue返す場合、フィルターの結果はaction属性で指定された値になります(この例では、これはIgnore )。 条件がfalse返す場合、フィルターの結果はNeutralます。 これは、フィルターがメッセージの処理方法を決定したくないことを意味します。


ここで 、レシーバーチェーンの処理方法を確認できます 。 各レシーバーについて、 GetFilterResultメソッドの対応するフィルターの結果がGetFilterResultます。 これは、非Neutralを返した最初のフィルターの結果と等しくなります。 つまり、一部のフィルターがNeutral以外の値を返す場合、後続のフィルターはすべて実行されません。


しかし、すべてのフィルターがNeutral返すとどうなりますか? この場合、デフォルト値が使用されます。 この値は、ルールのfiltersエレメントのdefaultAction属性を使用して設定されます。 defaultActionのデフォルト値は何だと思いますか? これがNeutralだと思うなら、あなたは正しい。 つまり、結果としてフィルターチェーン全体がNeutralを返すことができます。 この場合、NLogはLogを受け取るのと同じように動作します。 メッセージは受信者に書き込まれます( こちらを参照)。


IgnoreFinal 、フィルターがIgnoreまたはIgnoreFinal返す場合、メッセージはレシーバーに書き込まれません。 フィルターの結果がLogまたはLogFinal場合、メッセージが記録されます。 しかし、 IgnoreIgnoreFinalLogまたはLogFinal何ですか? 簡単です。 IgnoreFinalおよびLogFinal場合、 IgnoreFinalはレシーバーのチェーンの処理を停止し、後続のリンクに含まれるレシーバーには何も書き込みません。


おわりに


NLogコードを分析することで、ルールとフィルターの仕組みを理解することができました。 この記事があなたにも役立つことを願っています。 頑張って



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


All Articles