NLog支持以多种不同方式配置,目前同时支持直接编程和使用配置文件两种方法。本文将对目前支持的各种配置方式作详细描述。
日志配置
通过在启动的时候对一些常用目录的扫描,NLog会尝试使用找到的配置信息进行自动的自我配置。当你运行一个独立的*.exe客户端可执行程序时,NLog将在以下目录搜索配置信息:
如果是一个ASP.NET程序,被搜索的目录包括:
由于.NET Compact Framework不支持程序配置文件(*.exe.config)和环境变量,因此NLog将只会扫描这些地方:
配置文件格式
NLog支持两种配置文件格式
如果你选择了第一种方式,使用的是标准的configSections这种机制,那么你的配置文件看起来差不多是这个样子:
<configuration>
<configSections>
<section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/>
</configSections>
<nlog>
</nlog>
</configuration>
单一格式的配置文件就是一个以<nlog />为根节点的纯XMl文件。命名空间并不强制使用,如果使用的话我们就可以利用Visual Studio的智能感应。
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
</nlog>
需要注意的是NLog的配置文件总是大小写敏感的,不管是在使用的时候,或者即使你没有使用名字空间。当然只有你的大小写符合要求,智能感应才能正常工作。
配置元素
下面这些元素可以作为<nlog />的字节点。列表中的前两个元素在所有的NLog配置文件中都必须提供,其余的则可以选择使用,通常用于一些复杂场景。
输出目标
<target />区域定义了日志的目标或者说输出。每一个<target />元素代表一个目标。我们需要为每一个目标设置两个属性:
除了这两个属性,通常来说给目标添加一些其它参数,这些属性将会影响你在程序中如何使用诊断跟踪语句(diagnostic traces)。每一个目标都可以有一组不同的参数集合,并且参数都是上下文相关的,你可以在本项目的主页上找到更多关于参数的详细说明。Visual Studio的智能感应对这些参数同样有用。
举个例子 - “File”目标可以使用“fileName”作为参数来定义输出文件名,而“Console”目标可以借助“error”参数的值来判断是否应该把当前进程的diagnostic traces结果输出到标准错误(stderr)还是标准输出(stdout)控制台。
下面这个例子演示了在<targets />区域同时定义多个目标:两个files目标,一个network目标和一个OutputDebugString目标:
<targets>
<target name="f1" xsi:type="File" fileName="file1.txt"/>
<target name="f2" xsi:type="File" fileName="file2.txt"/>
<target name="n1" xsi:type="Network" address="tcp://localhost:4001"/>
<target name="ds" xsi:type="OutputDebugString"/>
</targets>
NLog提供了许多已经预先定义好的目标。关于这些目标的详细说明请参考本项目的主页。实际上,你也可以很容易的为自己创建目标 - 全部只需大约15-20行代码即可,更多信息请参考项目文档。
路由规则
<rules />区域定义了日志的路由规则。实际上它是一个简单的路由表,对每一个日志源/记录者的名称和记录等级的组合,定义了一个日志写入目标列表。 表中的规则是被顺序处理的。每当遇到匹配的规则时,日志信息就会被送到规则中定义的一个或多个目标去。如果一个规则被标识为最后一个,那么其后的规则都不会被执行。
每一个路由表项就是一个<logger />元素,它的可以接受的属性有:
一些例子:
最简单的情况下,整个日志的配置信息可以只由一个<target />元素和一个<logger />规则构成,就可以吧一定级别的日志信息路由到期望的目标去。随着程序不断的变大,增加新的目标和规则也很简单。
上下文信息
NLog最棒的功能之一就是使用布局(layouts)的能力。布局由被一个美元符号$加左大括弧“${”和一个右大括弧“}”为标记所包围的文本所组成。这个标记也就是所谓的“布局生成器(layout renderers),我们可以用它来把一些上下文相关的信息插入到日志信息中。布局可以应用在许多地方,比如可以被用在控制输出到屏幕或写入文件信息的格式,也可以用在控制文件名。接下来我们会更多的了解布局的强大。
假设我们希望每个输出到控制台的信息都包含一些这些信息:
利用Layout来实现很简单:
<target name="c" xsi:type="Console"
layout="${longdate} ${callsite} ${level} ${message}"/>
或者我们可以把每一个日志记录者生成的日志信息输出到一个单独的文件里:
<target name="f" xsi:type="File" fileName="${logger}.txt"/>
这里我们看到fileName属性的值被设置为布局生成器${logger},从而使每一条日志信息被写到一个以日志生成者名字命名的一个文件里。上面这个例子将生成如下一系列文件:
有一个常见需求是能够用日期信息来区分日志文件。如果使用${shortdate}布局生成器,这简直太容易了:
<target name="f" xsi:type="File" fileName="${shortdate}.txt"/>
那么可以给每一个职员生成一个日志文件吗?答案就是${windows-identity}布局生成器:
<target name="f" xsi:type="File" fileName="${windows-identity:domain=false}.txt"/>
这样我们就能够给每一个职员生成一个日志文件了:
更复杂的场景也能做到。下面这个例子说明了如何为每个人每天生成一个日志文件。每天的日志文件存放在不同的文件夹里:
<target name="f" xsi:type="File"
fileName="${shortdate}/${windows-identity:domain=false}.txt"/>
这将创建如下文件:
NLog提供了许多预先定义好的布局生成器。关于它们的说明都在这个页面:http://www.nlog-project.org/layoutrenderers.html。建立你自己的布局生成器也很容易,大概只需要15-20行的代码而已。详细做法请参考项目文档。
包含文件
有时我们希望把配置文件分割为一些比较小的文件。NLog提供了包含文件这一机制来支持这种需求。要包含一个外部文件,你需要做的只是设置fileName这个属性。同时,和其它大多数NLog配置文件的属性一样,fileName也支持用大家都很熟悉的${var}标记引入动态值,这使得我们可以根据环境属性的不同包含不同的文件。在下面这个例子里,我们总是导入基于当前机器名的配置文件。
<nlog>
...
<include file="${basedir}/${machinename}.config"/>
...
</nlog>
变量的使用可以使我们以比较简洁的形式书写复杂或者是重复表达式(如文件名)。定义一个变量的语法是:<variable name="var" value="xxx" />。变量定义好之后,就可以像使用布局生成器一样 – 通过语法${var}来使用了。下面我们来看一个使用变量的例子:
<nlog>
<variable name="logDirectory" value="${basedir}/logs/${shortdate}"/>
<targets>
<target name="file1" xsi:type="File" fileName="${logDirectory}/file1.txt"/>
<target name="file2" xsi:type="File" fileName="${logDirectory}/file2.txt"/>
</targets>
</nlog>
自动再配置
配置文件在程序启动时会被自动读取。然而在一些长时间运行的程序中(比如Windows服务或者ASP.NET程序),有时我们希望能够在不中断程序的前提下临时提高日志的级别。NLog可以一直监视日志配置文件的状态,并在它们被修改后重新读取。要激活这一机制,你只需在你的配置文件中设置<nlog autoReload="true" />。注意自动再配置支持引入文件,所以每次如果一个引入文件被修改了,会引起整个配置信息被重新载入。
日志排错
有时候即使你觉得你已经把日志配置的没有任何问题了,你的程序就是不输出任何日志信息。原因可能有很多,最常见的是权限问题,尤其在ASP.NET程序里,aspnet_wp.exe或者w3wp.exe进程可能没有足够的权限访问存放日志文件的目录。NLog被设计为吃掉任何由于记录日志而带来的运行时异常。而下面这些设置可以改变这种行为并/或者重定向这些信息。
异步处理,封装和复合目标
NLog提供的封装和复合目标可以修改其它目标的行为,这可以增加一些功能如:
定义一个封装或者复合目标,你只需在一个目标节点里嵌套另一个目标节点即可。你甚至可以封装一个封装目标。嵌套的层数没有任何限制。比如,要给你的配置文件加上异步日志记录的功能,同时异步日志记录可以自动重试,你可以这样做:
<targets>
<target name="n" xsi:type="AsyncWrapper">
<target xsi:type="RetryingWrapper">
<target xsi:type="File" fileName="${file}.txt"/>
</target>
</target>
</targets>
因为异步处理使用的非常普遍,NLog专门为异步处理设计了一个简化符号,这样所有需要异步处理的目标都不需要显式的定义封装了。你只要设置<targets async="true" />然后你所有的目标就都具备了异步处理的能力了。
缺省封装
有时我们希望用同一种封装来处理所有的目标,比如说增加缓冲和/或自动重试功能。NLog为此提供了专门的语法:<default-wrapper />。你只要把这个元素放在<targets />区域里,然后所有的目标都会自动加载同一个封装目标。需要注意的是<default-wrapper />只对当前这个<targets />区域有效,而你可以使用多个<targets />区域,这样你就可以把目标分组并用不同的封装目标处理。
<nlog>
<targets>
<default-wrapper xsi:type="BufferingWrapper" bufferSize="100"/>
<target name="f1" xsi:type="File" fileName="f1.txt"/>
<target name="f2" xsi:type="File" fileName="f2.txt"/>
</targets>
<targets>
<default-wrapper xsi:type="AsyncWrapper">
<wrapper xsi:type="RetryingWrapper"/>
</default-wrapper>
<target name="n1" xsi:type="Network" address="tcp://localhost:4001"/>
<target name="n2" xsi:type="Network" address="tcp://localhost:4002"/>
<target name="n3" xsi:type="Network" address="tcp://localhost:4003"/>
</targets>
</nlog>
上面的例子里我们定义了两个缓冲文件目标和三个异步以及自动重试网络目标。
缺省目标参数
和缺省封装目标类似,NLog也提供了<default-target-parameters />来让你为目标参数设置缺省值。比如,如果你不希望日志文件总是被打开,你既可以通过给每一个目标增加 keepFileOpen=”false”属性来达到这个目的:
<nlog>
<targets>
<target name="f1" xsi:type="File" fileName="f1.txt" keepFileOpen="false"/>
<target name="f2" xsi:type="File" fileName="f2.txt" keepFileOpen="false"/>
<target name="f3" xsi:type="File" fileName="f3.txt" keepFileOpen="false"/>
</targets>
</nlog>
或者,你可以定义一个<default-target-parameters />并把它的值赋给当前<targets />区域里所有的目标。缺省参数时依据不同的类型定义的,并且在XML文件的实际属性没有被定义好之前就生效了。
<nlog>
<targets>
<default-target-parameters xsi:type="File" keepFileOpen="false"/>
<target name="f1" xsi:type="File" fileName="f1.txt"/>
<target name="f2" xsi:type="File" fileName="f2.txt"/>
<target name="f3" xsi:type="File" fileName="f3.txt"/>
</targets>
</nlog>