原文连接:https://github.com/NLog/NLog/...
NOTE: 本文章由 赤石俊哉 翻译整理,您能够以学习交流为目的进行任意使用。如需商用请征得原做者以及译者的赞成。git
NLog能够从Nuget上下载。
你只须要安装NLog.Config包,它将会同时安装NLog和NLog.Schema包。
最后将会为工程添加一个初级的设置和智能补全(Intellisense)。
使用GUI或者在程序包管理命令行中输入:github
Install-Package NLog.Config
你如今就能够编译你的程序而后开始使用NLog了。安全
NOTE【译者注】
Log就是常说的日志信息。app
为了从你的程序中建立你所须要的日志消息你须要使用日志记录API。Logger
和LogManager
这两个类将会很常常的被使用到,它们都在NLog命名空间里面。Logger
表明了一些被命名的日志源,并且他们有能够发出日志消息的成员方法。LogManager
则是用于建立和管理Logger
对象的实例。异步
有一点你必需要理解的很重要的是,Logger
并不表明任何特定的日志输出(所以,它并不与任何特定的日志文件等相关联),它只是一个源,它一般对应你代码中的一个类。
从日志源到输出型式的映射经过配置文件和配置API分开定义。
保持这样的分离是为了让你能够在代码中继续写日志声明,经过更新一处的设置能够简单地变换日志的输出型式和输出位置。async
建议为每个类单首创建一个(private static
)Logger
对象。就如咱们以前所说的,你须要使用LogManager
去建立Logger
的实例。
下面的代码将会建立一个和class
有着相同名字的Logger
。函数
namespace MyNamespace { public class MyClass { private static Logger logger = LogManager.GetCurrentClassLogger(); } }
管理Logger
的名字也是能够的:性能
using NLog; Logger logger = LogManager.GetLogger("MyClassName");
由于Logger对象是线程安全的,因此你能够简单地建立它并存放在一个static
变量中。学习
每个日志消息都用一个日志级别来修饰,它们用来识别消息的重要性和具体细节。NLog能够以Logger对象的名称和日志级别为主,路由日志消息。测试
NLog支持下面的日志级别:
Trace
- 特别细节的日志,可能包含大量的信息,好比说协议的负载。这个日志级别一般只会在开发期间被启用。
Debug
- Debug信息,比Trace
的信息量要少一些,一般不会在生产环境下使用。
Info
- 信息消息,这个是在生产环境下常用到的。
Warn
- 警告消息,一般用来指示非关键性的问题,这些问题能够被恢复或者只是临时错误。
Error
- 错误消息 - 大多数时候,他们都是Exception
(异常)。
Fatal
- 特别严重的错误!
你能够简单地经过调用Logger
对象的其中一个成员方法来书写日志消息。Logger
类有六个成员函数,和它们的日志级别相符合:Trace()
,Debug()
,Info()
,Warn()
,Error()
,Fatal()
。
固然,也有一个成员函数叫Log()
,你能够将日志级别做为参数来调用这个方法。
using NLog; public class MyClass { private static Logger logger = LogManager.GetCurrentClassLogger(); public void MyMethod1() { logger.Trace("Sample trace message"); logger.Debug("Sample debug message"); logger.Info("Sample informational message"); logger.Warn("Sample warning message"); logger.Error("Sample error message"); logger.Fatal("Sample fatal error message"); // alternatively you can call the Log() method // and pass log level as the parameter. logger.Log(LogLevel.Info, "Sample informational message"); } }
日志消息也能够被参数化 - 你可使用字符串格式,就像你在Console.WriteLine()
和String.Format()
中同样:
using NLog; public class MyClass { private static Logger logger = LogManager.GetCurrentClassLogger(); public void MyMethod1() { int k = 42; int l = 100; logger.Trace("Sample trace message, k={0}, l={1}", k, l); logger.Debug("Sample debug message, k={0}, l={1}", k, l); logger.Info("Sample informational message, k={0}, l={1}", k, l); logger.Warn("Sample warning message, k={0}, l={1}", k, l); logger.Error("Sample error message, k={0}, l={1}", k, l); logger.Fatal("Sample fatal error message, k={0}, l={1}", k, l); logger.Log(LogLevel.Info, "Sample informational message, k={0}, l={1}", k, l); } }
TIP: 你应当尽可能避免本身进行字符串格式化来替代使用NLog中内建的格式化方法(好比:链接,以及自行调用
String.Format()
)。具体缘由表如今:
格式化日志消息须要花费很长时间,因此NLog尝试将格式化操做推迟到了当日志消息须要被输出的时候。若是消息的最后处理被跳过了,因为日志记录配置,你将不须要花费时间在String.Format()
上。具体参见日志记录性能最优化。
虽然到如今为止咱们已经学习了如何从代码中建立日志消息,可是咱们尚未对咱们的日志进行任何的配置输出。因此,当你运行你的测试应用程序时,你将会看到……好吧,啥都没有。如今咱们打开NLog.config
文件而后添加一些日志规则:
在<targets>
部分中,添加:
<target name="logfile" xsi:type="File" fileName="file.txt" />
这将会定义一个目标,日志将会被输出到一个叫作file.txt
的文件中。
在<rules>
部分中,添加:
<logger name="*" minlevel="Info" writeTo="logfile" />
这个片断将会引导Info
级别以及更高级别(包括Info
,Warn
,Error
和Fatal
)的全部日志(name="*"
)输出到一个已命名为logfile
的目标。
注意,当你将这个在Visual Studio中输入时,你应该能够看到IntelliSense会建议属性名而且验证他们的值。最后的配置文件应该像这样:
<?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="logfile" xsi:type="File" fileName="file.txt" /> </targets> <rules> <logger name="*" minlevel="Info" writeTo="logfile" /> </rules> </nlog>
让咱们来试试更复杂的东西吧。想象一下你想要将很是细节的日志发送到一个文件,并且你也但愿在控制台窗口中看到他们,可是在控制台窗口中细节稍微少一些。下面的配置文件能够实现这样的需求:
<?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="logfile" xsi:type="File" fileName="file.txt" /> <target name="console" xsi:type="Console" /> </targets> <rules> <logger name="*" minlevel="Trace" writeTo="logfile" /> <logger name="*" minlevel="Info" writeTo="console" /> </rules> </nlog>
如你所见,咱们如今有多个目标,并且有多个规则来路由日志到目标。
还有一个比较常见的应用场景则是,须要为当前正在开发的组件提供更多细节的日志,而其余的组件将会减小输出。咱们就能够用这样的配置文件:
<?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="logfile" xsi:type="File" fileName="file.txt" /> </targets> <rules> <logger name="SomeNamespace.Component.*" minlevel="Trace" writeTo="logfile" final="true" /> <logger name="*" minlevel="Info" writeTo="logfile" /> </rules> </nlog>
第一个规则将会将以SomeNamespace.Component
开头的Logger对象的Trace
级别及以上级别的日志发送到日志文件。属性final=true
将会使得在写入操做以后中止进一步处理。
第二个规则将会将剩下的日志发送到同一个日志文件,可是这些日志有一个约束,那就是级别须要是Info
或更高。
NLog支持特殊类型的目标,从而不须要它们本身作任何日志记录,而是修改其余Logger的行为。这些特殊的目标就称之为封装器。最经常使用的封装器有:
ImpersonatingWrapper - 在写入期间冒充另外一个用户。
AsyncWrapper - 提供异步操做,目标的写入的缓冲执行。
FallbackGroup - 提供错误时回滚。
FilteringWrapper - 用一些条件为基础从总体日志中进行筛选。
还有不少其余的封装器可使用,具体列表你能够看这里。
为了使用封装器,简单地使用一对括起来的<target />
元素用来表示封装器,而后在<rules/>
部分中使用封装器的名字,下面是一个例子:
<?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="asyncFile" xsi:type="AsyncWrapper"> <target name="logfile" xsi:type="File" fileName="file.txt" /> </target> </targets> <rules> <logger name="*" minlevel="Info" writeTo="asyncFile" /> </rules> </nlog>
这样文件的所有写入操做都是异步的了,将会提升调用线程的响应速度。
层级提供了一个当日志被写入文件时,指定日志内容格式的方法。主要有两种层级:
简单层级 - 使用层级渲染器撰写。
结构层级 - 能够输出XML、CSV、以及其余复杂的格式。
简单层级就是一个字符串,在${
和}
中嵌入一些特殊的标记。好比下面的声明将会使得每一条日志消息都是用一个格式为yyyMMddHHmmss:
的日期前缀:
<target name="logfile" xsi:type="File" fileName="file.txt" layout="${date:format=yyyyMMddHHmmss} ${message}" />
当咱们但愿将Logger对象展开到子对象的时候,咱们可使用下面的代码:
class BaseClass { protected BaseClass() { Log = LogManager.GetLogger(GetType().FullName); } protected Logger Log { get; private set; } } class ExactClass : BaseClass { public ExactClass() : base() { } ... }
在父类(BaseClass)的构造函数中,LogManger.GetLogger()
方法不该该使用Type
参数自变量,也就是:
protected BaseClass() { Log = LogManager.GetLogger(GetType().FullName, GetType()); }
这样调用会引起一个异常。
万一ExactClass
有一个默认的调用了BaseClass
构造函数的构造函数,那么,System.StackOverflowException
就会被引起。这是由于在异常被引起以前,ExactClass
尝试着调用了BaseClass
的GetLogger(String, Type)
来构造ExactClass
。
ExactClass => BaseClass => ExactClass => BaseClass => ...
当ExactClass
不存在默认的构造函数时,GetLogger(String, Type)
方法调用不知道如何去构造ExactClass
,则引起NLog.NLogConfigurationException
。