ASP.NET Core搭建多层网站架构【7-使用NLog日志记录器】

ASP.NET Core搭建多层网站架构【7-使用NLog日志记录器】

2020/01/29, ASP.NET Core 3.1, VS2019, NLog.Web.AspNetCore 4.9.0

摘要:基于ASP.NET Core 3.1 WebApi搭建后端多层网站架构【7-使用NLog日志记录器】
NLog日志记录器的写入数据库、写入文件、彩色控制台,按等级过滤日志等功能

文章目录

此分支项目代码

本章节介绍了NLog日志记录器的写入数据库、写入文件、彩色控制台,按等级过滤日志等功能,之前写过ASP.NET Core中使用NLog记录日志,仅仅是写入数据库和文件,也没有按等级过滤日志

添加包引用#

MS.WebCore类库添加以下包引用:

<ItemGroup>
  <PackageReference Include="NLog.Web.AspNetCore" Version="4.9.0" />
</ItemGroup>

上一章节中已经添加过,这里再次提示下,已经添加过的不需要重复添加
NLog.Web.AspNetCore包中已经包含NLog包,所以只需要这一个包即可

MS.WebApi应用程序添加以下包引用:

<ItemGroup>
  <PackageReference Include="MySql.Data" Version="8.0.19" />
</ItemGroup>

MySql.Data这个包是NLog写入MySQL数据库需要使用的数据库提供程序。

NLogExtensions#

MS.WebCore类库中添加Logger文件夹,在该文件夹中添加NLogExtensions.cs类:

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NLog;
using NLog.Config;
using NLog.Web;
using System.Linq;
using System.Xml.Linq;

namespace MS.WebCore.Logger
{
    public static class NLogExtensions
    {
        //优先级:Trace>Debug>Info>Warn>Error>Fatal

        const string _mssqlDbProvider = "Microsoft.Data.SqlClient.SqlConnection, Microsoft.Data.SqlClient";
        const string _mysqlDbProvider = "MySql.Data.MySqlClient.MySqlConnection, MySql.Data";

        /// <summary>
        /// 确保NLog配置文件sql连接字符串正确
        /// </summary>
        /// <param name="nlogPath"></param>
        /// <param name="dbType"></param>
        /// <param name="sqlConnectionStr"></param>
        public static void EnsureNlogConfig(string nlogPath, string dbType, string sqlConnectionStr)
        {
            XDocument xd = XDocument.Load(nlogPath);
            if (xd.Root.Elements().FirstOrDefault(a => a.Name.LocalName == "targets")
                is XElement targetsNode && targetsNode != null &&
                targetsNode.Elements().FirstOrDefault(a => a.Name.LocalName == "target" && a.Attribute("name").Value == "log_database")
                is XElement targetNode && targetNode != null)
            {
                if (!targetNode.Attribute("connectionString").Value.Equals(sqlConnectionStr))//连接字符串不一致则修改
                {
                    targetNode.Attribute("connectionString").Value = sqlConnectionStr;
                    //dbProvider的变动仅限mssql和mysql
                    if (dbType.ToLower() == "mysql")
                    {
                        targetNode.Attribute("dbProvider").Value = _mysqlDbProvider; //mysql 
                    }
                    else
                    {
                        targetNode.Attribute("dbProvider").Value = _mssqlDbProvider; //mssql
                    }
                    xd.Save(nlogPath);
                    //编辑后重新载入配置文件(不依靠NLog自己的autoReload,有延迟)
                    LogManager.Configuration = new XmlLoggingConfiguration(nlogPath);
                }
            }
        }

        /// <summary>
        /// 注入Nlog服务
        /// </summary>
        /// <param name="builder"></param>
        /// <returns></returns>
        public static IHostBuilder AddNlogService(this IHostBuilder builder)
        {
            return builder
                  .ConfigureLogging(logging =>
                  {
                      logging.ClearProviders();
                      logging.AddDebug();
                      logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
                  })
                  .UseNLog()// 替换NLog作为日志管理
                  ;
        }
    }
}

说明:

  • 第一个EnsureNlogConfig方法是确保NLog配置文件sql连接字符串和appsettings.json文件中一致,NLog写入数据库功能有对应的DbProvider,我这里只内置了MySQL和SQL server的,如有需要自行修改
  • 第二个AddNlogService是对IHostBuilder的一个方法扩展,把NLog开启的配置封装在里面

