编辑于 2020/03/12
熟话说得好,没有日志的监控的项目,上线那是不可能的,足以见得日志监控在整个项目中有它独特的地位,本来想使用Log4做日志监控,可是发现log4在asp.net core中并不支持写入数据库,如果想要写入数据库的话就得自己写,当然我还是有点自知之明的,想了想还是用第三方框架,所以这篇文章是基于Nlog + Sqlserver。
NLog是一个基于.NET平台编写的类库,我们可以使用NLog在应用程序中添加极为完善的跟踪调试代码。 NLog是一个简单灵活的.NET日志记录类库。通过使用NLog,我们可以在任何一种.NET语言中输出带有上下文的(contextual information)调试诊断信息,根据喜好配置其表现样式之后发送到一个或多个输出目标(target)中。 NLog的API非常类似于log4net,且配置方式非常简单。NLog使用路由表(routing table)进行配置,这样就让NLog的配置文件非常容易阅读,并便于今后维护。 NLog支持输出的目标
Nlog官网 最新版本:4.6.8 (2020-03-12)
use master
go
if exists (select * from sysdatabases where name='NlogTestDB')
drop database NlogTestDB --检查有没有这个数据库,如果有就删除它。
go
create database NlogTestDB
on
(
name=LogDB_data, ------------ 养成好习惯,数据文件加_data
filename='C:\sqlserverDB\NlogTestDB_data.mdf', ------------ 一定要是.mdf的文件,代表主数据文件
size=10mb,
maxsize=100mb,
filegrowth=10%
)
log on
(
name=LogDB_log, ------------ 养成好习惯,日志文件加_log
filename='C:\sqlserverDB\NlogTestDB_log.ldf', ------------ 一定要是.ldf的文件,代表日志文件
size=10mb,
maxsize=100mb,
filegrowth=10%
)
use NlogTestDB
--drop table logs
create table logs
(
Id int IDENTITY(1,1) PRIMARY key,
LogDate datetime not null,
LogLevel VARCHAR(50) not null,
LogType VARCHAR(50) DEFAULT null,
Message VARCHAR(5000) not null,
MachineName VARCHAR(50) not null,
MachineIp VARCHAR(50) not null,
RequestController VARCHAR(50) not null,
RequestAction VARCHAR(50) not null,
RequestMethod VARCHAR(100) not null,
RequestHeaders VARCHAR(500) not null,
RequestPostBody VARCHAR(2000) not null,
RequestQuery VARCHAR(100) not null,
RequestUrl VARCHAR(50) not null,
UserName VARCHAR(50) not null,
UserGuid VARCHAR(50) not null,
EXCEPTION VARCHAR(5000) not null,
)
这样数据库就创建成功了
创建. net core项目,这里就不过多演示,本项目是基于最新的Core 3.1 WebAPI
也可以通过双击web项目进行添加还原包
<PackageReference Include="NLog" Version="4.6.8" />
<PackageReference Include="NLog.Web.AspNetCore" Version="4.9.0" />
除此之外,还得装操作数据库的包,博主是基于SqlServer的。 MySql SqlServer
添加配置文件放置到web项目中的根目录即可 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="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="Microsoft.Data.SqlClient.SqlConnection, Microsoft.Data.SqlClient"
connectionString="Server=127.0.0.1;Database=BaseMIS;User ID=sa;Password=123456"
<commandText>
INSERT INTO logs
(LogDate,LogLevel,LogType,Message,MachineName,MachineIp,RequestController,RequestAction,RequestMethod,RequestHeaders
,RequestPostBody,RequestQuery,RequestUrl,UserName,UserGuid,Exception)
VALUES
(@LogDate,@LogLevel,@LogType,@Message,@MachineName,@MachineIp,@RequestController,@RequestAction,@RequestMethod
,@RequestHeaders,@RequestPostBody,@RequestQuery,@RequestUrl,@UserName,@UserGuid,@Exception);
</commandText>
<parameter name="@LogDate" layout="${date}" />
<parameter name="@LogLevel" layout="${level}" />
<parameter name="@LogType" layout="${event-properties:item=LogType}" />
<parameter name="@Message" layout="${message}" />
<parameter name="@MachineName" layout="${machinename}" />
<parameter name="@MachineIp" layout="${aspnet-request-ip}" />
<parameter name="@RequestController" layout="${aspnet-mvc-controller}" />
<parameter name="@RequestAction" layout="${aspnet-mvc-action}" />
<parameter name="@RequestMethod" layout="${aspnet-request-method}" />
<parameter name="@RequestHeaders" layout="${aspnet-request-headers}" />
<parameter name="@RequestPostBody" layout="${aspnet-request-posted-body}" />
<parameter name="@RequestQuery" layout="${aspnet-request-querystring}" />
<parameter name="@RequestUrl" layout="${aspnet-request-url}" />
<parameter name="@UserName" layout="${event-properties:item=UserName}" />
<parameter name="@UserGuid" layout="${event-properties:item=UserGuid}" />
<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根节点:
D:\Logs\aspNet.log
extensions节点,引用了NLog.Web.AspNetCore
targets是比较重要的节点,里面是整个连接数据的配置
第一个target节点,可以看到name是log_database,这里的name和下方logger中writeTo属性对应
xsi:type="Database"
写入的是数据库,填File
就是txtMicrosoft.Data.SqlClient.SqlConnection, Microsoft.Data.SqlClient
MySQL是
MySql.Data.MySqlClient.MySqlConnection, MySql.Data
其他数据库适配器在Nlog官网gitHub查看
connectionString
:数据库连接字符串commandText
:插入到数据库的脚本parameter
数据库脚本的参数,统一就行了name="@LogType"
是参数,layout="${event-properties:item=LogType}
表示@LogType
参数的值从event-properties
中的LogType中取,详见后文第二个target节点是写入txt文件的节点
xsi:type="File"
:写入txtfileName
是写入文件的文件名并按日期添加后缀rules节点是各个日志记录器logger的配置
final
属性是否为最后一个规则,如果为true,其后的规则即便被匹配也不会被运行。在这里务必要选中始终复制
创建文件夹Nlog和文件NlogUtil.cs
NlogUtil.cs
using NLog;
using NLog.Config;
using System;
using System.ComponentModel;
using System.Linq;
using System.Xml.Linq;
namespace Utils.Nlog
{
public enum LogType
{
[Description("网站")]
Web,
[Description("数据库")]
DataBase,
[Description("Api接口")]
ApiRequest,
[Description("中间件")]
Middleware
}
public static class NLogUtil
{
public static Logger MSdbLogger = LogManager.GetLogger("logdb");
public static Logger fileLogger = LogManager.GetLogger("logfile");
/// <summary>
/// 写日志到数据库
/// </summary>
/// <param name="logLevel">日志等级</param>
/// <param name="message">信息</param>
/// <param name="userName">请求用户名</param>
/// <param name="userGuid">请求用户Guid</param>
/// <param name="exception">异常</param>
public static void WriteDBLog(LogLevel logLevel, string message,string userName = null,string userGuid = null, Exception exception = null)
{
LogEventInfo theEvent = new LogEventInfo(logLevel, MSdbLogger.Name, message);
theEvent.Properties["LogType"] = LogType.Web.ToString();
theEvent.Properties["UserName"] = userName;
theEvent.Properties["UserGuid"] = userGuid;
theEvent.Exception = exception;
MSdbLogger.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, string message, Exception exception = null)
{
LogEventInfo theEvent = new LogEventInfo(logLevel, fileLogger.Name, message);
theEvent.Properties["LogType"] = LogType.Web.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的连接会被自动同步为该连接
"ConectionStrings": {
"MySqlserverConnection": "Data Source=127.0.0.1;Initial Catalog=NlogTestDB;Persist Security Info=True;User ID=sa;Password=123456"
}
public class Program
{
public static void Main(string[] args)
{
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:MySqlserverConnection").Value;
//确保NLog.config中连接字符串与appsettings.json中同步
NLogUtil.EnsureNlogConfig("NLog.config", sqlString);
}
//throw new Exception("测试异常");//for test
//其他项目启动时需要做的事情
//code
NLogUtil.WriteDBLog(NLog.LogLevel.Info, "网站启动成功");
host.Run();
}
catch (Exception ex)
{
//使用nlog写到本地日志文件(万一数据库没创建/连接成功)
string errorMessage = "网站启动初始化数据异常";
NLogUtil.WriteFileLog(NLog.LogLevel.Error, errorMessage, new Exception(errorMessage, ex));
NLogUtil.WriteDBLog(NLog.LogLevel.Info, errorMessage);
throw;
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
//using NLog.Web;
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
}).UseNLog(); // NLog: 依赖注入Nlog
}
在core webapi 默认创建的WeatherForecast控制器中get方法使用Nlog记录日志
在web项目bin目录下的项目路径和数据库都会写入数据 Bin目录下的txt
数据库
下载Nlog分支即可
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。