NLog 快速入门
2024-04-28 15:40:24

使用 NLog 需要先进行配置。可以通过文件配置或代码配置。大多数时候都是通过文件来配置。

配置文件搜索顺序

程序启动时会依次搜索以下文件,直到搜索到为止:

  1. 标准应用程序配置文件 app.config(例如 myapp.exe.config)。
  2. 应用程序目录中的 myapp.exe.nlog
  3. 应用程序目录中的 NLog.config
  4. NLog.dll.nlog 位于 NLog.dll 所在目录中(仅当 NLog 未安装在 GAC 中时)。


从这个顺序可以看出,当有多个项目时可以为每个 exe 独立配置规则,也可以共用一个规则。

配置文件

在工程目录下创建一个 NLog.config 文件,在 Visual Studio 中选中该文件将属性复制到输出目录改为始终复制如果较新则复制
一个简单的配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8" ?>
<nlog>
<!-- 日志输出到哪些地方 -->
<targets>
<!-- name 是目标名称,后面规则中会用到。type 决定了输出位置。其他属性根据 type 有所不同 -->
<target name="logfile" type="File" fileName="${basedir}/file.log" />
<target name="dbg" type="Debugger" />
</targets>

<!-- 日志输出规则 -->
<rules>
<!-- minlevel 是命中级别,该级别及以上才会命中。writeTo 是写入哪个目标 -->
<logger name="*" minlevel="Info" writeTo="logfile" />
<logger name="*" minlevel="Debug" writeTo="dbg" />
</rules>
</nlog>

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using NLog;

namespace WinFormsApp1
{
internal static class Program
{
private static readonly Logger s_logger = LogManager.GetCurrentClassLogger();

[STAThread]
private static void Main()
{
s_logger.Info("hello info");
s_logger.Debug("Hello debug");

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}

控制台输出:

1
2
2024-04-25 23:22:03.6134|INFO|WinFormsApp1.Program|hello info
2024-04-25 23:22:03.6344|DEBUG|WinFormsApp1.Program|Hello debug

日志文件输出:

1
2024-04-25 23:22:03.6134|INFO|WinFormsApp1.Program|hello info

Targets

targets 部分定义日志目标。每个目标都由一个 target 元素表示。每个目标需要两个属性:

  • name:目标名称,在 logger 中需要用到。
  • type:目标类型,表示日志将写到哪里。

Type

目标 说明 文档
Chainsaw 将日志消息发送到 Log4J XML Viewer 应用程序的远程实例。 Wiki
ColoredConsole 使用可自定义的颜色将日志消息写入控制台。 Wiki
Console 将日志消息写入控制台。 Wiki
Database 使用ADO.NET提供程序将日志消息写入数据库。数据库操作总是在事务之外执行。 Wiki
DebugSystem 通过 Debug.WriteLine 发送日志消息。 Wiki
Debug Wiki
Debugger 将日志消息写入附加的托管调试器。 Wiki
EventLog 将日志消息写入Windows事件日志。 Wiki
File 将日志消息写入一个或多个文件。 Wiki
LogReceiverService Wiki
Mail Wiki
Memory Wiki
MethodCall Wiki
Network Wiki
NLogViewer Wiki
Null Wiki
OutputDebugString Wiki
PerfCounter Wiki
Trace Wiki
WebService Wiki


每个 target 都有自己的配置属性,查看官方 Wiki 即可。其中用的最多的当然还是 File target 了。
注意,某些 target 还需要按照依赖包才会生效。

Layout

laytou 属性默认值是:

1
${longdate}|${level:uppercase=true}|${logger}|${message:withexception=true}

输出的日志:

1
2024-04-27 13:40:17.5794|TRACE|WindowsFormsApp.Program|start

简单说,layout就是由一系列的内置变量组合而成的。

变量 示例 说明 文档
${shortdate} 2024-04-27 当前日期 Wiki
${time} 14:08:04.4274 当前时间 Wiki
${date} 2024/04/27 14:04:02.735 当前日期时间(短) Wiki
${longdate} 2024-04-27 13:49:06.1412 当前日期时间(长) Wiki
${ticks} 638498236261006047 当前日期和时间的刻度值 Wiki
${level} TRACE 日志级别 Wiki
${logger} WindowsFormsApp.Program 记录器名称 Wiki
${message} 日志内容 Wiki
${callsite} WindowsFormsApp.Program.Main 调用站点。可包含函数名、源文件等信息 Wiki
${appdomain} 0001:WindowsFormsApp.exe 应用程序域 Wiki
${appsetting} 应用程序设置配置 Wiki
${assembly-version} 1.0.0.0 程序集版本 Wiki
${gc} 1291536 垃圾收集器的信息 Wiki
${hostname} DESKTOP-XXXX 计算机名 Wiki
${machinename DESKTOP-XXXX 运行进程的计算机名 Wiki
${local-ip} 169.254.227.96 本地IP地址 Wiki
${processid} 14476 进程ID Wiki
${processname} WindowsFormsApp 进程名称 Wiki
${processdir} D:\MyApp 进程目录 Wiki
${processinfo} 进程信息。默认显示进程ID Wiki
${processtime} 00:00:04.836 进程启动以来的时间 Wiki
${threadname} 线程名称 Wiki
${threadid} 线程ID Wiki
${basedir} D:\MyApp 应用程序的位置 Wiki
${currentdir} D:\MyApp 工作路径 Wiki
${specialfolder} 系统特殊文件夹路径 Wiki
${tempdir} 系统临时目录 Wiki
${environment} 环境变量 Wiki
${registry} 注册表值 Wiki
${pad} 将填充应用于另一个布局输出 Wiki


常用的一般就是进程、线程信息了。还有其他一些高级用法可以参考官方文档。
另外注意,某些变量需要依赖扩展包,否则不会生效。


我个人喜欢的一个布局:

1
${longdate} [${level:uppercase=true:padding=5}] [${threadid}] [${logger}] ${message}

在默认的布局上对齐日志级别以及加入线程ID

1
2024-04-27 15:03:14.0145 [TRACE] [1] [WindowsFormsApp.Program] Hello

Rules

rules 部分控制什么级别的日志输出到什么 target。一些例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="utf-8" ?>
<nlog>
<rules>
<!-- 匹配任何名称的记录器,Info 级及以上日志输出到 logfile -->
<logger name="*" minlevel="Info" writeTo="logfile" />

<!-- Trace 日志输出到 logfile -->
<logger name="*" level="Trace" writeTo="logfile" />

<!-- 禁用的记录器 -->
<logger name="mylog" levels="Warn,Error" enabled="false" />
</rules>
</nlog>

NLog 会自上而下去尝试匹配每个 logger,匹配到了就打印日志到 target,除非遇到了 final 属性,比如:

1
2
3
4
<rules>
<logger name="*" minlevel="Trace" writeTo="logfile" final="true" />
<logger name="*" minlevel="Trace" writeTo="dbgSys" />
</rules>

final属性会阻止 NLog 继续向下匹配,所以这个例子只会将日志输出到 logfile target。

name

匹配记录器对象的记录器名称,可以包含通配符(*?)。
创建 NLog 记录器对象时,必须提供类似 NLog.LogManager.GetLogger("logger name") 的记录器名称。还可以使用 NLog.LogManager.GetCurrentClassLogger() 从类上下文中提取记录器名称。

1
2
3
4
5
6
7
8
9
10
11
12
internal static class Program
{
static void Main()
{
var logger = LogManager.GetCurrentClassLogger();
// 等于 var logger = LogManager.GetLogger(typeof(Program).FullName);

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}

记录器级别过滤器

如果规则包含多个级别声明属性( level 、 levels 、 minlevel 和 maxlevel ),则仅包含第一个级别声明使用属性或集合,其余的将被忽略。
级别声明属性按以下顺序处理:

  1. levels
  2. level
  3. minlevel 和 maxlevel (它们具有相同的优先级)


注意这里是我测试过的排序,与官方文档中的优先级不同(NLog v5.2.8)。

相关阅读

Tutorial
Configuration file
Configure from code
Layouts
Nlog笔记