NLog.config#

MS.WebApi应用程序中添加Web配置文件,并改名为NLog.config:

右击NLog.config文件,"属性"中选择复制到输出目录为 始终复制
修改NLog.config文件内容如下:

<?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="${basedir}/logs/NlogRecords.log">
  <!--指定了当NLog自己遇到Warn等级以上的报错时,生成日志到./logs/NlogRecords.log下(网站的相对路径)。除非纠错,不可以设为Trace否则速度很慢,起码Debug以上-->
  <extensions>
    <add assembly="NLog.Web.AspNetCore" />
  </extensions>
  <targets>
    <!--通过数据库记录日志 配置
    dbProvider请选择mysql或是sqlserver,同时注意连接字符串,需要安装对应的sql数据提供程序
    dbProvider="MySql.Data.MySqlClient.MySqlConnection, MySql.Data" connectionString="server=192.168.137.10;database=EvMSDB;user=root;password=mysql@local"
    dbProvider="Microsoft.Data.SqlClient.SqlConnection, Microsoft.Data.SqlClient" connectionString="Server=192.168.1.204;Database=EvMSDB;User ID=sa;Password=yzhly@126"
    -->
    <target name="log_database" xsi:type="Database" dbProvider="MySql.Data.MySqlClient.MySqlConnection, MySql.Data" connectionString="server=192.168.137.10;database=MSDB;user=root;password=mysql@local;">
      <commandText>
        INSERT INTO TblLogrecords (LogDate,LogLevel,Logger,Message,MachineName,MachineIp,NetRequestMethod,NetRequestUrl,NetUserIsauthenticated,NetUserAuthtype,NetUserIdentity,Exception)
        VALUES(@LogDate,@LogLevel,@Logger,@Message,@MachineName,@MachineIp,@NetRequestMethod,@NetRequestUrl,@NetUserIsauthenticated,@NetUserAuthtype,@NetUserIdentity,@Exception);
      </commandText>
      <parameter name="@LogDate" layout="${date}" />
      <parameter name="@LogLevel" layout="${level}" />
      <parameter name="@Logger" layout="${logger}" />
      <parameter name="@Message" layout="${message}" />
      <parameter name="@MachineName" layout="${machinename}" />
      <parameter name="@MachineIp" layout="${aspnet-request-ip}" />
      <parameter name="@NetRequestMethod" layout="${aspnet-request-method}" />
      <parameter name="@NetRequestUrl" layout="${aspnet-request-url}" />
      <parameter name="@NetUserIsauthenticated" layout="${aspnet-user-isauthenticated}" />
      <parameter name="@NetUserAuthtype" layout="${aspnet-user-authtype}" />
      <parameter name="@NetUserIdentity" layout="${aspnet-user-identity}" />
      <parameter name="@Exception" layout="${exception:tostring}" />
    </target>
    <!--输出文件-->
    <target name="log_file" xsi:type="File" fileName="${basedir}/logs/${shortdate}.log" layout="${longdate} | ${level:uppercase=false} | ${logger} | ${message} ${onexception:${exception:format=tostring} ${newline} ${stacktrace} ${newline}" />
    <!--ColoredConsole彩色控制台 xsi:type="Console"是指定输出到普通控制台-->
    <target name="log_console" xsi:type="ColoredConsole" useDefaultRowHighlightingRules="true" layout="${longdate}|${level}|${logger}|${message} ${exception}">
      <highlight-row condition="level == LogLevel.Trace" foregroundColor="DarkGray" />
      <highlight-row condition="level == LogLevel.Debug" foregroundColor="Gray" />
      <highlight-row condition="level == LogLevel.Info" foregroundColor="White" />
      <highlight-row condition="level == LogLevel.Warn" foregroundColor="Yellow" />
      <highlight-row condition="level == LogLevel.Error" foregroundColor="Red" />
      <highlight-row condition="level == LogLevel.Fatal" foregroundColor="Magenta" backgroundColor="White" />
    </target>
  </targets>
  <rules>
    <!--跳过所有级别的Microsoft组件的日志记录-->
    <!--<logger name="Microsoft.*" maxlevel="Info" final="true" />-->
    <!-- BlackHole without writeTo -->
    <!--只通过数据库记录日志,这里的*,如果给了name名字,代码里用日志记录的时候,取logger需要把name当做参数-->
    <logger name="*" minlevel="Info" writeTo="log_database" />
    <logger name="*" minlevel="Trace" writeTo="log_console" />
    <logger name="*" minlevel="Warn" writeTo="log_file" />
  </rules>
</nlog>

说明:

  • internalLogLevel="Warn" internalLogFile="${basedir}/logs/NlogRecords.log"这段内容,指定了当NLog自己遇到Warn等级以上的报错时,生成日志到./logs/NlogRecords.log下(网站的相对路径)
  • 下面介绍一共设了的三种target:
    • log_database 写入到数据库:
      • 根据dbProvider不同,写入到不同类型的数据库,其他数据库类型可以查看官方文档
      • connectionString即数据库连接字符串,我们会在项目启动时,调用EnsureNlogConfig方法确保它和appsettings.json一致
    • log_file 输出到文件:
      • 文件名按日期命名写入到./logs文件夹下
    • log_console 输出到彩色控制台:
      • 此时应用的是ColoredConsole即彩色控制台
      • 我自定义了一些highlight-row,自己指定了各等级日志的颜色
  • rules应用规则,给三种target限定了三种等级:
    • 首先写入控制台最小等级为Trace,这样我们在调试时,任何日志我们都能在控制台看到
    • 写入数据库的最小等级为Info,这样并不是所以日志都写入数据库,仅当日志等级大于等于Info时才写入
    • 当发生一些警告、致命错误时,必须以文件形式记录下来,所以写入文件的最小等级为Warn
    • 以上是我自己的配置,可以自行配置等级

网站项目应用NLog服务#

MS.WebApi应用程序的Program.cs类中,添加以下代码至Main方法中:

//using MS.WebCore.Logger
//添加以上using引用
//确保NLog.config中连接字符串与appsettings.json中同步
NLogExtensions.EnsureNlogConfig("NLog.config", "MySQL", scope.ServiceProvider.GetRequiredService<IConfiguration>().GetSection("ConectionStrings:MSDbContext").Value);

CreateHostBuilder方法内,追加使用NLog服务.AddNlogService()
修改后如下图所示:

此时启动项目,可以看到控制台的信息已经发生了变化:

黄色的那部分日志是EntityFrameworkCore自带的日志,在5-网站数据库实体设计及映射配置这一章节中,指定了EFCore使用原生日志方法,而不是NLog日志,因为很可能数据库还没有创建,而NLog要写入到数据库时找不到数据库造成性能下降

修改原生日志等级#

MS.WebApi应用程序中,打开appsettings.Development.json文件,修改LogLevel的默认等级为Trace,Microsoft.Hosting.Lifetime的等级为Warning:

{
  "Logging": {
    "LogLevel": {
      "Default": "Trace",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Warning",
      "Microsoft.EntityFrameworkCore": "Information"
    }
  }
}

修改后如下图

如此一来,在开发调试阶段,微软原生的Logging日志记录最小等级为Trace,Microsoft.Hosting.Lifetime的等级为Warning以下的日志都会跳过

测试写日志#

Program.cs类的Main方法修改为以下内容:

//using NLog;
//添加以上using引用
public static void Main(string[] args)
{
    Logger logger = LogManager.GetCurrentClassLogger();
    try
    {
        var host = CreateHostBuilder(args).Build();
        logger.Trace("网站启动中...");
        using (IServiceScope scope = host.Services.CreateScope())
        {
            logger.Trace("初始化NLog");
            //确保NLog.config中连接字符串与appsettings.json中同步
            NLogExtensions.EnsureNlogConfig("NLog.config", "MySQL", scope.ServiceProvider.GetRequiredService<IConfiguration>().GetSection("ConectionStrings:MSDbContext").Value);

            logger.Trace("初始化数据库");
            //初始化数据库
            DBSeed.Initialize(scope.ServiceProvider.GetRequiredService<IUnitOfWork<MSDbContext>>());

            //for test -start
            //用于查看彩色控制台样式,以及日志等级过滤
            logger.Trace("Test For Trace");
            logger.Debug("Test For Debug");
            logger.Info("Test For Info");
            logger.Warn("Test For Warn");
            logger.Error("Test For Error");
            logger.Fatal("Test For Fatal");
            //for test -end
        }
        logger.Trace("网站启动完成");
        host.Run();
    }
    catch (Exception ex)
    {
        logger.Fatal(ex, "网站启动失败");
        throw;
    }
}

