2019/10/28, ASP.NET Core 3.0, NLog 4.6.7, NLog.Web.AspNetCore 4.9.0html
摘要:NLog在ASP.NET Core網站中的使用,NLog日誌寫入數據庫,NLog日誌寫入文件
案例代碼mysql
編輯於 2020/02/21 :
本文的記錄日誌封裝了統一的NLogUtil方法進行調用寫日誌,其實可使用依賴注入的方式獲得logger,而且日誌按等級過濾,能夠考慮看我寫的新的關於NLog使用的方法:《ASP.NET Core搭建多層網站架構【7-使用NLog日誌記錄器】》git
1.日誌自動寫入到數據庫、寫入到文件
2.appsettings.json數據庫鏈接更改後,不須要去改NLog中的鏈接地址,啓動網站或項目時自動檢測變更而後去更改,以appsettings.json爲準,保持同步。
3.寫入日誌時,除了NLog自帶的字段,新增LogType自定義字段記錄日誌類型,例如網站日誌、中間件日誌等
4.統一的寫日誌方法,不用每次get一個logger對象(或依賴注入)來記日誌github
在nuget中安裝NLog
和NLog.Web.AspNetCore
,這兩個是NLog相關的包。
還須要安裝NLog寫入數據庫的數據庫適配器,我這裏寫入到MySQL數據庫,因此安裝MySql.Data
若是是寫入到SQL server數據庫,須要安裝Microsoft.Data.SqlClient
sql
網站根目錄下新建NLog.config
配置文件,記得右擊該文件「屬性」,複製到輸出目錄:「始終複製」
數據庫
NLog.config文件內容:json
<?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="Off" internalLogFile="NlogRecords.log"> <!--Nlog內部日誌記錄爲Off關閉。除非糾錯,不能夠設爲Trace不然速度很慢,起碼Debug以上--> <extensions> <add assembly="NLog.Web.AspNetCore" /> </extensions> <targets> <!--經過數據庫記錄日誌 配置 dbProvider請選擇mysql或是sqlserver,同時注意鏈接字符串,須要安裝對應的sql數據提供程序 MYSQL: dbProvider="MySql.Data.MySqlClient.MySqlConnection, MySql.Data" connectionString="server=localhost;database=BaseMIS;user=root;password=123456" MSSQL: dbProvider="Microsoft.Data.SqlClient.SqlConnection, Microsoft.Data.SqlClient" connectionString="Server=127.0.0.1;Database=BaseMIS;User ID=sa;Password=123456" --> <target name="log_database" xsi:type="Database" dbProvider="MySql.Data.MySqlClient.MySqlConnection, MySql.Data" connectionString="server=192.168.137.10;database=TestNLog;user=root;password=mysql@local"> <commandText> INSERT INTO TblLogrecords (LogDate,LogLevel,LogType,Logger,Message,MachineName,MachineIp,NetRequestMethod ,NetRequestUrl,NetUserIsauthenticated,NetUserAuthtype,NetUserIdentity,Exception) VALUES (@LogDate,@LogLevel,@LogType,@Logger,@Message,@MachineName,@MachineIp,@NetRequestMethod ,@NetRequestUrl,@NetUserIsauthenticated,@NetUserAuthtype,@NetUserIdentity,@Exception); </commandText> <parameter name="@LogDate" layout="${date}" /> <parameter name="@LogLevel" layout="${level}" /> <parameter name="@LogType" layout="${event-properties:item=LogType}" /> <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} | ${message} ${onexception:${exception:format=tostring} ${newline} ${stacktrace} ${newline}" /> </targets> <rules> <!--跳過全部級別的Microsoft組件的日誌記錄--> <logger name="Microsoft.*" final="true" /> <!-- BlackHole without writeTo --> <!--只經過數據庫記錄日誌,若是給了name名字,cs裏用日誌記錄的時候,取logger須要把name當作參數--> <logger name="logdb" writeTo="log_database" /> <logger name="logfile" writeTo="log_file" /> </rules> </nlog>
c:\temp\nlog-internal.log
NLog.Web.AspNetCore
包MySql.Data.MySqlClient.MySqlConnection, MySql.Data
,SQL server是Microsoft.Data.SqlClient.SqlConnection, Microsoft.Data.SqlClient
(此處更新時間2020-01-06,NLog在新版本中對於mssql的dbProvider有所變更,原先只要Microsoft.Data.SqlClient便可),其餘數據庫適配器可在官方文檔內查看name="@LogType"
參數,layout="${event-properties:item=LogType}",表示@LogType參數的值從event-properties中的LogType中取,這個後文會寫到用法aspnet-
開頭的是NLog.Web.AspNetCore包中提供的方法這裏數據庫爲TestNLog:c#
CREATE DATABASE IF NOT EXISTS `TestNLog`; USE `TestNLog`; -- Dumping structure for table TestNLog.TblLogrecords CREATE TABLE IF NOT EXISTS `TblLogrecords` ( `Id` int(11) NOT NULL AUTO_INCREMENT, `LogDate` datetime(6) NOT NULL, `LogLevel` varchar(50) NOT NULL, `LogType` varchar(50) DEFAULT NULL, `Logger` varchar(256) NOT NULL, `Message` longtext, `MachineName` varchar(50) DEFAULT NULL, `MachineIp` varchar(50) DEFAULT NULL, `NetRequestMethod` varchar(10) DEFAULT NULL, `NetRequestUrl` varchar(500) DEFAULT NULL, `NetUserIsauthenticated` varchar(10) DEFAULT NULL, `NetUserAuthtype` varchar(50) DEFAULT NULL, `NetUserIdentity` varchar(50) DEFAULT NULL, `Exception` longtext, PRIMARY KEY (`Id`) ) ENGINE=InnoDB AUTO_INCREMENT=96 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
appsettings.json中增長ConectionStrings節點:架構
"ConectionStrings": { "MySqlConnection": "server=192.168.137.10;database=TestNLog;user=root;password=mysql@local" }
網站下新建CommonUtils文件夾,添加NLogUtil.cs文件(包含LogType定義):app
using NLog; using NLog.Config; using System; using System.ComponentModel; using System.Linq; using System.Xml.Linq; namespace NLogUsage.CommonUtils { public enum LogType { [Description("網站")] Web, [Description("數據庫")] DataBase, [Description("Api接口")] ApiRequest, [Description("中間件")] Middleware } public static class NLogUtil { public static Logger dbLogger = LogManager.GetLogger("logdb"); public static Logger fileLogger = LogManager.GetLogger("logfile"); /// <summary> /// 寫日誌到數據庫 /// </summary> /// <param name="logLevel">日誌等級</param> /// <param name="logType">日誌類型</param> /// <param name="message">信息</param> /// <param name="exception">異常</param> public static void WriteDBLog(LogLevel logLevel, LogType logType, string message, Exception exception = null) { LogEventInfo theEvent = new LogEventInfo(logLevel, dbLogger.Name, message); theEvent.Properties["LogType"] = logType.ToString(); theEvent.Exception = exception; dbLogger.Log(theEvent); } /// <summary> /// 寫日誌到文件 /// </summary> /// <param name="logLevel">日誌等級</param> /// <param name="logType">日誌類型</param> /// <param name="message">信息</param> /// <param name="exception">異常</param> public static void WriteFileLog(LogLevel logLevel, LogType logType, string message, Exception exception = null) { LogEventInfo theEvent = new LogEventInfo(logLevel, fileLogger.Name, message); theEvent.Properties["LogType"] = logType.ToString(); theEvent.Exception = exception; fileLogger.Log(theEvent); } /// <summary> /// 確保NLog配置文件sql鏈接字符串正確 /// </summary> /// <param name="nlogPath"></param> /// <param name="sqlConnectionStr"></param> public static void EnsureNlogConfig(string nlogPath, 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))//不一致則修改 { //這裏暫時沒有考慮dbProvider的變更 targetNode.Attribute("connectionString").Value = sqlConnectionStr; xd.Save(nlogPath); //編輯後從新載入配置文件(不依靠NLog本身的autoReload,有延遲) LogManager.Configuration = new XmlLoggingConfiguration(nlogPath); } } } } }
網站Program.cs文件中,在CreateHostBuilder方法中添加如下內容:
//using NLog.Web; .ConfigureLogging(logging => { logging.ClearProviders(); logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace); }).UseNLog(); // NLog: 依賴注入Nlog
完成後以下圖所示:
修改網站啓動Program.cs中的邏輯:
//using NLogUsage.CommonUtils; //using Microsoft.Extensions.DependencyInjection; public static void Main(string[] args) { //CreateHostBuilder(args).Build().Run(); var host = CreateHostBuilder(args).Build(); try { using (IServiceScope scope = host.Services.CreateScope()) { IConfiguration configuration = scope.ServiceProvider.GetRequiredService<IConfiguration>(); //獲取到appsettings.json中的鏈接字符串 string sqlString = configuration.GetSection("ConectionStrings:MySqlConnection").Value; //確保NLog.config中鏈接字符串與appsettings.json中同步 NLogUtil.EnsureNlogConfig("NLog.config", sqlString); } //throw new Exception("測試異常");//for test //其餘項目啓動時須要作的事情 //code NLogUtil.WriteDBLog(NLog.LogLevel.Trace, LogType.Web, "網站啓動成功"); host.Run(); } catch (Exception ex) { //使用nlog寫到本地日誌文件(萬一數據庫沒建立/鏈接成功) string errorMessage = "網站啓動初始化數據異常"; NLogUtil.WriteFileLog(NLog.LogLevel.Error, LogType.Web, errorMessage, new Exception(errorMessage, ex)); NLogUtil.WriteDBLog(NLog.LogLevel.Error, LogType.Web, errorMessage, new Exception(errorMessage, ex)); throw; } }
修改完成後,以下圖所示:
啓動項目,能夠正常記錄日誌到數據庫和文件: