2020/01/29, ASP.NET Core 3.1, VS2019, NLog.Web.AspNetCore 4.9.0html
摘要:基於ASP.NET Core 3.1 WebApi搭建後端多層網站架構【7-使用NLog日誌記錄器】
NLog日誌記錄器的寫入數據庫、寫入文件、彩色控制檯,按等級過濾日誌等功能mysql
文章目錄git
此分支項目代碼github
本章節介紹了NLog日誌記錄器的寫入數據庫、寫入文件、彩色控制檯,按等級過濾日誌等功能,以前寫過ASP.NET Core中使用NLog記錄日誌,僅僅是寫入數據庫和文件,也沒有按等級過濾日誌sql
向MS.WebCore
類庫添加如下包引用:數據庫
<ItemGroup> <PackageReference Include="NLog.Web.AspNetCore" Version="4.9.0" /> </ItemGroup>
上一章節中已經添加過,這裏再次提示下,已經添加過的不須要重複添加
NLog.Web.AspNetCore
包中已經包含NLog
包,因此只須要這一個包便可json
向MS.WebApi
應用程序添加如下包引用:後端
<ItemGroup> <PackageReference Include="MySql.Data" Version="8.0.19" /> </ItemGroup>
MySql.Data
這個包是NLog寫入MySQL數據庫須要使用的數據庫提供程序。架構
在MS.WebCore
類庫中添加Logger文件夾,在該文件夾中添加NLogExtensions.cs
類:app
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開啓的配置封裝在裏面在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下(網站的相對路徑)EnsureNlogConfig
方法確保它和appsettings.json
一致在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替換了:
NLogUtil.WriteFileLog
方法,而如今,日誌寫入文件是按日誌等級來的,大於指定的等級自動寫入文件logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace)
"Default": "Information"
"Default": "Trace"
"Default": "Trace"
等級提升至Information,此時再用Postman調用http://localhost:5000/weatherforecast
,你會發現控制檯沒有日誌輸出了,由於咱們在WeatherForecastController中寫的日誌等級爲LogTrace,被過濾掉了項目完成後,以下圖所示: