ASP.NET Core 集成NLog教程
首先、了解集成NLog使用流程
1、安装 NuGet 包
2、配置文件(nlog.config)
3、Program.cs启动配置
4、在代码中使用
第一步:安装 NuGet 包
根据项目类型,在"程序包管理器控制台"执行对应命令:
csharp
# 基础库,所有项目都需要
dotnet add package NLog
# ASP.NET Core 项目专用(增强了对 HttpContext 的支持)
dotnet add package NLog.Web.AspNetCore
# 若需将日志写入数据库
dotnet add package NLog.Database
# 连接数据库包
dotnet add package Microsoft.Data.SqlClient
⚙️ 第二步:配置文件(nlog.config)
NLog 核心是 nlog.config 文件(XML 格式),建议放在项目根目录并设"生成操作"为"始终复制"。
2.1、NLog配置仅仅写入文件
xml
<?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"
autoReload="true"
throwExceptions="false"
internalLogLevel="Warn"
internalLogFile="logs/internal-nlog.log">
<targets>
<!-- 异步写入,提升性能 -->
<target name="asyncFile" xsi:type="AsyncWrapper" queueLimit="5000" overflowAction="Block">
<target xsi:type="File"
name="fileTarget"
fileName="logs/${shortdate}.log"
layout="${longdate} ${level:uppercase=true} ${logger:shortName=true} - ${message} ${exception:format=toString}"
archiveFileName="logs/archive/${shortdate}.{#}.log"
archiveEvery="Day"
archiveNumbering="DateAndSequence"
maxArchiveFiles="30"
concurrentWrites="true"
keepFileOpen="true"
encoding="utf-8" />
</target>
</targets>
<rules>
<!-- 屏蔽框架日志 -->
<logger name="Microsoft.*" maxlevel="Warn" final="true" />
<logger name="System.*" maxlevel="Warn" final="true" />
<!-- 应用日志 -->
<logger name="*" minlevel="Info" writeTo="asyncFile" />
</rules>
</nlog>
注意事项
✅ 确保目录存在
NLog 会自动创建不存在的目录,无需手动创建。
✅ 文件锁问题
xml
<!-- 多进程/多线程写入 -->
<target xsi:type="File" concurrentWrites="true" />
<!-- 单进程高频写入 -->
<target xsi:type="File" keepFileOpen="true" />
✅ 性能优化建议
生产环境开启 async="true" 或使用 AsyncWrapper
设置合适的 queueLimit(如 5000-10000)
使用 keepFileOpen="true" 减少文件打开/关闭开销
2.2、 生产环境推荐配置仅写入Sqlsever数据库
xml
<?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"
autoReload="true"
throwExceptions="false"
internalLogLevel="Warn"
internalLogFile="logs/nlog-internal.log">
<extensions>
<add assembly="NLog.Database"/>
</extensions>
<targets>
<!-- 异步 + 数据库连接池 -->
<target name="asyncDb" xsi:type="AsyncWrapper"
queueLimit="5000"
overflowAction="Block">
<target xsi:type="Database"
dbProvider="Microsoft.Data.SqlClient"
connectionString="Server=localhost;Database=LogDb;User Id=loguser;Password=***;Pooling=true;Min Pool Size=5;Max Pool Size=50;"
commandTimeout="30">
<commandText>
INSERT INTO NLogLogs
([Timestamp], Level, Logger, Message, Exception, MachineName, ProcessId, ThreadId)
VALUES
(@timestamp, @level, @logger, @message, @exception, @machinename, @processid, @threadid);
</commandText>
<parameter name="@timestamp" layout="${date:format=yyyy-MM-dd HH\:mm\:ss.fff}" />
<parameter name="@level" layout="${level:uppercase=true}" />
<parameter name="@logger" layout="${logger:shortName=true}" />
<parameter name="@message" layout="${message}" />
<parameter name="@exception" layout="${exception:format=ToString}" />
<parameter name="@machinename" layout="${machinename}" />
<parameter name="@processid" layout="${processid}" />
<parameter name="@threadid" layout="${threadid}" />
</target>
</target>
</targets>
<rules>
<!-- 屏蔽框架冗余日志 -->
<logger name="Microsoft.*" maxlevel="Warn" final="true" />
<logger name="System.*" maxlevel="Warn" final="true" />
<!-- 应用日志写数据库 -->
<logger name="*" minlevel="Info" writeTo="asyncDb" />
</rules>
</nlog>
📌 总结
仅写入数据库的关键点:
- ✅ 必须安装
NLog.Database包 - ✅ 配置文件中只保留
DatabaseTarget - ✅ 不要配置 File 或 Console Target
- ✅ 生产环境使用异步包装器提升性能
- ✅ 启用内部日志便于排查问题
这样配置后,所有日志将仅写入数据库,不会产生任何文件或控制台输出。
常用配置文件选项说明
| 配置项 | 说明 | 示例 |
|---|---|---|
fileName |
日志文件路径和名称 | "logs/${shortdate}.log" |
layout |
日志内容格式 | "${longdate} ${level} ${message}" |
archiveFileName |
归档文件名 | "logs/archive/log.{#}.log" |
archiveEvery |
归档周期 | Day, Month, Year, Hour |
maxArchiveFiles |
保留归档文件数 | 30 (保留30天) |
concurrentWrites |
多进程同时写入 | true |
encoding |
文件编码 | utf-8 |
keepFileOpen |
保持文件打开状态 | true (提升性能) |
2.3、混合使用
xml
<?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"
autoReload="true" <!-- 这一行启用自动重载 -->
internalLogLevel="Warn"
internalLogFile="logs/internal-nlog.txt">
<!-- 定义变量 -->
<variable name="logDirectory" value="${basedir}/logs" />
<variable name="logFormat" value="${longdate}|${level:uppercase=true}|${logger}|${message} ${exception:format=tostring}" />
<!-- 扩展自定义过滤器 -->
<extensions>
<add assembly="YourApp" />
</extensions>
<!-- 目标定义 -->
<targets>
<!-- 控制台输出(开发环境) -->
<target xsi:type="Console" name="console"
layout="${date:format=HH\:mm\:ss}|${level:uppercase=true}|${logger}|${message} ${exception:format=tostring}" />
<!-- 结构化JSON文件日志(对接ELK) -->
<target xsi:type="File" name="jsonFile"
fileName="${logDirectory}/app-${shortdate}.json"
layout="${json-encode:raw=true:
time=${date:format=yyyy-MM-ddTHH\:mm\:ss.fffZ}
level=${level:upperCase=true}
logger=${logger}
message=${message}
userId=${mdlc:item=UserId}
requestId=${mdlc:item=RequestId}
clientIp=${mdlc:item=ClientIp}
traceId=${activity:id}
spanId=${activity:parentId}
exception=${exception:tostring}
responseTime=${mdlc:item=ResponseTime}
}" />
<!-- 异步批量写入数据库 -->
<target xsi:type="AsyncWrapper" name="asyncDb">
<target xsi:type="BufferingWrapper" bufferSize="100" flushTimeout="5000">
<target xsi:type="Database"
name="database"
connectionStringName="NLogConnection"
commandType="StoredProcedure"
commandText="dbo.InsertLog">
<parameter name="@Timestamp" layout="${date:format=yyyy-MM-dd HH\:mm\:ss.fff}" />
<parameter name="@Level" layout="${level}" />
<parameter name="@Message" layout="${message}" />
<parameter name="@Exception" layout="${exception:tostring}" />
<parameter name="@UserId" layout="${mdlc:item=UserId}" />
<parameter name="@RequestId" layout="${mdlc:item=RequestId}" />
<parameter name="@ClientIp" layout="${mdlc:item=ClientIp}" />
<parameter name="@TraceId" layout="${activity:id}" />
<parameter name="@SpanId" layout="${activity:parentId}" />
<parameter name="@ResponseTime" layout="${mdlc:item=ResponseTime}" />
</target>
</target>
</target>
<!-- 慢请求过滤器(响应时间>2s) -->
<target xsi:type="FilteringTargetWrapper" name="slowFilter" condition="length('${mdlc:item=ResponseTime}') > 0 and ${mdlc:item=ResponseTime} >= 2000">
<target xsi:type="File" fileName="${logDirectory}/slow-requests.log"
layout="${longdate} | ${level} | ${message} | ${mdlc:item=ResponseTime}ms | ${mdlc:item=RequestId}" />
</target>
</targets>
<!-- 规则定义 -->
<rules>
<!-- 开发环境:控制台输出所有级别 -->
<logger name="*" minlevel="Trace" writeTo="console" final="true" />
<!-- 生产环境:JSON文件记录所有级别 -->
<logger name="*" minlevel="Info" writeTo="jsonFile" />
<!-- 数据库:仅记录Info及以上,异步批量写入 -->
<logger name="*" minlevel="Info" writeTo="asyncDb" />
<!-- 慢请求:单独记录 -->
<logger name="*" minlevel="Info" writeTo="slowFilter" />
<!-- 屏蔽微软和第三方框架的详细日志 -->
<logger name="Microsoft.*" maxlevel="Warn" final="true" />
<logger name="System.*" maxlevel="Warn" final="true" />
<!-- 应用日志:记录 Info 及以上级别 -->
<logger name="*" minlevel="Info" writeTo="console,file" />
<!-- OpenTelemetry追踪ID绑定 -->
<logger name="Microsoft.AspNetCore.*" minlevel="Info" writeTo="jsonFile" final="true" />
</rules>
</nlog>
重要 :将 internalLogFile 路径改为你机器上存在的目录(如 c:\temp),以便 NLog 自己写内部日志,方便排查配置问题。
配置说明:
autoReload="true":运行时修改配置文件会自动生效,无需重启程序。targets:定义日志"写到哪里",Console 和 File 是最常用的。layout:定义日志格式,示例中输出:时间 级别 日志记录器名称 - 消息 异常信息。rules:定义哪些日志记录器匹配哪些 target,*表示所有记录器。
第三步:项目依赖与Program.cs启动配置
确保安装以下NuGet包:
- NLog.Web.AspNetCore
- NLog.Extensions.Logging
在 Program.cs 中按此顺序配置:
csharp
using ModbusDome.Services;
using NLog.Extensions.Logging;
using NLog.Web;
//using NLog.Web.AspNetCore
var builder = WebApplication.CreateBuilder(args);
//// 1. 加载NLog配置(必须在AddLogging之前)
//builder.Host.UseNLog();
//// 2. 清除默认日志提供者,仅保留NLog
//builder.Logging.ClearProviders();
//// 设为最细级别
//builder.Logging.SetMinimumLevel(LogLevel.Trace);
// 移除所有其他日志提供程序(可选)
builder.Logging.ClearProviders();
// 设置最低日志级别
builder.Logging.SetMinimumLevel(LogLevel.Trace);
// 集成 NLog(会自动加载 nlog.config)
builder.Host.UseNLog();
builder.Logging.AddNLog();
// Add services to the container.
builder.Services.AddControllersWithViews();
// 添加Modbus轮询服务作为单例
builder.Services.AddSingleton<ModbusPollService>();
// 注册 BackgroundService
builder.Services.AddHostedService<MyBackgroundService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
// 启动Modbus后台轮询服务
var pollService = app.Services.GetService<ModbusPollService>();
pollService?.Start();
app.Run();
第四步:在代码中使用
方式一:使用 ILogger<T>(推荐)
csharp
[ApiController]
[Route("api/[controller]")]
public class WeatherController : ControllerBase
{
private readonly ILogger<WeatherController> _logger;
public WeatherController(ILogger<WeatherController> logger)
{
_logger = logger;
}
[HttpGet]
public IActionResult Get()
{
_logger.LogInformation("获取天气信息请求");
try
{
// 业务逻辑
return Ok(new { Temperature = 25 });
}
catch (Exception ex)
{
_logger.LogError(ex, "获取天气信息失败");
return StatusCode(500);
}
}
}
方式二:直接使用 NLog Logger
csharp
using NLog;
[ApiController]
[Route("api/[controller]")]
public class ProductController : ControllerBase
{
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
[HttpGet("{id}")]
public IActionResult Get(int id)
{
logger.Info("查询商品,ID: {ProductId}", id);
// 业务逻辑
return Ok();
}
}
注意 :logger 是线程安全的,无需用 lock 保护;但实例通常每类一个,通过 LogManager.GetCurrentClassLogger() 获得。
第五步:进阶实战技巧
1. 异步日志(高性能)
同步日志可能拖慢业务线程,推荐生产环境开启异步:
xml
<targets async="true">
<!-- 原有 target 配置 -->
</targets>
或在目标外套 AsyncWrapper 并设 queueLimit="10000"。异步能大幅提升吞吐(10000+条/秒),但若系统崩溃可能丢失极少量未写入队列的日志。
2. 结构化日志
用占位符 {0}、{1} 或 {@obj} 传递参数,方便后续分析:
logger.Info("用户 {UserId} 登录失败,尝试次数 {Attempts}", user.Id, retryCount);
3. 自定义规则与过滤
按命名空间区分日志,并支持最终匹配 (final):
xml
<rules>
<!-- 核心模块记录详细信息 -->
<logger name="MyApp.Core.*" minlevel="Debug" writeTo="file" />
<!-- API 控制器只记录警告及以上,且此规则匹配后不再继续 -->
<logger name="MyApp.Controllers.*" minlevel="Warn" writeTo="file" final="true" />
<!-- 其他所有模块 -->
<logger name="*" minlevel="Info" writeTo="file" />
</rules>
第六步: 常见问题排查
问题:日志没有输出
解决方案:
- 检查
nlog.config是否在输出目录:
xml
<Content Include="nlog.config" CopyToOutputDirectory="PreserveNewest" />
- 启用 NLog 内部日志,查看配置加载错误:
csharp
// 在 Program.cs 开头添加
using NLog;
InternalLogger.LogFile = "c:\\temp\\nlog-internal.log";
InternalLogger.LogLevel = LogLevel.Trace;
- 验证配置文件语法:
csharp
// 手动加载配置,如果抛出异常说明配置有问题
try
{
LogManager.Configuration = new XmlLoggingConfiguration("nlog.config");
}
catch (Exception ex)
{
Console.WriteLine($"配置加载失败: {ex.Message}");
}
问题:性能和异步配置
生产环境建议开启异步:
xml
<targets async="true">
<target name="file" xsi:type="File" ... />
</targets>
总结
最简洁的 ASP.NET Core + NLog 配置只需:
- 安装 NuGet 包
- 创建
nlog.config文件 Program.cs中添加builder.Host.UseNLog();