有关NLog及中间件实现日志记录
NLog简介
NLog 是一个非常强大的日志记录库,广泛应用于 .NET 应用程序中。它支持多种日志目标(如文件、数据库、控制台、远程服务器等),并且可以根据日志级别(如 Trace、Debug、Info、Warn、Error、Fatal)灵活地输出日志。NLog 的设计非常灵活,允许开发人员通过配置文件或代码轻松控制日志记录的行为。
在 .NET Core 中使用 NLog 记录日志到数据库
为了在 .NET Core 中使用 NLog 并通过中间件记录所有接口的日志到数据库,你可以按照以下步骤操作:
1. 安装 NLog 包
你需要安装以下 NuGet 包:
- NLog:核心包
- NLog.Web.AspNetCore:与 ASP.NET Core 集成
- NLog.Config:提供 NLog 的配置文件支持
- NLog.Targets.Database:支持将日志记录到数据库
2. 配置 NLog
- 顶层属性:控制 NLog 的基本行为,如自动重载、异常抛出和内部日志的配置。
- 扩展:允许加载额外的 NLog 功能,如 ASP.NET Core 的日志渲染器。
- 目标(Targets):定义了日志的实际输出位置,比如数据库、文件等。
- 日志规则(Rules):通过规则来决定不同级别、来源的日志要写入到哪些目标中,实现日志的分类与分发。
3.类型
- 基本组成部分包括:顶层属性、扩展、变量、目标、规则。
- 可选扩展可以包括过滤器、布局渲染器、条件、异步目标、异常处理、异步批处理等。
在项目的根目录下创建或修改 nlog.config
文件,配置将日志记录到数据库。示例如下:
<?xml version="1.0" encoding="utf-8" ?>
<!--xmlns:xsi定义 NLog 配置的 XML 命名空间和模式,用于验证配置的合法性。-->
<!--autoReload:启用="" NLog="" 配置文件的自动重载。当配置文件发生变化时,NLog="" 会自动重新加载,不需要重启应用。=""-->
<!--throwConfigExceptions:启用时,如果配置有问题,NLog 将抛出异常,帮助开发人员调试配置错误。-->
<!--internalLogLevel:用于设置内部日志的级别,如设为 off 表示关闭内部日志。-->
<!--internalLogFile:指定 NLog 的内部日志文件路径。此日志仅用于调试 NLog 本身的工作情况。-->
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
throwConfigExceptions="true"
internalLogLevel="off"
internalLogFile="nlog.txt">
<!-- enable asp.net core layout renderers -->
<!--extensions:NLog 的扩展点,允许加载额外的功能或布局渲染器。在此处,
加载了 NLog.Web.AspNetCore,该程序集提供了一些与 ASP.NET Core 特性集成的日志渲染器(如 HTTP 请求信息、用户信息等)。-->
<extensions>
<add assembly="NLog.Web.AspNetCore"/>
</extensions>
<!--目标定义了日志要输出的地方。在这个配置中,有多个目标:-->
<targets>
<!--这俩大坨定义了不同的日志记录详细情况,不过目标都是存库里的同一张表。-->
<!--xsi:type="Database":这是一个数据库目标。它将日志条目插入到数据库中的 Sys_Logs 表中。-->
<!--dbProvider:指定数据库提供程序,在此使用 MySqlConnector 用于 MySQL 数据库。-->
<!--connectionString:数据库连接字符串,定义如何连接到数据库。-->
<!--commandText:SQL 插入语句,用于将日志数据插入数据库。参数如 @Logger、@Level 等由 NLog 动态生成并插入到日志表中。-->
<!--parameter:这些是插入 SQL 语句中的参数。每个参数的 layout 定义了如何从日志条目中提取数据,如 ${logger} 表示日志的来源,${message} 表示日志消息,${longdate} 表示日志的创建时间-->
<!--第一个更详细,用来跟踪 API 请求,适合监控 API 的性能、请求内容、耗时等。-->
<target name="ApiTrace" xsi:type="Database" dbProvider="MySqlConnector.MySqlConnection, MySqlConnector" connectionString="Server=localhost;Database=laboratory_master;UID=root;Password=123456"
commandText="INSERT INTO Sys_Logs (ID, Logger, Level, Host, Url , Method, Cookie, UserAgent, QueryString, Body , Message, CreateTime, IPAddress, Elapsed) VALUES (upper(uuid()), @Logger, @Level, @Host, @Url , @Method, @Cookie, @UserAgent, @QueryString, @Body , @Message, @CreateTime, @IPAddress, @Elapsed);">
<parameter name="@Logger" layout="${logger}" />
<parameter name="@Level" layout="${uppercase:${level}}" />
<parameter name="@Host" layout="${aspnet-request-host}" />
<parameter name="@Url" layout="${aspnet-request-url:IncludeScheme=false:IncludeHost=false}" />
<parameter name="@Method" layout="${aspnet-request-method}" />
<parameter name="@Cookie" layout="${aspnet-request-headers:HeaderNames=SYSTOKEN:ValuesOnly=true}" />
<parameter name="@UserAgent" layout="${aspnet-request-useragent}" />
<parameter name="@QueryString" layout="${aspnet-request-querystring:OutputFormat=JSON}" />
<parameter name="@Body" layout="${event-properties:item=RequestBody}" />
<parameter name="@Message" layout="${message}" />
<parameter name="@CreateTime" layout="${longdate}" />
<parameter name="@IPAddress" layout="${aspnet-request-ip}" />
<parameter name="@Elapsed" layout="${event-properties:item=Elapsed}"/>
</target>
<!--通用,适用于普通的日志记录,记录请求的基本信息,但不涉及请求体的详细信息或耗时。-->
<target name="database" xsi:type="Database" dbProvider="MySqlConnector.MySqlConnection, MySqlConnector"connectionString="Server=localhost;Database=laboratory_master;UID=root;Password=123456"
commandText="INSERT INTO Sys_Logs (ID, Logger, Level, Host, Url , Method, Cookie, UserAgent, QueryString, Body , Message, CreateTime, IPAddress, Elapsed) VALUES (upper(uuid()), @Logger, @Level, @Host, @Url , @Method, @Cookie, @UserAgent, @QueryString, @Body , @Message, @CreateTime, @IPAddress, 0);">
<parameter name="@Logger" layout="${logger}" />
<parameter name="@Level" layout="${uppercase:${level}}" />
<parameter name="@Host" layout="${aspnet-request-host}" />
<parameter name="@Url" layout="${aspnet-request-url:IncludeScheme=false:IncludeHost=false}" />
<parameter name="@Method" layout="${aspnet-request-method}" />
<parameter name="@Cookie" layout="${aspnet-request-headers:HeaderNames=SYSTOKEN:ValuesOnly=true}" />
<parameter name="@UserAgent" layout="${aspnet-request-useragent}" />
<parameter name="@QueryString" layout="${aspnet-request-querystring:OutputFormat=JSON}" />
<parameter name="@Body" layout="${aspnet-request-posted-body}" />
<parameter name="@Message" layout="${message}" />
<parameter name="@CreateTime" layout="${longdate}" />
<parameter name="@IPAddress" layout="${aspnet-request-ip}" />
</target>
<!--xsi:type="File":这是一个文件目标。它将日志写入文件。-->
<!--fileName:日志文件的路径。使用 ${basedir} 表示应用程序的基础目录,日志按日期进行组织,例如 ERROR-20240915.log。-->
<!--layout:定义日志的格式。这里日志条目包括日志时间、日志来源、日志级别和日志内容,格式清晰易读。-->
<target name="error" xsi:type="File" layout="*********************************************************************************
*****************************************${newline} 日志时间 : ${longdate} ${newline} 日
志来源 : ${logger} ${newline} 日志级别 : ${uppercase:${level}} ${newline} 日志内容 : ${message}${newline}" fileName="${basedir}/Logs/${date:format=yyyyMM}/ERROR-${shortdate}.log" />
<target name="debug" xsi:type="File" layout="*********************************************************************************
*****************************************${newline} 日志时间 : ${longdate} ${newline} 日志来源 : ${logger} ${newline} 日志级别 : ${uppercase:${level}} ${newline} 日志内容 : ${message}${newline}"
fileName="${basedir}/Logs/${date:format=yyyyMM}/DEBUG-${shortdate}.log" />
</targets>
<rules>
<!-- add your logging rules here -->
<!--
Write all events with minimal level of Debug (So Debug, Info, Warn, Error and Fatal, but not Trace) to "f"
<logger name="*" minlevel="Debug" writeTo="f" />
-->
<!--Skip non-critical Microsoft logs and so log only own logs-->
<!--定义了上面目标的使用场景-->
<!--name="Microsoft.*":表示匹配 Microsoft.* 命名空间的日志源,maxlevel="Info" 表示记录最大到 Info 级别的日志,
而不包括 Warn、Error 等。final="true" 表示匹配到这个规则后,不会继续应用后续规则,跳过非关键的 Microsoft 系统日志。-->
<!--name="*":匹配所有日志源。-->
<!--level:指定日志级别。比如 Trace 级别的日志会写入 ApiTrace 目标,而 Debug 级别的日志则写入 debug 文件。-->
<!--writeTo:指定日志写入的目标。例如,writeTo="ApiTrace" 将日志写入到 ApiTrace 目标(即数据库)。-->
<!-- 将所有Trace级别的日志写入到 ApiTrace (详细API跟踪日志) -->
<logger name="Microsoft.*" maxlevel="Info" final="true" />
<!-- 将Info和Warn级别的日志写入到 database (普通日志记录) -->
<logger name="*" level="Trace" writeTo="ApiTrace" />
<logger name="*" level="Info" writeTo="database" />
<logger name="*" level="Warn" writeTo="database" />
<logger name="*" level="Debug" writeTo="debug" />
<logger name="*" level="Error" writeTo="error" />
</rules>
</nlog>
4.在 Program.cs
或 Startup.cs
中配置 NLog
在 Program.cs
中添加 NLog 并将其注册为应用程序的日志记录提供者。
using Autofac.Extensions.DependencyInjection;
using Meiam.System.Common;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NLog;
using NLog.Web;
using System;
using System.Diagnostics;
using System.IO;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace Meiam.System.Hostd
{
public class Program
{
public static void Main(string[] args)
{
//这是初始化 NLog 的第一步。
//Setup():初始化 NLog 的设置。
//LoadConfigurationFromAppSettings():从应用程序的配置文件中(通常是 nlog.config 或 appsettings.json)加载 NLog 的配置文件,
//这个配置文件定义了日志的目标(例如文件、数据库等)和规则(哪些级别的日志输出到哪些目标)。
var logger = NLog.LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
try
{
//创建一个记录器实例(logger),这个记录器专门用于 Program 类中。
//每个类都可以获取它自己的记录器实例,方便将日志与特定类或模块关联
CreateHostBuilder(args).Build().Run();
}
catch (Exception exception)
{
logger.Error(exception, "Stopped program because of exception");
throw;
}
finally
{
LogManager.Shutdown();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
//UseServiceProviderFactory这里使用 Autofac 作为依赖注入容器。NLog 本身依赖依赖注入(DI)框架来获取相关服务,
//这一步不是直接与 NLog 相关,但它确保了整个依赖注入系统正常工作。
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>()
.UseUrls(AppSettings.Configuration["Startup:ApiUrls"].Split(';'))
.ConfigureKestrel(serverOptions =>
{
serverOptions.AllowSynchronousIO = true;//启用同步 IO
})
//logging.ClearProviders():清除默认的日志提供程序,以确保不会与 NLog 或其他日志框架冲突。
//logging.SetMinimumLevel(LogLevel.Trace):设置最低日志级别为 Trace,
//即所有级别的日志(Trace、Debug、Info、Warn、Error、Fatal)都会被捕获并输出。
//logging.AddDebug() 和 logging.AddConsole():分别添加调试输出和控制台输出作为日志目标。
//这些可以帮助在开发过程中查看日志,但与 NLog 的日志目标不冲突。
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
logging.AddDebug();
logging.AddConsole();
});
//这是关键部分,启用了 NLog 作为日志框架。
//它会替换掉默认的 ASP.NET Core 日志框架,将日志处理委托给 NLog。
//结合 NLog 的配置文件(nlog.config 或 appsettings.json 中的 NLog 配置),它决定日志记录的目标和规则。
}).UseWindowsService().UseNLog();
}
}
NLog.LogManager.Setup().LoadConfigurationFromAppSettings()
是 NLog 初始化的一个快捷方法,用于从配置文件中加载日志记录的设置。一下是其查找相应配置文件的方法
1) nlog.config
文件(最常见的方式)
NLog 默认会在应用程序的根目录下(或 bin
目录)寻找名为 nlog.config
的文件。
2) appsettings.json
文件
-
在某些场景下,你可以在
appsettings.json
文件中定义 NLog 的配置。 -
通过
LoadConfigurationFromAppSettings()
,NLog 还可以读取appsettings.json
中的 NLog 配置块。要使其生效,需要在appsettings.json
中包含 NLog 配置部分
3. 显式指定文件路径
var logger = NLog.LogManager.Setup().LoadConfigurationFromFile("path/to/your/nlog.config")
.GetCurrentClassLogger();
5. 创建日志表
确保你的数据库中有一个表来存储日志。
6. 通过中间件记录日志
为了确保所有接口都能记录日志,你可以创建一个自定义中间件来记录每个请求和响应信息:
using Microsoft.AspNetCore.Http;
using NLog;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
namespace Meiam.System.Hostd.Middleware
{
/// <summary>
/// 中间件
/// 记录请求和响应数据
/// </summary>
public class RequestMiddleware
{
private readonly RequestDelegate _next;
/// <summary>
/// 日志接口
/// LogManager.GetCurrentClassLogger()方法返回一个与当前类关联的日志记录器。
/// NLog会根据配置文件或代码中定义的规则将日志写入到指定的目标。
/// </summary>
private static Logger logger = LogManager.GetCurrentClassLogger();
private Stopwatch _stopwatch;
public RequestMiddleware(RequestDelegate next)
{
_stopwatch = new Stopwatch();
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
// 过滤,只有接口
if (context.Request.Path.Value.ToLower().Contains("api"))
{
context.Request.EnableBuffering();
Stream originalBody = context.Response.Body;
_stopwatch.Restart();
// 获取 Api 请求内容
var requestContent = await GetRequesContent(context);
// 获取 Api 返回内容
using (var ms = new MemoryStream())
{
context.Response.Body = ms;
await _next(context);
ms.Position = 0;
await ms.CopyToAsync(originalBody);
}
context.Response.Body = originalBody;
_stopwatch.Stop();
//与日志记录有关的逻辑
//这是NLog用于记录日志的核心数据结构。它可以包含消息、日志级别、属性等信息。
var eventInfo = new LogEventInfo();
eventInfo.Message = "Success";
eventInfo.Properties["Elapsed"] = _stopwatch.ElapsedMilliseconds;
eventInfo.Properties["RequestBody"] = requestContent;
//将日志事件记录到日志目标。这里使用的是Trace级别,这意味着这些日志信息是详细的,通常用于调试目的。
logger.Trace(eventInfo);
}
else
{
await _next(context);
}
}
private async Task<string> GetRequesContent(HttpContext context)
{
var request = context.Request;
var sr = new StreamReader(request.Body);
var content = $"{await sr.ReadToEndAsync()}";
if (!string.IsNullOrEmpty(content))
{
request.Body.Position = 0;
}
return content;
}
}
}
该中间件会捕获每个请求的路径,并在日志中记录“Handling request”和“Finished handling request”消息。结合 NLog,所有这些日志都将根据你的配置写入到数据库中。
总结
- 第一步:安装 NLog 相关 NuGet 包。
- 第二步:配置
nlog.config
文件以指定日志存储目标(如数据库)。 - 第三步:在
Program.cs
中设置 NLog 作为日志提供者。 - 第四步:创建一个记录日志的中间件,确保所有接口请求都能自动记录日志。
通过这种方法,你可以在 .NET Core 中使用 NLog 轻松实现全局接口的日志记录,并且能够将这些日志持久化到数据库中。
原文地址:https://blog.csdn.net/m0_73847536/article/details/142284961
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!