Asp.Net Core用NLog記錄日志操作方法


需求

1.日志自動寫入到數據庫、寫入到文件

2.appsettings.json數據庫連接更改后,不需要去改NLog中的連接地址,啟動網站或項目時自動檢測變動然后去更改,以appsettings.json為准,保持同步。

3.寫入日志時,除了NLog自帶的字段,新增LogType自定義字段記錄日志類型,例如網站日志、中間件日志等

4.統一的寫日志方法,不用每次get一個logger對象(或依賴注入)來記日志

安裝包

在nuget中安裝NLogNLog.Web.AspNetCore ,這兩個是NLog相關的包。

還需要安裝NLog寫入數據庫的數據庫適配器,我這里寫入到MySQL數據庫,所以安裝MySql.Data

如果是寫入到SQL server數據庫,需要安裝Microsoft.Data.SqlClient

NLog.config 配置文件內容

網站根目錄下新建NLog.config配置文件,記得右擊該文件“屬性”,復制到輸出目錄:“始終復制”

NLog.config文件內容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<?xml version= "1.0" encoding= "utf-8" ?>
  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"
  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>

 

配置文件解讀 nlog根節點: autoReload屬性,true時,如果NLog.config文件有變動,會自動應用新配置(但是會有延遲,過幾秒才會應用起來) internalLogLevel屬性,設定后,輸出的是NLog內部自己的日志記錄,如果遇到NLog異常/配置文件沒配好,可以把Off改為Trace或Debug來查看NlogRecords.log里的內容 internalLogFile屬性,可以設定路徑,例如默認的c:\temp\nlog-internal.log 新增了extensions節點,因為引用了NLog.Web.AspNetCore包 targets節點中是各種記錄方式的配置第一個target節點,可以看到name是log_database,這里的name和下方logger中writeTo屬性對應 xsi:type="Database",就是寫入數據庫了 dbProvider屬性是數據庫適配器,MySQL是MySql.Data.MySqlClient.MySqlConnection, MySql.Data,SQL server是Microsoft.Data.SqlClient,其他數據庫適配器可在官方文檔內查看 connectionString即連接字符串了 commandText子節點是插入數據庫時insert語句,可以看到我這里是寫入到TblLogrecords表,表結構下文會展示出來 parameter子節點是insert語句的各個參數: 有個name="@LogType"參數,layout="${event-properties:item=LogType}",表示@LogType參數的值從event-properties中的LogType中取,這個后文會寫到用法其余參數均是NLog自帶的內容,aspnet-開頭的是NLog.Web.AspNetCore包中提供的方法 layout render官方文檔 第二個target節點,可以看到name是log_file,這里的name和下方logger中writeTo屬性對應 xsi:type="File",即寫入到文件 fileName屬性是文件名,這里是寫入到當前目錄下的logs文件夾,並且按日期歸檔 layout屬性是寫入日志的格式 rules節點是各個日志記錄器logger的配置 第一個logger配置跳過所有Microsoft組件的日志記錄,final 標記當前規則為最后一個規則。其后的規則即時匹配也不會被運行。第二個logger name="logdb",該日志記錄器名為logdb,是適配log_database規則,即寫入數據庫,如果要適配多條規則,用逗號隔開其余規則可以參考https://www.jb51.net/article/173004.htm  數據庫配置數據表結構

這里數據庫為TestNLog:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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節點:

1
2
3
"ConectionStrings" : {
  "MySqlConnection" : "server=192.168.137.10;database=TestNLog;user=root;password=mysql@local"
  }

 

統一日志記錄方法

網站下新建CommonUtils文件夾,添加NLogUtil.cs文件(包含LogType定義):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
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);
   }
   }
  }
  }
}

 

配置NLog依賴注入

網站Program.cs文件中,在CreateHostBuilder方法中添加以下內容:

1
2
3
4
5
//using NLog.Web;
.ConfigureLogging(logging => {
   logging.ClearProviders();
   logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
   }).UseNLog(); // NLog: 依賴注入Nlog

完成后如下圖所示:

啟動項目同步連接字符串

修改網站啟動Program.cs中的邏輯:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//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 ;
  }
}

 

修改完成后,如下圖所示:

啟動驗證

啟動項目,可以正常記錄日志到數據庫和文件:

以上就是本次介紹的全部相關知識點,感謝大家的學習和對腳本之家的支持。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM