NLog:规则和过滤器
在Confirmit,我们使用NLog库登录.NET应用程序。 尽管存在该库的文档,但让我很难理解它们的全部工作原理。 在本文中,我将尝试解释如何在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>
您可以使用一行代码下载此文件:
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从缓存中获取一个现有的日志,或创建一个新的日志(请参阅此处 )。 在后一种情况下,还将使用给定名称为记录器创建配置。 让我们看一下创建它的过程。
简而言之,记录器配置是每个记录级别( Trace
, Debug
, Info
, Warn
, Error
, Fatal
)的接收器和相应过滤器的单独链(请参见此处 )。 现在,我将向您展示如何构建这些链。
负责创建这些链的主要方法是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
。
将来自该规则的所有接收者添加到相应的链中之后,该方法将根据同一算法递归处理当前规则的所有嵌套规则。 无论为父规则启用的日志记录级别如何,都会发生这种情况。
总体而言,记录器的配置已准备就绪。 它包含带有筛选器的接收器链,用于每个可能的日志记录级别:

现在该看看如何使用此配置。
使用记录器配置
让我们从简单的事情开始。 Logger
类具有IsEnabled
方法和关联的IsXXXEnabled
属性( IsDebugEnabled
, IsInfoEnabled
等)。 它们如何工作? 实际上,它们只是检查给定日志级别的接收器链是否包含至少一个链接(请参阅此处 )。 这意味着过滤器永远不会影响这些属性的值。
接下来,让我解释一下您尝试保护邮件时会发生什么。 您可能已经猜到了,记录器采用一连串的接收者作为该消息的记录级别。 然后他开始一个接一个地处理该链的链接。 对于每个链接,记录器决定是否将消息写入链接中指定的接收者,并在此之后是否继续处理该链。 这些决定是使用过滤器做出的。 让我向您展示过滤器如何在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
方法中相应过滤器的结果。 它等于第一个未返回Neutral
过滤器的结果。 这意味着,如果某些过滤器返回的值不是Neutral
,则不会执行所有后续过滤器。
但是,如果所有过滤器都返回“ Neutral
怎么办? 在这种情况下,将使用默认值。 该值是使用规则的filters
元素的defaultAction
属性设置的。 您认为defaultAction
的默认值是什么? 如果您认为这是Neutral
您是对的。 也就是说,整个过滤链可以因此返回“ Neutral
。 在这种情况下,NLog的行为与接收Log
行为相同。 该消息将被写到接收者(请参阅此处 )。
您可能已经猜到了,如果过滤器返回Ignore
或IgnoreFinal
,则消息将不会被写入接收者。 如果筛选结果为Log
或LogFinal
,则将记录该消息。 但是, Ignore
和IgnoreFinal
与Log
或LogFinal
之间有什么区别? 很简单 对于IgnoreFinal
和LogFinal
NLog停止处理接收器链,并且不向后续链接中包含的接收器写入任何内容。
结论
分析NLog代码有助于我理解规则和过滤器的工作方式。 希望本文对您有所帮助。 祝你好运