用于测试的代码使用完记得注释掉!

WeatherForecastController.cs类中Get方法添加以下代码:

_logger.LogTrace("WeatherForecast被调用");

完成后代码如下图所示

启动项目,可以看到各日志都按对应等级过滤,写入到不同的目标中:

启动Postman,调用http://localhost:5000/weatherforecast,可以看到原生日志方法已经被NLog替换了:

说明#

  • 和之前的文章ASP.NET Core中使用NLog记录日志相比:
    • 写入数据库时,我去除了LogType这种自定义字段,这样就可以使用原生的写日志方法
    • 不用方法去区别写入数据库还是写入文件,由日志等级自行去过滤,例如之前《ASP.NET Core中使用NLog记录日志》文章中,日志写入文件要调用NLogUtil.WriteFileLog方法,而现在,日志写入文件是按日志等级来的,大于指定的等级自动写入文件
  • 文章一共有三处指定了默认的日志等级:
    • NLogExtensions的AddNlogService方法里logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace)
    • appsettings.json的LogLevel里"Default": "Information"
    • appsettings.Development.json的LogLevel里"Default": "Trace"
    • appsettings.json或appsettings.Development.json中的日志等级配置会覆盖SetMinimumLevel方法,也就是同时都配置的情况下,SetMinimumLevel方法其实是无效的
    • 以上三处全是指定的微软原生Logging的日志默认等级,而不是NLog的,要注意理解和区别。例如把appsettings.Development.json的LogLevel里"Default": "Trace"等级提高至Information,此时再用Postman调用http://localhost:5000/weatherforecast,你会发现控制台没有日志输出了,因为我们在WeatherForecastController中写的日志等级为LogTrace,被过滤掉了

项目完成后,如下图所示:

作者:kasnti

出处:https://www.cnblogs.com/kasnti/p/12239514.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

好的,以下是使用NLog日志记录到SqlServer的步骤: 1. 首先,需要在项目中安装NLogNLog.Web.AspNetCore包。可以使用NuGet包管理器或在项目文件中手动添加依赖项。 2. 在项目的appsettings.json文件中添加以下NLog配置: ``` "NLog": { "targets": { "database": { "type": "Database", "dbProvider": "System.Data.SqlClient", "connectionString": "Server=[server];Database=[database];User Id=[user];Password=[password];", "commandText": "INSERT INTO [Logs] ([Date], [Level], [Logger], [Message], [Exception]) VALUES (@Date, @Level, @Logger, @Message, @Exception);", "parameter": [ { "name": "@Date", "layout": "${date}" }, { "name": "@Level", "layout": "${level}" }, { "name": "@Logger", "layout": "${logger}" }, { "name": "@Message", "layout": "${message}" }, { "name": "@Exception", "layout": "${exception}" } ] } }, "rules": [ { "logger": "*", "minLevel": "Trace", "writeTo": "database" } ] } ``` 3. 在Startup.cs文件中添加以下代码: ```csharp public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) { //... loggerFactory.AddNLog(); //... app.UseMiddleware<NLogMiddleware>(); //... } ``` 4. 创建一个名为Logs的表,用于存储日志记录。表结构应如下所示: ```sql CREATE TABLE [dbo].[Logs]( [Id] [int] IDENTITY(1,1) NOT NULL, [Date] [datetime2](7) NOT NULL, [Level] [nvarchar](50) NOT NULL, [Logger] [nvarchar](250) NOT NULL, [Message] [nvarchar](max) NOT NULL, [Exception] [nvarchar](max) NULL, CONSTRAINT [PK_Logs] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] ``` 5. 现在,可以在代码中使用NLog记录日志了。例如: ```csharp private readonly ILogger<HomeController> _logger; public HomeController(ILogger<HomeController> logger) { _logger = logger; } public IActionResult Index() { _logger.LogInformation("Hello, world!"); return View(); } ``` 这将在Logs表中插入一条日志记录。 希望这可以帮助到你。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值