日志配置
通过在启动的时候对一些常用目录的扫描,NLog会尝试使用找到的配置信息进行自动的自我配置。当你运行一个独立的*.exe客户端可执行程序时,NLog将在以下目录搜索配置信息:
- 标准的程序配置文件(通常为 程序名.exe.config)
- 程序目录下的程序名.exe.nlog文件
- 程序目录下的NLog.config文件
- NLog.dll所在目录下的NLog.dll.nlog文件
- 如果定义了NLOG_GLOBAL_CONFIG_FILE环境变量,则该变量所指向的文件
如果是一个ASP.NET程序,被搜索的目录包括:
- 标准的web程序配置文件web.config
- 和web.config在同一目录下的web.nlog文件
- 程序目录下的NLog.config文件
- NLog.dll所在目录下的NLog.dll.nlog文件
- 如果定义了NLOG_GLOBAL_CONFIG_FILE环境变量,则该变量所指向的文件
由于.NET Compact Framework不支持程序配置文件(*.exe.config)和环境变量,因此NLog将只会扫描这些地方:
- 程序目录下的NLog.config文件
- NLog.dll所在目录下的NLog.dll.nlog文件
- 如果定义了NLOG_GLOBAL_CONFIG_FILE环境变量,则该变量所指向的文件
配置文件格式
NLog支持两种配置文件格式
- 配置信息嵌入在.NET应用程序标准的*.exe.config或者web.config文件里
- 保存在独立文件里,也叫单一格式
如果你选择了第一种方式,使用的是标准的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配置文件中都必须提供,其余的则可以选择使用,通常用于一些复杂场景。
- <targets /> - 定义日志的目标/输出
- <rules /> - 定义日志的路由规则
- <extensions /> - 从*.dll加载NLog扩展
- <include /> - 导入外部配置文件
- <variable /> - 为配置变量赋值
输出目标
<target />区域定义了日志的目标或者说输出。每一个<target />元素代表一个目标。我们需要为每一个目标设置两个属性:
- name - 目标的名称
- type - 目标的类型 - 比如“File”,“Database”,“Mail”。如果你使用了名字空间,这个属性会被命名为 xsi:type.
除了这两个属性,通常来说给目标添加一些其它参数,这些属性将会影响你在程序中如何使用诊断跟踪语句(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>
路由规则
<rules />区域定义了日志的路由规则。实际上它是一个简单的路由表,对每一个日志源/记录者的名称和记录等级的组合,定义了一个日志写入目标列表。 表中的规则是被顺序处理的。每当遇到匹配的规则时,日志信息就会被送到规则中定义的一个或多个目标去。如果一个规则被标识为最后一个,那么其后的规则都不会被执行。
每一个路由表项就是一个<logger />元素,它的可以接受的属性有:
- name - 日志源/记录者的名字 (允许使用通配符*)
- minlevel - 该规则所匹配日志范围的最低级别
- maxlevel - 该规则所匹配日志范围的最高级别
- level - 该规则所匹配的单一日志级别
- levels - 该规则所匹配的一系列日志级别,由逗号分隔。
- writeTo - 规则匹配时日志应该被写入的一系列目标,由逗号分隔。
- final - 标记当前规则为最后一个规则。其后的规则即时匹配也不会被运行。
一些例子:
- <logger name="Name.Space.Class1" minlevel="Debug" writeTo="f1" /> - 名字空间Name.Space下的Class1这个类的所有级别等于或者高于Debug的日志信息都写入到“f1”这个目标里。
- <logger name="Name.Space.Class1" levels="Debug,Error" writeTo="f1" /> -名字空间Name.Space下的Class1这个类的所有级别等于Debug或Error的日志信息都写入到“f1”这个目标里。
- <logger name="Name.Space.*" writeTo="f3,f4" /> -名字空间Name.Space下所有类的所有级别的日志信息都写入到“f3”和“f4”这两个目标里。
- <logger name="Name.Space.*" minlevel="Debug" maxlevel="Error" final="true" /> - 名字空间Name.Space下所有类的、级别在Debug和Error之间的(包括Debug,Info,Warn,Error) 日志信息都不会被记录(因为这条规则没有定义writeTo),同时其它后续规则也都会被忽略(因为这里设置了final="true")。
最简单的情况下,整个日志的配置信息可以只由一个<target />元素和一个<logger />规则构成,就可以吧一定级别的日志信息路由到期望的目标去。随着程序不断的变大,增加新的目标和规则也很简单。
上下文信息
NLog最棒的功能之一就是使用布局(layouts)的能力。布局由被一个美元符号$加左大括弧“${”和一个右大括弧“}”为标记所包围的文本所组成。这个标记也就是所谓的“布局生成器(layout renderers),我们可以用它来把一些上下文相关的信息插入到日志信息中。布局可以应用在许多地方,比如可以被用在控制输出到屏幕或写入文件信息的格式,也可以用在控制文件名。接下来我们会更多的了解布局的强大。
包含文件
有时我们希望把配置文件分割为一些比较小的文件。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 throwExceptions="true" />- 设置throwExceptions属性为“true”可以让NLog不再阻挡这类异常,而是把它们抛给调用者。在部署是这样做可以帮我们快速定位问题。一旦应用程序已经正确配置了,我们建议把throwExceptions的值设为“false”,这样由于日志引发的问题不至于导致应用程序的崩溃。
- <nlog internalLogFile="file.txt" />- 设置internalLogFile属性可以让NLog把内部的调试和异常信息都写入指定文件里。
- <nlog internalLogLevel="Trace|Debug|Info|Warn|Error|Fatal" /> - 决定内部日志的级别,级别越高,输出的日志信息越简洁。
- <nlog internalLogToConsole="false|true" /> - 是否把内部日志输出到标准控制台。
- <nlog internalLogToConsoleError="false|true" /> - 是否把内部日志输出到标准错误控制台 (stderr)。
有时我们希望用同一种封装来处理所有的目标,比如说增加缓冲和/或自动重试功能。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>