欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > IT业 > 有关NLog及中间件实现日志记录

有关NLog及中间件实现日志记录

2024/10/25 15:25:50 来源:https://blog.csdn.net/m0_73847536/article/details/142284961  浏览:    关键词:有关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.csStartup.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 轻松实现全局接口的日志记录,并且能够将这些日志持久化到数据库中。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com