一、什么是LogDashboard
Logdashboard是在github上开源的aspnetcore项目, 它旨在帮助开发人员排查项目运行中出现错误时快速查看日志排查问题。
通常我们会在项目中使用nlog、log4net等日志组件,它们用于记录日志的功能非常强大和完整,常见情况会将日志写到txt或数据库中, 但通过记事本和sql查看日志并不简单方便. LogDashboard提供了一个可以简单快速查看日志的面板。
LogDashboard适用于aspnetcore 2.x - aspnetcore3.x 项目, 采用aspnetcore中间件技术开发. 轻量快速。
官网:https://doc.logdashboard.net/
源码:https://github.com/realLiangshiwei/LogDashboard/tree/master
注:官网和github上的示例版本比较老,可能会出现问题。
二、什么是NLog
NLog 是一个灵活且免费的日志平台,适用于各种 .NET 平台,包括 .NET 标准。NLog 使写入多个 目标变得容易。(数据库、文件、控制台)并即时更改日志记录配置。
NLog 支持结构化 和传统的日志记录。
NLog 的重点:高性能、易于使用、易于扩展和灵活配置。
官网:https://nlog-project.org/?r=redirect
三、LogDashboard集成NLog使用
(1)创建ASP.NET Core Web API项目(.Net 5),并在NuGet中引入LogDashboard、NLog、NLog.Database、NLog.Web.AspNe包,版本如下图所示:
(2)配置NLog.Config
添加一个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="true"
internalLogLevel="off"
internalLogFile="c:\temp\nlog-internal.log" >
<!--日志级别:Trace,Debug,Info,Warn,Error-->
<variable name="myvar" value="myvalue"/>
<!--当你不仅仅只使用 NLog 这一个基础的 dll ,并使用了一些基于 NLog 扩展的工具时,
你就需要在 extensions 节点下面添加引用的程序集名称-->
<extensions>
<add assembly="NLog.Database"/>
<add assembly="NLog.Web.AspNetCore"/>
</extensions>
<targets>
<!--直接在NLog写数据库配置方式,dbProvider="Microsoft.Data.SqlClient.SqlConnection, Microsoft.Data.SqlClient" 这个配置在这里不需要加,加入后会报错
<target name="log_db" xsi:type="Database" connectionString="Server=.;Database=log;Trusted_Connection=True;MultipleActiveResultSets=true" >
-->
<target name="log_db" xsi:type="Database">
<connectionString>${var:ConnectionString}</connectionString>
<commandText>
insert into dbo.NLog ( MachineName, LongDate, Level, Message, Logger, Callsite, Exception ) values ( @MachineName, @LongDate, @Level, @Message, @Logger, @Callsite, @Exception );
</commandText>
<parameter name="@MachineName" layout="${machinename}" />
<parameter name="@LongDate" layout="${longDate}" />
<parameter name="@Level" layout="${level}" />
<parameter name="@Message" layout="${message}" />
<parameter name="@Logger" layout="${logger}" />
<parameter name="@Callsite" layout="${callsite}" />
<parameter name="@Exception" layout="${exception:tostring}" />
</target>
<!--输出到控制台(自定义格式)-->
<!--
<target xsi:type="ColoredConsole" name="console"
layout="日志时间:${longdate} ${newline}日志级别:${uppercase:${level}} ${newline}描述信息:${newline}类名:${logger} ${newline}${message}${newline}" >
</target>
-->
<!--输出到文本-->
<target name="log_file" xsi:type="file" fileName="${basedir}/logs/${shortdate}.log" layout="${longdate}||${level}||${logger}||${message}||${exception:format=ToString:innerFormat=ToString:maxInnerExceptionLevel=10:separator=\r\n}||end" />
</targets>
<rules>
<logger name="Microsoft.*" final="true" />
<!--<logger name="*" minlevel="Trace" writeTo="console" />-->
<logger name="*" minlevel="Trace" writeTo="log_db" />
<logger name="*" minlevel="Trace" writeTo="log_file" />
</rules>
</nlog>
配置文件简单解读
【nlog根节点】
- autoReload属性,true时,如果NLog.config文件有变动,会自动应用新配置(但是会有延迟,过几秒才会应用起来)
- throwExceptions属性,true时,启动程序的时候如果NLog的配置有问题,可以抛出错误,false时则不会提示错误
- internalLogLevel属性(可以理解为Nlog自己运行的日志),设定后,输出的是NLog内部自己的日志记录,如果遇到NLog异常/配置文件没配好,可以把Off改为Trace或Debug来查看NlogRecords.log里的内容
- internalLogFile属性(可以理解为日志记录的路径),可以设定路径,例如默认的D:\Logs\aspNet.log
【extensions节点】引用相应的Dll库
【targets节点】
第一个target节点,可以看到name是log_db,这里的name和下方logger中writeTo属性对应
- xsi:type=”Database” 写入的是数据库(如果填File就是文本)
- dbProvider属性是数据库适配器
SQL server为
Microsoft.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中取,详见后文
- 其余参数均是NLog自带的内容,更多的使用方法查看layout render官方文档
第二个target节点是写入txt文件的节点
- xsi:type=”file”:写入文本
- fileName是写入文件的文件名并按日期添加后缀
- layout属性是写入日志的格式
【rules节点】是各个日志记录器logger的配置
logger配置跳过所有Microsoft日志记录,final 属性是否为最后一个规则,如果为true,其后的规则即便被匹配也不会被运行。 是适配log_db规则,即写入数据库,如果要适配多条规则,用逗号隔开 是适配log_file规则,即写入文本的 以上配置说明出自:
作者:zyknow
链接:https://www.jianshu.com/p/a9f98dfb4600
来源:简书
备注:还有一种通过NuGet的方式引入NLog.Config,这里不推荐使用。了解可以参照:https://www.modb.pro/db/380564 这篇文章
(3)创建数据库表
USE [master]
GO
/****** Object: Database [log] Script Date: 2019/1/3 15:06:59 ******/
CREATE DATABASE [log]
CONTAINMENT = NONE
ON PRIMARY
( NAME = N'log', FILENAME = N'D:\我的项目\LogDashboard可视化日志\Database\log.mdf' , SIZE = 8192KB , MAXSIZE = UNLIMITED, FILEGROWTH = 65536KB )
LOG ON
( NAME = N'log_log', FILENAME = N'D:\我的项目\LogDashboard可视化日志\Database\log_log.ldf' , SIZE = 8192KB , MAXSIZE = 2048GB , FILEGROWTH = 65536KB )
GO
ALTER DATABASE [log] SET COMPATIBILITY_LEVEL = 130
GO
IF (1 = FULLTEXTSERVICEPROPERTY('IsFullTextInstalled'))
begin
EXEC [log].[dbo].[sp_fulltext_database] @action = 'enable'
end
GO
ALTER DATABASE [log] SET ANSI_NULL_DEFAULT OFF
GO
ALTER DATABASE [log] SET ANSI_NULLS OFF
GO
ALTER DATABASE [log] SET ANSI_PADDING OFF
GO
ALTER DATABASE [log] SET ANSI_WARNINGS OFF
GO
ALTER DATABASE [log] SET ARITHABORT OFF
GO
ALTER DATABASE [log] SET AUTO_CLOSE OFF
GO
ALTER DATABASE [log] SET AUTO_SHRINK OFF
GO
ALTER DATABASE [log] SET AUTO_UPDATE_STATISTICS ON
GO
ALTER DATABASE [log] SET CURSOR_CLOSE_ON_COMMIT OFF
GO
ALTER DATABASE [log] SET CURSOR_DEFAULT GLOBAL
GO
ALTER DATABASE [log] SET CONCAT_NULL_YIELDS_NULL OFF
GO
ALTER DATABASE [log] SET NUMERIC_ROUNDABORT OFF
GO
ALTER DATABASE [log] SET QUOTED_IDENTIFIER OFF
GO
ALTER DATABASE [log] SET RECURSIVE_TRIGGERS OFF
GO
ALTER DATABASE [log] SET DISABLE_BROKER
GO
ALTER DATABASE [log] SET AUTO_UPDATE_STATISTICS_ASYNC OFF
GO
ALTER DATABASE [log] SET DATE_CORRELATION_OPTIMIZATION OFF
GO
ALTER DATABASE [log] SET TRUSTWORTHY OFF
GO
ALTER DATABASE [log] SET ALLOW_SNAPSHOT_ISOLATION OFF
GO
ALTER DATABASE [log] SET PARAMETERIZATION SIMPLE
GO
ALTER DATABASE [log] SET READ_COMMITTED_SNAPSHOT OFF
GO
ALTER DATABASE [log] SET HONOR_BROKER_PRIORITY OFF
GO
ALTER DATABASE [log] SET RECOVERY SIMPLE
GO
ALTER DATABASE [log] SET MULTI_USER
GO
ALTER DATABASE [log] SET PAGE_VERIFY CHECKSUM
GO
ALTER DATABASE [log] SET DB_CHAINING OFF
GO
ALTER DATABASE [log] SET FILESTREAM( NON_TRANSACTED_ACCESS = OFF )
GO
ALTER DATABASE [log] SET TARGET_RECOVERY_TIME = 60 SECONDS
GO
ALTER DATABASE [log] SET DELAYED_DURABILITY = DISABLED
GO
ALTER DATABASE [log] SET QUERY_STORE = OFF
GO
USE [log]
GO
ALTER DATABASE SCOPED CONFIGURATION SET LEGACY_CARDINALITY_ESTIMATION = OFF;
GO
ALTER DATABASE SCOPED CONFIGURATION SET MAXDOP = 0;
GO
ALTER DATABASE SCOPED CONFIGURATION SET PARAMETER_SNIFFING = ON;
GO
ALTER DATABASE SCOPED CONFIGURATION SET QUERY_OPTIMIZER_HOTFIXES = OFF;
GO
USE [log]
GO
/****** Object: Table [dbo].[NLog] Script Date: 2019/1/3 15:06:59 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[NLog](
[Id] [int] IDENTITY(1,1) NOT NULL,
[MachineName] [nvarchar](50) NOT NULL,
[LongDate] [datetime2] NOT NULL,
[Level] [nvarchar](50) NOT NULL,
[Message] [nvarchar](max) NOT NULL,
[Logger] [nvarchar](250) NULL,
[Callsite] [nvarchar](max) NULL,
[Exception] [nvarchar](max) NULL,
CONSTRAINT [PK_dbo.NLog] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
USE [master]
GO
ALTER DATABASE [log] SET READ_WRITE
GO
注:( NAME = N’log’, FILENAME = N’D:\我的项目\LogDashboard可视化日志\Database\log.mdf’ , SIZE = 8192KB , MAXSIZE = UNLIMITED, FILEGROWTH = 65536KB )
LOG ON
( NAME = N’log_log’, FILENAME = N’D:\我的项目\LogDashboard可视化日志\Database\log_log.ldf’ , SIZE = 8192KB , MAXSIZE = 2048GB , FILEGROWTH = 65536KB )
这两段改为自己数据库保存的位置即可
(4)appsettings.json中添加数据库连接配置
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"DefaultConnection": "Server=.;Database=log;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
(5)Program.cs中配置NLog
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NLog.Web;
namespace WebApplication
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args).ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Information);
logging.AddConsole();
}).UseNLog()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
(6)Startup.cs配置
using LogDashboard;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using NLog;
using System.Data.SqlClient;
namespace WebApplication
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// 数据库连接字符串
var connectionString = Configuration.GetConnectionString("DefaultConnection");
services.AddLogDashboard(opt =>
{
//NLog为数据库日志表表名
opt.UseDataBase(() => new SqlConnection(connectionString), "NLog");
});
//NLog.config配置中使用
LogManager.Configuration.Variables["ConnectionString"] = connectionString;
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebApplication", Version = "v1" });
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebApplication v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
//使用日志面板
app.UseLogDashboard();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
四、问题&思考
(1)集成 Serilog写入数据库
(2)LogDashboard集群中使用
(3)自定义日志
(4)根据业务需求自定义LogDashboard日志面板