需求
1.日志自动写入到数据库、写入到文件
2.appsettings.json数据库连接更改后,不需要去改NLog中的连接地址,启动网站或项目时自动检测变动然后去更改,以appsettings.json为准,保持同步。
3.写入日志时,除了NLog自带的字段,新增LogType自定义字段记录日志类型,例如网站日志、中间件日志等
4.统一的写日志方法,不用每次get一个logger对象(或依赖注入)来记日志
安装包
在nuget中安装NLog
和NLog.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" ?> <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" 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规则,即写入数据库,如果要适配多条规则,用逗号隔开其余规则可以参考http://www.zzvips.com/article/77734.html 数据库配置数据表结构
这里数据库为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 ; } } |
修改完成后,如下图所示:
启动验证
启动项目,可以正常记录日志到数据库和文件:
以上就是本次介绍的全部相关知识点,感谢大家的学习和对服务器之家的支持。
原文链接:https://www.cnblogs.com/kasnti/p/11748306.html