2019/10/28, ASP.NET Core 3.0, NLog 4.6.7, NLog.Web.AspNetCore 4.9.0

摘要:NLog在ASP.NET Core网站中的使用,NLog日志写入数据库,NLog日志写入文件

案例代码

编辑于 2020/02/21 :

本文的记录日志封装了统一的NLogUtil方法进行调用写日志,其实可以使用依赖注入的方式得到logger,并且日志按等级过滤,可以考虑看我写的新的关于NLog使用的方法:《ASP.NET Core搭建多层网站架构【7-使用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. <?xml version="1.0" encoding="utf-8"?>
  2. <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. autoReload="true"
  5. throwExceptions="false"
  6. internalLogLevel="Off"
  7. internalLogFile="NlogRecords.log">
  8. <!--Nlog内部日志记录为Off关闭。除非纠错,不可以设为Trace否则速度很慢,起码Debug以上-->
  9. <extensions>
  10. <add assembly="NLog.Web.AspNetCore" />
  11. </extensions>
  12. <targets>
  13. <!--通过数据库记录日志 配置
  14. dbProvider请选择mysql或是sqlserver,同时注意连接字符串,需要安装对应的sql数据提供程序
  15. MYSQL:
  16. dbProvider="MySql.Data.MySqlClient.MySqlConnection, MySql.Data"
  17. connectionString="server=localhost;database=BaseMIS;user=root;password=123456"
  18. MSSQL:
  19. dbProvider="Microsoft.Data.SqlClient.SqlConnection, Microsoft.Data.SqlClient"
  20. connectionString="Server=127.0.0.1;Database=BaseMIS;User ID=sa;Password=123456"
  21. -->
  22. <target name="log_database" xsi:type="Database" dbProvider="MySql.Data.MySqlClient.MySqlConnection, MySql.Data"
  23. connectionString="server=192.168.137.10;database=TestNLog;user=root;password=mysql@local">
  24. <commandText>
  25. INSERT INTO TblLogrecords
  26. (LogDate,LogLevel,LogType,Logger,Message,MachineName,MachineIp,NetRequestMethod
  27. ,NetRequestUrl,NetUserIsauthenticated,NetUserAuthtype,NetUserIdentity,Exception)
  28. VALUES
  29. (@LogDate,@LogLevel,@LogType,@Logger,@Message,@MachineName,@MachineIp,@NetRequestMethod
  30. ,@NetRequestUrl,@NetUserIsauthenticated,@NetUserAuthtype,@NetUserIdentity,@Exception);
  31. </commandText>
  32. <parameter name="@LogDate" layout="${date}" />
  33. <parameter name="@LogLevel" layout="${level}" />
  34. <parameter name="@LogType" layout="${event-properties:item=LogType}" />
  35. <parameter name="@Logger" layout="${logger}" />
  36. <parameter name="@Message" layout="${message}" />
  37. <parameter name="@MachineName" layout="${machinename}" />
  38. <parameter name="@MachineIp" layout="${aspnet-request-ip}" />
  39. <parameter name="@NetRequestMethod" layout="${aspnet-request-method}" />
  40. <parameter name="@NetRequestUrl" layout="${aspnet-request-url}" />
  41. <parameter name="@NetUserIsauthenticated" layout="${aspnet-user-isauthenticated}" />
  42. <parameter name="@NetUserAuthtype" layout="${aspnet-user-authtype}" />
  43. <parameter name="@NetUserIdentity" layout="${aspnet-user-identity}" />
  44. <parameter name="@Exception" layout="${exception:tostring}" />
  45. </target>
  46. <target name="log_file" xsi:type="File" fileName="${basedir}/logs/${shortdate}.log"
  47. layout="${longdate} | ${level:uppercase=false} | ${message} ${onexception:${exception:format=tostring} ${newline} ${stacktrace} ${newline}" />
  48. </targets>
  49. <rules>
  50. <!--跳过所有级别的Microsoft组件的日志记录-->
  51. <logger name="Microsoft.*" final="true" />
  52. <!-- BlackHole without writeTo -->
  53. <!--只通过数据库记录日志,如果给了name名字,cs里用日志记录的时候,取logger需要把name当做参数-->
  54. <logger name="logdb" writeTo="log_database" />
  55. <logger name="logfile" writeTo="log_file" />
  56. </rules>
  57. </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.SqlConnection, Microsoft.Data.SqlClient(此处更新时间2020-01-06,NLog在新版本中对于mssql的dbProvider有所变动,原先只要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规则,即写入数据库,如果要适配多条规则,用逗号隔开
    • 其余规则可以参考博客

数据库配置

数据表结构

这里数据库为TestNLog:

  1. CREATE DATABASE IF NOT EXISTS `TestNLog`;
  2. USE `TestNLog`;
  3. -- Dumping structure for table TestNLog.TblLogrecords
  4. CREATE TABLE IF NOT EXISTS `TblLogrecords` (
  5. `Id` int(11) NOT NULL AUTO_INCREMENT,
  6. `LogDate` datetime(6) NOT NULL,
  7. `LogLevel` varchar(50) NOT NULL,
  8. `LogType` varchar(50) DEFAULT NULL,
  9. `Logger` varchar(256) NOT NULL,
  10. `Message` longtext,
  11. `MachineName` varchar(50) DEFAULT NULL,
  12. `MachineIp` varchar(50) DEFAULT NULL,
  13. `NetRequestMethod` varchar(10) DEFAULT NULL,
  14. `NetRequestUrl` varchar(500) DEFAULT NULL,
  15. `NetUserIsauthenticated` varchar(10) DEFAULT NULL,
  16. `NetUserAuthtype` varchar(50) DEFAULT NULL,
  17. `NetUserIdentity` varchar(50) DEFAULT NULL,
  18. `Exception` longtext,
  19. PRIMARY KEY (`Id`)
  20. ) ENGINE=InnoDB AUTO_INCREMENT=96 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

网站配置连接

appsettings.json中增加ConectionStrings节点:

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

统一日志记录方法

网站下新建CommonUtils文件夹,添加NLogUtil.cs文件(包含LogType定义):

  1. using NLog;
  2. using NLog.Config;
  3. using System;
  4. using System.ComponentModel;
  5. using System.Linq;
  6. using System.Xml.Linq;
  7. namespace NLogUsage.CommonUtils
  8. {
  9. public enum LogType
  10. {
  11. [Description("网站")]
  12. Web,
  13. [Description("数据库")]
  14. DataBase,
  15. [Description("Api接口")]
  16. ApiRequest,
  17. [Description("中间件")]
  18. Middleware
  19. }
  20. public static class NLogUtil
  21. {
  22. public static Logger dbLogger = LogManager.GetLogger("logdb");
  23. public static Logger fileLogger = LogManager.GetLogger("logfile");
  24. /// <summary>
  25. /// 写日志到数据库
  26. /// </summary>
  27. /// <param name="logLevel">日志等级</param>
  28. /// <param name="logType">日志类型</param>
  29. /// <param name="message">信息</param>
  30. /// <param name="exception">异常</param>
  31. public static void WriteDBLog(LogLevel logLevel, LogType logType, string message, Exception exception = null)
  32. {
  33. LogEventInfo theEvent = new LogEventInfo(logLevel, dbLogger.Name, message);
  34. theEvent.Properties["LogType"] = logType.ToString();
  35. theEvent.Exception = exception;
  36. dbLogger.Log(theEvent);
  37. }
  38. /// <summary>
  39. /// 写日志到文件
  40. /// </summary>
  41. /// <param name="logLevel">日志等级</param>
  42. /// <param name="logType">日志类型</param>
  43. /// <param name="message">信息</param>
  44. /// <param name="exception">异常</param>
  45. public static void WriteFileLog(LogLevel logLevel, LogType logType, string message, Exception exception = null)
  46. {
  47. LogEventInfo theEvent = new LogEventInfo(logLevel, fileLogger.Name, message);
  48. theEvent.Properties["LogType"] = logType.ToString();
  49. theEvent.Exception = exception;
  50. fileLogger.Log(theEvent);
  51. }
  52. /// <summary>
  53. /// 确保NLog配置文件sql连接字符串正确
  54. /// </summary>
  55. /// <param name="nlogPath"></param>
  56. /// <param name="sqlConnectionStr"></param>
  57. public static void EnsureNlogConfig(string nlogPath, string sqlConnectionStr)
  58. {
  59. XDocument xd = XDocument.Load(nlogPath);
  60. if (xd.Root.Elements().FirstOrDefault(a => a.Name.LocalName == "targets")
  61. is XElement targetsNode && targetsNode != null &&
  62. targetsNode.Elements().FirstOrDefault(a => a.Name.LocalName == "target" && a.Attribute("name").Value == "log_database")
  63. is XElement targetNode && targetNode != null)
  64. {
  65. if (!targetNode.Attribute("connectionString").Value.Equals(sqlConnectionStr))//不一致则修改
  66. {
  67. //这里暂时没有考虑dbProvider的变动
  68. targetNode.Attribute("connectionString").Value = sqlConnectionStr;
  69. xd.Save(nlogPath);
  70. //编辑后重新载入配置文件(不依靠NLog自己的autoReload,有延迟)
  71. LogManager.Configuration = new XmlLoggingConfiguration(nlogPath);
  72. }
  73. }
  74. }
  75. }
  76. }

配置NLog依赖注入

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

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

完成后如下图所示:

启动项目同步连接字符串

修改网站启动Program.cs中的逻辑:

  1. //using NLogUsage.CommonUtils;
  2. //using Microsoft.Extensions.DependencyInjection;
  3. public static void Main(string[] args)
  4. {
  5. //CreateHostBuilder(args).Build().Run();
  6. var host = CreateHostBuilder(args).Build();
  7. try
  8. {
  9. using (IServiceScope scope = host.Services.CreateScope())
  10. {
  11. IConfiguration configuration = scope.ServiceProvider.GetRequiredService<IConfiguration>();
  12. //获取到appsettings.json中的连接字符串
  13. string sqlString = configuration.GetSection("ConectionStrings:MySqlConnection").Value;
  14. //确保NLog.config中连接字符串与appsettings.json中同步
  15. NLogUtil.EnsureNlogConfig("NLog.config", sqlString);
  16. }
  17. //throw new Exception("测试异常");//for test
  18. //其他项目启动时需要做的事情
  19. //code
  20. NLogUtil.WriteDBLog(NLog.LogLevel.Trace, LogType.Web, "网站启动成功");
  21. host.Run();
  22. }
  23. catch (Exception ex)
  24. {
  25. //使用nlog写到本地日志文件(万一数据库没创建/连接成功)
  26. string errorMessage = "网站启动初始化数据异常";
  27. NLogUtil.WriteFileLog(NLog.LogLevel.Error, LogType.Web, errorMessage, new Exception(errorMessage, ex));
  28. NLogUtil.WriteDBLog(NLog.LogLevel.Error, LogType.Web, errorMessage, new Exception(errorMessage, ex));
  29. throw;
  30. }
  31. }

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

启动验证

启动项目,可以正常记录日志到数据库和文件:

Asp.Net Core中使用NLog记录日志的更多相关文章

  1. ASP.NET Core:ASP.NET Core中使用NLog记录日志

    一.前言 在所有的应用程序中,日志功能是不可或缺的模块,我们可以根据日志信息进行调试.查看产生的错误信息,在ASP.NET Core中我们可以使用log4net或者NLog日志组件来实现记录日志的功能 ...

  2. ASP.NET Core中使用Graylog记录日志

    以下基于.NET Core 2.1 定义GrayLog日志记录中间件: 中间件代码: public class GrayLogMiddleware { private readonly Request ...

  3. ASP.NET Core 中使用 GrayLog 记录日志

    使用 UDP 协议发送日志 自定义好的查询 key 存储数据,尽量不要使用 graylog2-server 服务端格式化日志再存储 Ubuntu 安装服务端 sudo apt-get update & ...

  4. 在asp.net core中使用NLog

    第一步:nuget  引入  NLog.Web.AspNetCore 4.5+ 第二步:放入nlog.config <?xml version="1.0" encoding= ...

  5. Asp.net Core中使用NLog,并封装成公共的日志方法

    1.安装NLog "NLog.Extensions.Logging": "1.0.0-rtm-alpha4" 2.配置NLog public void Conf ...

  6. NLog在asp.net core中的应用

    Asp.net core中,自带的Log是在当selfhost运行时,在控制台中输出,不便于查阅,如果用一个log架框,把日志持久化,便于查询. NLog是一个免费的日志记录框架,专门为.net平台下 ...

  7. Asp.Net Core中利用Seq组件展示结构化日志功能

    在一次.Net Core小项目的开发中,掌握的不够深入,对日志记录并没有好好利用,以至于一出现异常问题,都得跑动服务器上查看,那时一度怀疑自己肯定没学好,不然这一块日志不可能需要自己扒服务器日志来查看 ...

  8. 玩转ASP.NET Core中的日志组件

    简介 日志组件,作为程序员使用频率最高的组件,给程序员开发调试程序提供了必要的信息.ASP.NET Core中内置了一个通用日志接口ILogger,并实现了多种内置的日志提供器,例如 Console ...

  9. ASP.NET Core中,UseDeveloperExceptionPage扩展方法会吃掉异常

    在ASP.NET Core中Startup类的Configure方法中,有一个扩展方法叫UseDeveloperExceptionPage,如下所示: // This method gets call ...

随机推荐

  1. Comet 67E: ffort

    题目传送门:Comet 67E. 用了个傻逼做法 A 了这题,欢迎观赏睿智做法! 题意简述: 题目说得很清楚了(这次是我不想写了). 题解: 为了方便,令 \(m\) 为敌人数,\(n\) 为己方士兵 ...

  2. js:

    JavaScript的历史 1992年Nombas开发出C-minus-minus(C--)的嵌入式脚本语言(最初绑定在CEnvi软件中).后将其改名ScriptEase.(客户端执行的语言) Net ...

  3. LeetCode 654. Maximum Binary Tree最大二叉树 (C++)

    题目: Given an integer array with no duplicates. A maximum tree building on this array is defined as f ...

  4. Computer Network Chapter4 solution

    1.以太网使用曼彻斯特编码,效率50% 2.侦听信道时间:来回延时时间(10usec):发送数据(25.6usec): 3.单向时延t=S(距离)/V(电缆传输速率):最小帧长=2*t*C(数据传输速 ...

  5. openlayers绘制点,线,圆等

    由于我的业务需求是可以在底图上进行一些操作,比如绘制电子围栏等功能,于是需要使用openlayers中的画笔功能,接下来开始一波操作 还是上一篇的html页面, 直接上代码 <!doctype ...

  6. 2019SDN上机第2次作业

    1. 利用mininet创建如下拓扑,要求拓扑支持OpenFlow 1.3协议,主机名.交换机名以及端口对应正确,请给出拓扑Mininet执行结果,展示端口连接情况 创建拓扑: 拓扑支持OpenFlo ...

  7. 数据结构——顺序栈(sequence stack)

    /* sequenceStack.c */ /* 栈 先进后出(First In Last Out,FILO)*/ #include <stdio.h> #include <stdl ...

  8. day 29

    Let the dead have the immortality of fame, but the living the immortality of love. 让逝者拥有不朽的荣誉,让生者拥有不 ...

  9. [LeetCode] 343. Integer Break 整数拆分

    Given a positive integer n, break it into the sum of at least two positive integers and maximize the ...

  10. Salesforce 版本控制 - VS Code + GitHub + Salesforce

    使用VS Code开发Salesforce有个很好的地方是可以联接GitHub进行代码版本控制,点击查看使用VS Code开发SalesForce 第一步:安装GIthub Desktop Githu ...