ASP.NET Core 集成NLog详细教程

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>
📌 总结

仅写入数据库的关键点:

  1. ✅ 必须安装 NLog.Database
  2. ✅ 配置文件中只保留 Database Target
  3. ✅ 不要配置 File 或 Console Target
  4. ✅ 生产环境使用异步包装器提升性能
  5. ✅ 启用内部日志便于排查问题

这样配置后,所有日志将仅写入数据库,不会产生任何文件或控制台输出。

常用配置文件选项说明
配置项 说明 示例
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包:

  1. NLog.Web.AspNetCore
  2. 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>

第六步: 常见问题排查

问题:日志没有输出

解决方案:

  1. 检查 nlog.config 是否在输出目录:
xml 复制代码
<Content Include="nlog.config" CopyToOutputDirectory="PreserveNewest" />
  1. 启用 NLog 内部日志,查看配置加载错误:
csharp 复制代码
// 在 Program.cs 开头添加
using NLog;

InternalLogger.LogFile = "c:\\temp\\nlog-internal.log";
InternalLogger.LogLevel = LogLevel.Trace;
  1. 验证配置文件语法:
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 配置只需:

  1. 安装 NuGet 包
  2. 创建 nlog.config 文件
  3. Program.cs 中添加 builder.Host.UseNLog();
相关推荐
java修仙传1 小时前
Java 实习日记:一次 Excel 导入校验 Bug 的定位与数据更新逻辑优化
java·数据库·bug·excel·后端开发
wa的一声哭了1 小时前
Mit6.s081 Interrupts and device driver(中断和设备驱动)
linux·服务器·arm开发·数据库·python·gpt·算法
RoboWizard1 小时前
DIY移动硬盘?2230能否堪大任!
数据库·人工智能·智能手机·性能优化·负载均衡
六月雨滴1 小时前
CDB/PDB 多租户存储架构(12c+)
数据库·oracle·dba
城数派1 小时前
1958-2024年全球4km分辨率逐月土壤湿度栅格数据
数据库·arcgis·信息可视化·excel
六月雨滴1 小时前
Oracle 存储体系架构概述
数据库·oracle
鹏程十八少1 小时前
13. Android 面了50位Kotlin候选人,这36个语法坑90%的人答不全
前端·后端·面试
zt1985q1 小时前
本地部署开源数据库管理工具 DBeaver 并实现外部访问( Windows 版本)
运维·服务器·网络·数据库·网络协议
珂玥c1 小时前
新增硬盘有脏数据如何处理——ubuntu16.04
linux·数据库·ide