引言
不管你是开发单体应用还是微服务应用,在实际的软件的开发、测试和运行阶段,开发者都需要借助日志来定位问题。因此一款好的日志组件将至关重要,在.NET 的开源生态中,目前主要有Serilog、Log4Net和NLog三款优秀的日志组件,但相较而言,NLog功能更加强大且扩展性强,允许开发者在仅修改配置文件的方式来丰富日志输出内容,支持多种日志格式,包括XML、JSON、YAML等,支持多种输出目标,包括文件、数据库、控制台、Loki、ElasticSearch等,支持自定义日志格式,支持日志级别,支持异步写入等功能。
NLog 日志组件的使用
那在实际使用中如何集成呢?接下来以ASP.NET Core 应用为例进行详细讲解。
- 创建示例项目:控制台执行
dotnet new mvc -n NLog.Demo
创建示例应用。 - 安装NLog 日志组件:进入项目内部,控制台执行
dotnet add package NLog.Web.AspNetCore
添加NLog.Web.AspNetCore
NuGet 包。 - 添加NLog 配置文件:官方提供两种方式用来添加配置,一种是添加
nlog.config
文件使用xml
格式进行配置,一种是直接在appsettings.json
文件中使用json
格式进行配置,这里推荐使用json
格式配置,以便和ASP.NET Core现有的配置体系对齐。在appsettings.json
中添加NLog
配置节点,如下所示,该配置将Info
及以上级别的日志输出到控制台,将Debug
及以上级别的日志输出到App_Data/Logs
目录。
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"NLog": {
"throwConfigExceptions": true,
"variables": {
"logDirectory": "${basedir}/App_Data/Logs"
},
"extensions": [
{
"assembly": "NLog.Web.AspNetCore"
}
],
"targets": {
"async": true,
"logfile": {
"type": "File",
"encoding": "utf-8",
"fileName": "${logDirectory}/${shortdate}/${logger}.${level}.log"
},
"logconsole": {
"type": "Console"
}
},
"rules": [
{
"logger": "*",
"minLevel": "Info",
"writeTo": "logconsole"
},
{
"logger": "*",
"minLevel": "Debug",
"writeTo": "logfile"
}
]
}
}
- 配置NLog 日志组件:修改
Program.cs
如下:
using NLog.Extensions.Logging;
using NLog.Web;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
//配置从配置文件的`NLog` 节点读取配置
var nlogConfig = builder.Configuration.GetSection("NLog");
NLog.LogManager.Configuration = new NLogLoggingConfiguration(nlogConfig);
//清空其他日志Providers
builder.Logging.ClearProviders();
//该配置用来指定使用ASP.NET Core 默认的日志过滤器
var nlogOptions = new NLogAspNetCoreOptions() { RemoveLoggerFactoryFilter = false };
builder.Host.UseNLog(nlogOptions); //启用NLog
var app = builder.Build();
// 省略其他代码
- 打印日志:修改
HomeController
中的Index
Action,添加日志:
using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using NLog.Demo.Models;
namespace NLog.Demo.Controllers;
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
_logger.LogInformation("Hello {user}, this is NLog.", new { id = 1, name = "Shengjie" });
return View();
}
}
- 运行项目:日志将按照上方配置输出到控制台和指定目录。
如果此时想按环境控制日志输出等级,仅需修改对应环境的配置文件即可,比如修改appsettings.Development.json
中的Logging
节点配置如下,即可输出所有以Microsoft.AspNetCore
为前缀Information
以上级别的日志:
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Information"
}
}
修改后,即可输出前缀为Microsoft.AspNetCore的日志,如下所示,从中可以看出该日志是使用|分割,使用的是默认的日志布局TextLayout,配置为:{longdate}|{level:uppercase=true}|{logger}|{message:withexception=true}。
2023-03-01 10:00:38.7022|INFO|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Executed action NLog.Demo.Controllers.HomeController.Index (NLog.Demo) in 94.5297ms
这种日志的好处是开发环境查看比较直观,但是因为缺失了字段信息,收集后不便分析,那如何调整为结构化的日志结构呢?简单,使用JsonLayout
即可,修改NLog:targets:logconsole
节点添加layout
节点配置即可,如下所示:
"targets": {
"async": true,
"logconsole": {
"type": "Console",
"layout": {
"type": "JsonLayout",
"attributes": [
{
"name": "@timestamp",
"layout": "${date}"
},
{
"name": "app",
"layout": "${processname}"
},
{
"name": "env",
"layout": "${environment:ASPNETCORE_ENVIRONMENT}"
},
{
"name": "level",
"layout": "${level}"
},
{
"name": "logger",
"layout": "${logger}"
},
{
"name": "message",
"layout": "${message}"
},
{
"name": "exception",
"layout": "${exception:format=toString}"
},
{
"name": "aspnet-request-method",
"layout": "${aspnet-request-method}"
},
{
"name": "aspnet-request-url",
"layout": "${aspnet-request-url}"
},
{
"name": "aspnet-mvc-controller",
"layout": "${aspnet-mvc-controller}"
},
{
"name": "aspnet-mvc-action",
"layout": "${aspnet-mvc-action}"
}
]
}
}
}
重新运行就可以得到Json
结构化的日志结构,日志输出举例如下:
{
"@timestamp": "2023/03/01 13:25:11.912",
"app": "NLog.Demo",
"env": "Development",
"level": "Info",
"logger": "NLog.Demo.Controllers.HomeController",
"message": "Hello { id = 1, name = Shengjie }, this is NLog.",
"aspnet-request-method": "GET",
"aspnet-request-url": "https://localhost/",
"aspnet-mvc-controller": "Home",
"aspnet-mvc-action": "Index"
}
其中app字段,是通过NLog预置的{processname}字段获取,env字段是通过{environment}从指定的环境变量获取,以aspnet-为前缀的字段则是通过NLog.Web.AspNetCore中预置的字段中获取,因此,在配置NLog时,要在NLog节点下加入extensions配置。
"NLog": {
"throwConfigExceptions": true,
"variables": {
"logDirectory": "${basedir}/App_Data/Logs"
},
"extensions": [
{
"assembly": "NLog.Web.AspNetCore"
}
]
}
NLog除了以上预置的字段外,还有很多其他字段,比如从配置文件读取字段,从应用读取身份信息,提取请求数据包,读取请求头,截取QueryString中的指定字段。而正是是因为这些开箱即用的预置字段,保证开发者随时按需调整日志输出的字段、格式和目标。
总结
通过以上介绍,相信你发现了NLog日志组件的强大之处,允许开发者在仅修改配置文件的方式来丰富日志输出字段、格式,可以有效地帮助开发者记录和分析应用程序的运行情况。