From 0d2a95e0e94553140f550fc4606ef88c8efab824 Mon Sep 17 00:00:00 2001
From: LemonNoCry <773596523@qq.com>
Date: Sat, 1 Apr 2023 23:25:56 +0800
Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20=E5=88=9D=E6=AD=A5=E8=B0=83?=
=?UTF-8?q?=E6=95=B4Serilog?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 2 +
Blog.Core.Api/Blog.Core.Api.csproj | 6 +-
Blog.Core.Api/Blog.Core.xml | 2 +-
Blog.Core.Api/Controllers/ValuesController.cs | 2 +-
Blog.Core.Api/Filter/GlobalExceptionFilter.cs | 6 +-
Blog.Core.Api/Log4net.config | 364 -----------
Blog.Core.Api/Program.cs | 112 ++--
Blog.Core.Api/Startup.cs | 1 -
Blog.Core.Api/appsettings.json | 601 +++++++++---------
Blog.Core.Api/skyapm.json | 2 +-
Blog.Core.Common/App.cs | 63 +-
Blog.Core.Common/Blog.Core.Common.csproj | 14 +-
Blog.Core.Common/Const/SqlSugarConst.cs | 9 +
Blog.Core.Common/Core/InternalApp.cs | 27 +-
Blog.Core.Common/DB/Aop/SqlsugarAop.cs | 30 +-
Blog.Core.Common/DB/BaseDBConfig.cs | 3 +-
Blog.Core.Common/Helper/RecursionHelper.cs | 67 +-
.../{ => Https}/HttpPolly/HttpPollyHelper.cs | 20 +-
.../{ => Https}/HttpPolly/IHttpPollyHelper.cs | 2 +-
Blog.Core.Common/Https/RequestIpUtility.cs | 83 +++
Blog.Core.Common/Hubs/ChatHub.cs | 3 +-
.../LogHelper/LogContextExtension.cs | 42 ++
.../LogHelper/LogContextStatic.cs | 42 ++
Blog.Core.Common/LogHelper/LogLock.cs | 170 ++---
.../Blog.Core.Extensions.csproj | 3 +-
.../Middlewares/ExceptionHandlerMiddleware.cs | 9 +-
.../Middlewares/IpLimitMiddleware.cs | 7 +-
.../Middlewares/IpLogMiddleware.cs | 7 +-
.../Middlewares/MiniProfilerMiddleware.cs | 7 +-
.../Middlewares/SignalRSendMiddleware.cs | 1 +
.../Middlewares/SwaggerMiddleware.cs | 21 +-
.../ServiceExtensions/AppConfigSetup.cs | 38 +-
.../AutofacModuleRegister.cs | 20 +-
.../ServiceExtensions/HttpPollySetup.cs | 2 +-
.../ServiceExtensions/SerilogSetup.cs | 37 ++
.../ServiceExtensions/SqlsugarSetup.cs | 45 +-
.../ServiceExtensions/SwaggerSetup.cs | 26 +-
.../Blog.Core.Serilog.Es.csproj | 2 +-
Blog.Core.Serilog/Blog.Core.Serilog.csproj | 13 +
.../LoggerConfigurationExtensions.cs | 121 ++++
.../Utility/SerilogRequestUtility.cs | 34 +
.../Jobs/Job_AccessTrendLog_Quartz.cs | 4 +-
.../QuartzNet/Jobs/Job_OperateLog_Quartz.cs | 17 +-
.../DependencyInjection/DI_Test.cs | 1 -
Blog.Core.sln | 6 +
45 files changed, 1138 insertions(+), 956 deletions(-)
delete mode 100644 Blog.Core.Api/Log4net.config
create mode 100644 Blog.Core.Common/Const/SqlSugarConst.cs
rename Blog.Core.Common/{ => Https}/HttpPolly/HttpPollyHelper.cs (98%)
rename Blog.Core.Common/{ => Https}/HttpPolly/IHttpPollyHelper.cs (96%)
create mode 100644 Blog.Core.Common/Https/RequestIpUtility.cs
create mode 100644 Blog.Core.Common/LogHelper/LogContextExtension.cs
create mode 100644 Blog.Core.Common/LogHelper/LogContextStatic.cs
create mode 100644 Blog.Core.Extensions/ServiceExtensions/SerilogSetup.cs
create mode 100644 Blog.Core.Serilog/Blog.Core.Serilog.csproj
create mode 100644 Blog.Core.Serilog/Extensions/LoggerConfigurationExtensions.cs
create mode 100644 Blog.Core.Serilog/Utility/SerilogRequestUtility.cs
diff --git a/.gitignore b/.gitignore
index b7645c4..4f554be 100644
--- a/.gitignore
+++ b/.gitignore
@@ -356,3 +356,5 @@ Blog.Core/Blog.Core*.xml
Blog.Core.Api/WMBlog.db
Blog.Core.Api/wwwroot/ui/
*.db
+/Blog.Core.Api/WMBlog.db-journal
+Logs
diff --git a/Blog.Core.Api/Blog.Core.Api.csproj b/Blog.Core.Api/Blog.Core.Api.csproj
index 77d681f..3bf6439 100644
--- a/Blog.Core.Api/Blog.Core.Api.csproj
+++ b/Blog.Core.Api/Blog.Core.Api.csproj
@@ -26,21 +26,25 @@
+
+
+
+
@@ -51,8 +55,6 @@
-
-
diff --git a/Blog.Core.Api/Blog.Core.xml b/Blog.Core.Api/Blog.Core.xml
index 89cb321..488903a 100644
--- a/Blog.Core.Api/Blog.Core.xml
+++ b/Blog.Core.Api/Blog.Core.xml
@@ -760,7 +760,7 @@
Values控制器
-
+
ValuesController
diff --git a/Blog.Core.Api/Controllers/ValuesController.cs b/Blog.Core.Api/Controllers/ValuesController.cs
index 1347ca1..677eb13 100644
--- a/Blog.Core.Api/Controllers/ValuesController.cs
+++ b/Blog.Core.Api/Controllers/ValuesController.cs
@@ -1,7 +1,7 @@
using AutoMapper;
using Blog.Core.Common;
using Blog.Core.Common.HttpContextUser;
-using Blog.Core.Common.HttpPolly;
+using Blog.Core.Common.Https.HttpPolly;
using Blog.Core.Common.WebApiClients.HttpApis;
using Blog.Core.EventBus;
using Blog.Core.EventBus.EventHandling;
diff --git a/Blog.Core.Api/Filter/GlobalExceptionFilter.cs b/Blog.Core.Api/Filter/GlobalExceptionFilter.cs
index da119a6..44c6124 100644
--- a/Blog.Core.Api/Filter/GlobalExceptionFilter.cs
+++ b/Blog.Core.Api/Filter/GlobalExceptionFilter.cs
@@ -3,14 +3,10 @@ using Blog.Core.Common.Helper;
using Blog.Core.Common.LogHelper;
using Blog.Core.Hubs;
using Blog.Core.Model;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.SignalR;
-using Microsoft.Extensions.Logging;
using StackExchange.Profiling;
-using System;
namespace Blog.Core.Filter
{
@@ -54,7 +50,7 @@ namespace Blog.Core.Filter
MiniProfiler.Current.CustomTiming("Errors:", json.msg);
- //采用log4net 进行错误日志记录
+ //进行错误日志记录
_loggerHelper.LogError(json.msg + WriteLog(json.msg, context.Exception));
if (AppSettings.app(new string[] { "Middleware", "SignalRSendLog", "Enabled" }).ObjToBool())
{
diff --git a/Blog.Core.Api/Log4net.config b/Blog.Core.Api/Log4net.config
deleted file mode 100644
index 61bd373..0000000
--- a/Blog.Core.Api/Log4net.config
+++ /dev/null
@@ -1,364 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Blog.Core.Api/Program.cs b/Blog.Core.Api/Program.cs
index f5223be..f7790a8 100644
--- a/Blog.Core.Api/Program.cs
+++ b/Blog.Core.Api/Program.cs
@@ -1,20 +1,16 @@
// 以下为asp.net 6.0的写法,如果用5.0,请看Program.five.cs文件
-using System.IdentityModel.Tokens.Jwt;
-using System.Reflection;
-using System.Text;
+
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Blog.Core;
using Blog.Core.Common;
using Blog.Core.Common.Core;
-using Blog.Core.Common.LogHelper;
using Blog.Core.Extensions;
using Blog.Core.Extensions.Apollo;
using Blog.Core.Extensions.Middlewares;
+using Blog.Core.Extensions.ServiceExtensions;
using Blog.Core.Filter;
using Blog.Core.Hubs;
-using Blog.Core.IServices;
-using Blog.Core.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Server.Kestrel.Core;
@@ -22,34 +18,38 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
+using Serilog;
+using System.IdentityModel.Tokens.Jwt;
+using System.Reflection;
+using System.Text;
+using Blog.Core.Common.Https;
+using Blog.Core.Serilog.Utility;
var builder = WebApplication.CreateBuilder(args);
+
+
// 1、配置host与容器
builder.Host
-.UseServiceProviderFactory(new AutofacServiceProviderFactory())
-.ConfigureContainer(builder =>
-{
- builder.RegisterModule(new AutofacModuleRegister());
- builder.RegisterModule();
-})
-.ConfigureLogging((hostingContext, builder) =>
-{
- builder.AddFilter("System", LogLevel.Error);
- builder.AddFilter("Microsoft", LogLevel.Error);
- builder.SetMinimumLevel(LogLevel.Error);
- builder.AddLog4Net(Path.Combine(Directory.GetCurrentDirectory(), "Log4net.config"));
-})
-.ConfigureAppConfiguration((hostingContext, config) =>
-{
- config.Sources.Clear();
- config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false);
- config.AddConfigurationApollo("appsettings.apollo.json");
-});
+ .UseServiceProviderFactory(new AutofacServiceProviderFactory())
+ .ConfigureContainer(builder =>
+ {
+ builder.RegisterModule(new AutofacModuleRegister());
+ builder.RegisterModule();
+ })
+ .ConfigureAppConfiguration((hostingContext, config) =>
+ {
+ config.Sources.Clear();
+ config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false);
+ config.AddConfigurationApollo("appsettings.apollo.json");
+ });
+builder.ConfigureApplication();
// 2、配置服务
builder.Services.AddSingleton(new AppSettings(builder.Configuration));
-builder.Services.AddSingleton(new LogLock(builder.Environment.ContentRootPath));
+
+
+
builder.Services.AddUiFilesZipSetup(builder.Environment);
Permissions.IsUseIds4 = AppSettings.app(new string[] { "Startup", "IdentityServer4", "Enabled" }).ObjToBool();
@@ -62,6 +62,9 @@ builder.Services.AddMemoryCacheSetup();
builder.Services.AddRedisCacheSetup();
builder.Services.AddSqlsugarSetup();
builder.Services.AddDbSetup();
+
+builder.Host.AddSerilogSetup();
+
builder.Services.AddAutoMapperSetup();
builder.Services.AddCorsSetup();
builder.Services.AddMiniProfilerSetup();
@@ -92,34 +95,34 @@ builder.Services.AddIpPolicyRateLimitSetup(builder.Configuration);
builder.Services.AddSignalR().AddNewtonsoftJsonProtocol();
builder.Services.AddScoped();
builder.Services.Configure(x => x.AllowSynchronousIO = true)
- .Configure(x => x.AllowSynchronousIO = true);
+ .Configure(x => x.AllowSynchronousIO = true);
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession();
builder.Services.AddHttpPollySetup();
builder.Services.AddControllers(o =>
-{
- o.Filters.Add(typeof(GlobalExceptionsFilter));
- //o.Conventions.Insert(0, new GlobalRouteAuthorizeConvention());
- o.Conventions.Insert(0, new GlobalRoutePrefixFilter(new RouteAttribute(RoutePrefix.Name)));
-})
-.AddNewtonsoftJson(options =>
-{
- options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
- options.SerializerSettings.ContractResolver = new DefaultContractResolver();
- options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
- //options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
- options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
- options.SerializerSettings.Converters.Add(new StringEnumConverter());
-})
-//.AddFluentValidation(config =>
-//{
-// //程序集方式添加验证
-// config.RegisterValidatorsFromAssemblyContaining(typeof(UserRegisterVoValidator));
-// //是否与MvcValidation共存
-// config.DisableDataAnnotationsValidation = true;
-//})
-;
+ {
+ o.Filters.Add(typeof(GlobalExceptionsFilter));
+ //o.Conventions.Insert(0, new GlobalRouteAuthorizeConvention());
+ o.Conventions.Insert(0, new GlobalRoutePrefixFilter(new RouteAttribute(RoutePrefix.Name)));
+ })
+ .AddNewtonsoftJson(options =>
+ {
+ options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
+ options.SerializerSettings.ContractResolver = new DefaultContractResolver();
+ options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
+ //options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
+ options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
+ options.SerializerSettings.Converters.Add(new StringEnumConverter());
+ })
+ //.AddFluentValidation(config =>
+ //{
+ // //程序集方式添加验证
+ // config.RegisterValidatorsFromAssemblyContaining(typeof(UserRegisterVoValidator));
+ // //是否与MvcValidation共存
+ // config.DisableDataAnnotationsValidation = true;
+ //})
+ ;
builder.Services.AddEndpointsApiExplorer();
@@ -159,12 +162,23 @@ app.UseDefaultFiles(defaultFilesOptions);
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseStatusCodePages();
+app.UseSerilogRequestLogging(options =>
+{
+ options.GetLevel = SerilogRequestUtility.GetRequestLevel;
+ options.EnrichDiagnosticContext = (diagnosticContext, httpContext) =>
+ {
+ diagnosticContext.Set("RequestHost", httpContext.Request.Host.Value);
+ diagnosticContext.Set("RequestScheme", httpContext.Request.Scheme);
+ diagnosticContext.Set("RequestIp", httpContext.GetRequestIp());
+ };
+});
app.UseRouting();
if (builder.Configuration.GetValue("AppSettings:UseLoadTest"))
{
app.UseMiddleware();
}
+
app.UseAuthentication();
app.UseAuthorization();
app.UseMiniProfilerMiddleware();
diff --git a/Blog.Core.Api/Startup.cs b/Blog.Core.Api/Startup.cs
index bc1630f..1364d6a 100644
--- a/Blog.Core.Api/Startup.cs
+++ b/Blog.Core.Api/Startup.cs
@@ -39,7 +39,6 @@ namespace Blog.Core
{
// 以下code可能与文章中不一样,对代码做了封装,具体查看右侧 Extensions 文件夹.
services.AddSingleton(new AppSettings(Configuration));
- services.AddSingleton(new LogLock(Env.ContentRootPath));
services.AddUiFilesZipSetup(Env);
Permissions.IsUseIds4 = AppSettings.app(new string[] { "Startup", "IdentityServer4", "Enabled" }).ObjToBool();
diff --git a/Blog.Core.Api/appsettings.json b/Blog.Core.Api/appsettings.json
index 3c11737..c712054 100644
--- a/Blog.Core.Api/appsettings.json
+++ b/Blog.Core.Api/appsettings.json
@@ -1,98 +1,92 @@
{
- "urls": "http://*:9291", //web服务端口,如果用IIS部署,把这个去掉
- "Logging": {
- "LogLevel": {
- "Default": "Information", //加入Default否则log4net本地写入不了日志
- "Blog.Core.AuthHelper.ApiResponseHandler": "Error"
- },
- "Debug": {
- "IncludeScopes": false,
- "LogLevel": {
- "Default": "Warning"
- }
- },
- "Console": {
- "IncludeScopes": false,
- "LogLevel": {
- "Default": "Warning",
- "Microsoft.Hosting.Lifetime": "Debug"
- }
- },
- "Log4Net": {
- "Name": "Blog.Core"
- }
+ "urls": "http://*:9291", //web服务端口,如果用IIS部署,把这个去掉
+ "Serilog": {
+ "MinimumLevel": {
+ "Default": "Debug",
+ "Override": {
+ "Microsoft": "Information",
+ "Microsoft.AspNetCore": "Warning",
+ "System": "Warning",
+ "System.Net.Http.HttpClient": "Warning",
+ "Hangfire": "Information",
+ "Magicodes": "Warning",
+ "DotNetCore.CAP": "Information",
+ "Savorboard.CAP": "Information",
+ "Quartz": "Information"
+ }
+ }
+ },
+ "AllowedHosts": "*",
+ "Redis": {
+ "ConnectionString": "127.0.0.1:6319,password=admin"
+ },
+ "RabbitMQ": {
+ "Enabled": false,
+ "Connection": "118.25.251.13",
+ "UserName": "",
+ "Password": "!",
+ "RetryCount": 3
+ },
+ "Kafka": {
+ "Enabled": false,
+ "Servers": "localhost:9092",
+ "Topic": "blog",
+ "GroupId": "blog-consumer",
+ "NumPartitions": 3 //主题分区数量
+ },
+ "EventBus": {
+ "Enabled": false,
+ "SubscriptionClientName": "Blog.Core"
+ },
+ "AppSettings": {
+ "RedisCachingAOP": {
+ "Enabled": false
},
- "AllowedHosts": "*",
- "Redis": {
- "ConnectionString": "127.0.0.1:6319,password=admin"
+ "MemoryCachingAOP": {
+ "Enabled": true
},
- "RabbitMQ": {
- "Enabled": false,
- "Connection": "118.25.251.13",
- "UserName": "",
- "Password": "!",
- "RetryCount": 3
+ "LogAOP": {
+ "Enabled": true,
+ "LogToFile": {
+ "Enabled": false
+ },
+ "LogToDB": {
+ "Enabled": true
+ }
},
- "Kafka": {
- "Enabled": false,
- "Servers": "localhost:9092",
- "Topic": "blog",
- "GroupId": "blog-consumer",
- "NumPartitions": 3 //主题分区数量
+ "TranAOP": {
+ "Enabled": true
},
- "EventBus": {
- "Enabled": false,
- "SubscriptionClientName": "Blog.Core"
- },
- "AppSettings": {
- "RedisCachingAOP": {
- "Enabled": false
- },
- "MemoryCachingAOP": {
- "Enabled": true
- },
- "LogAOP": {
- "Enabled": true,
- "LogToFile": {
- "Enabled": false
- },
- "LogToDB": {
- "Enabled": true
- }
- },
- "TranAOP": {
- "Enabled": true
- },
- "SqlAOP": {
- "Enabled": true,
- "LogToFile": {
- "Enabled": false
- },
- "LogToDB": {
- "Enabled": false
- },
- "LogToConsole": {
- "Enabled": true
- }
- },
- "Date": "2018-08-28",
- "SeedDBEnabled": true, //只生成表结构
- "SeedDBDataEnabled": true, //生成表,并初始化数据
- "Author": "Blog.Core",
- "SvcName": "", // /svc/blog
- "UseLoadTest": false
+ "SqlAOP": {
+ "Enabled": true,
+ "LogToFile": {
+ "Enabled": true
+ },
+ "LogToDB": {
+ "Enabled": false
+ },
+ "LogToConsole": {
+ "Enabled": true
+ }
},
+ "Date": "2018-08-28",
+ "SeedDBEnabled": true, //只生成表结构
+ "SeedDBDataEnabled": true, //生成表,并初始化数据
+ "Author": "Blog.Core",
+ "SvcName": "", // /svc/blog
+ "UseLoadTest": false
+ },
- // 请配置MainDB为你想要的主库的ConnId值,并设置对应的Enabled为true;
- // *** 单库操作,把 MutiDBEnabled 设为false ***;
- // *** 多库操作,把 MutiDBEnabled 设为true,其他的从库Enabled也为true **;
- // 具体配置看视频:https://www.bilibili.com/video/BV1BJ411B7mn?p=6
-
- "MainDB": "WMBLOG_SQLITE", //当前项目的主库,所对应的连接字符串的Enabled必须为true
- "MutiDBEnabled": false, //是否开启多库模式
- "CQRSEnabled": false, //是否开启读写分离模式,必须是单库模式,且数据库类型一致,比如都是SqlServer
- "DBS": [
- /*
+ // 请配置MainDB为你想要的主库的ConnId值,并设置对应的Enabled为true;
+ // *** 单库操作,把 MutiDBEnabled 设为false ***;
+ // *** 多库操作,把 MutiDBEnabled 设为true,其他的从库Enabled也为true **;
+ // 具体配置看视频:https://www.bilibili.com/video/BV1BJ411B7mn?p=6
+ //Log:日志库;
+ "MainDB": "WMBLOG_SQLITE", //当前项目的主库,所对应的连接字符串的Enabled必须为true
+ "MutiDBEnabled": true, //是否开启多库模式
+ "CQRSEnabled": false, //是否开启读写分离模式,必须是单库模式,且数据库类型一致,比如都是SqlServer
+ "DBS": [
+ /*
对应下边的 DBType
MySql = 0,
SqlServer = 1,
@@ -102,225 +96,232 @@
Dm = 5,//达梦
Kdbndp = 6,//人大金仓
*/
- {
- "ConnId": "WMBLOG_SQLITE",
- "DBType": 2,
- "Enabled": true,
- "HitRate": 50, // 值越大,优先级越高
- "Connection": "WMBlog.db" //sqlite只写数据库名就行
- },
- {
- "ConnId": "WMBLOG_MSSQL_1",
- "DBType": 1,
- "Enabled": false,
- "HitRate": 40,
- "Connection": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=WMBLOG_MSSQL_1;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
- "ProviderName": "System.Data.SqlClient"
- },
- {
- "ConnId": "WMBLOG_MSSQL_2",
- "DBType": 1,
- "Enabled": false,
- "HitRate": 30,
- "Connection": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=WMBLOG_MSSQL_2;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
- "ProviderName": "System.Data.SqlClient"
- },
- {
- "ConnId": "WMBLOG_MYSQL",
- "DBType": 0,
- "Enabled": false,
- "HitRate": 20,
- "Connection": "server=localhost;Database=blog;Uid=root;Pwd=root;Port=3306;Allow User Variables=True;"
- },
- {
- "ConnId": "WMBLOG_MYSQL_2",
- "DBType": 0,
- "Enabled": false,
- "HitRate": 20,
- "Connection": "server=localhost;Database=blogcore001;Uid=root;Pwd=root;Port=3306;Allow User Variables=True;"
- },
- {
- "ConnId": "WMBLOG_ORACLE",
- "DBType": 3,
- "Enabled": false,
- "HitRate": 10,
- "Connection": "Data Source=127.0.0.1/ops;User ID=OPS;Password=123456;Persist Security Info=True;Connection Timeout=60;"
- },
- {
- "ConnId": "WMBLOG_DM",
- "DBType": 5,
- "Enabled": false,
- "HitRate": 10,
- "Connection": "PORT=5236;DATABASE=DAMENG;HOST=localhost;PASSWORD=SYSDBA;USER ID=SYSDBA;"
- },
- {
- "ConnId": "WMBLOG_KDBNDP",
- "DBType": 6,
- "Enabled": false,
- "HitRate": 10,
- "Connection": "Server=127.0.0.1;Port=54321;UID=SYSTEM;PWD=system;database=SQLSUGAR4XTEST1;"
- }
- ],
- "Audience": {
- "Secret": "sdfsdfsrty45634kkhllghtdgdfss345t678fs", //不要太短,16位+
- "SecretFile": "C:\\my-file\\blog.core.audience.secret.txt", //安全。内容就是Secret
- "Issuer": "Blog.Core",
- "Audience": "wr"
+ {
+ "ConnId": "WMBLOG_SQLITE",
+ "DBType": 2,
+ "Enabled": true,
+ "HitRate": 50, // 值越大,优先级越高
+ "Connection": "WMBlog.db" //sqlite只写数据库名就行
},
- "Mongo": {
- "ConnectionString": "mongodb://nosql.data",
- "Database": "BlogCoreDb"
+ {
+ "ConnId": "Log",
+ "DBType": 2,
+ "Enabled": true,
+ "HitRate": 50, // 值越大,优先级越高
+ "Connection": "WMBlogLog.db" //sqlite只写数据库名就行
},
- "Startup": {
- "Domain": "http://localhost:9291",
- "Cors": {
- "PolicyName": "CorsIpAccess", //策略名称
- "EnableAllIPs": false, //当为true时,开放所有IP均可访问。
- // 支持多个域名端口,注意端口号后不要带/斜杆:比如localhost:8000/,是错的
- // 注意,http://127.0.0.1:1818 和 http://localhost:1818 是不一样的
- "IPs": "http://127.0.0.1:2364,http://localhost:2364,http://127.0.0.1:6688,http://localhost:6688"
- },
- "AppConfigAlert": {
- "Enabled": true
- },
- "ApiName": "Blog.Core",
- "IdentityServer4": {
- "Enabled": false, // 这里默认是false,表示使用jwt,如果设置为true,则表示系统使用Ids4模式
- "AuthorizationUrl": "http://localhost:5004", // 认证中心域名
- "ApiName": "blog.core.api" // 资源服务器
- },
- "Authing": {
- "Enabled": false,
- "Issuer": "https://uldr24esx31h-demo.authing.cn/oidc",
- "Audience": "63d51c4205c2849803be5178",
- "JwksUri": "https://uldr24esx31h-demo.authing.cn/oidc/.well-known/jwks.json"
- },
- "RedisMq": {
- "Enabled": false //redis 消息队列
- },
- "MiniProfiler": {
- "Enabled": false //性能分析开启
- },
- "Nacos": {
- "Enabled": false //Nacos注册中心
- }
+ {
+ "ConnId": "WMBLOG_MSSQL_1",
+ "DBType": 1,
+ "Enabled": false,
+ "HitRate": 40,
+ "Connection": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=WMBLOG_MSSQL_1;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
+ "ProviderName": "System.Data.SqlClient"
},
- "Middleware": {
- "RequestResponseLog": {
- "Enabled": true,
- "LogToFile": {
- "Enabled": false
- },
- "LogToDB": {
- "Enabled": true
- }
- },
- "IPLog": {
- "Enabled": true,
- "LogToFile": {
- "Enabled": false
- },
- "LogToDB": {
- "Enabled": true
- }
- },
- "RecordAccessLogs": {
- "Enabled": true,
- "LogToFile": {
- "Enabled": false
- },
- "LogToDB": {
- "Enabled": true
- },
- "IgnoreApis": "/api/permission/getnavigationbar,/api/monitor/getids4users,/api/monitor/getaccesslogs,/api/monitor/server,/api/monitor/getactiveusers,/api/monitor/server,"
- },
- "SignalR": {
- "Enabled": false
- },
- "SignalRSendLog": {
- "Enabled": false
- },
- "QuartzNetJob": {
- "Enabled": true
- },
- "Consul": {
- "Enabled": false
- },
- "IpRateLimit": {
- "Enabled": true
- }
+ {
+ "ConnId": "WMBLOG_MSSQL_2",
+ "DBType": 1,
+ "Enabled": false,
+ "HitRate": 30,
+ "Connection": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=WMBLOG_MSSQL_2;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
+ "ProviderName": "System.Data.SqlClient"
},
- "IpRateLimiting": {
- "EnableEndpointRateLimiting": true, //False: globally executed, true: executed for each
- "StackBlockedRequests": false, //False: Number of rejections should be recorded on another counter
- "RealIpHeader": "X-Real-IP",
- "ClientIdHeader": "X-ClientId",
- "IpWhitelist": [], //白名单
- "EndpointWhitelist": [ "get:/api/xxx", "*:/api/yyy" ],
- "ClientWhitelist": [ "dev-client-1", "dev-client-2" ],
- "QuotaExceededResponse": {
- "Content": "{{\"status\":429,\"msg\":\"访问过于频繁,请稍后重试\",\"success\":false}}",
- "ContentType": "application/json",
- "StatusCode": 429
- },
- "HttpStatusCode": 429, //返回状态码
- "GeneralRules": [ //api规则,结尾一定要带*
- {
- "Endpoint": "*:/api/blog*",
- "Period": "1m",
- "Limit": 20
- },
- {
- "Endpoint": "*/api/*",
- "Period": "1s",
- "Limit": 3
- },
- {
- "Endpoint": "*/api/*",
- "Period": "1m",
- "Limit": 30
- },
- {
- "Endpoint": "*/api/*",
- "Period": "12h",
- "Limit": 500
- }
- ]
-
+ {
+ "ConnId": "WMBLOG_MYSQL",
+ "DBType": 0,
+ "Enabled": false,
+ "HitRate": 20,
+ "Connection": "server=localhost;Database=blog;Uid=root;Pwd=root;Port=3306;Allow User Variables=True;"
},
- "ConsulSetting": {
- "ServiceName": "BlogCoreService",
- "ServiceIP": "localhost",
- "ServicePort": "9291",
- "ServiceHealthCheck": "/healthcheck",
- "ConsulAddress": "http://localhost:8500"
+ {
+ "ConnId": "WMBLOG_MYSQL_2",
+ "DBType": 0,
+ "Enabled": false,
+ "HitRate": 20,
+ "Connection": "server=localhost;Database=blogcore001;Uid=root;Pwd=root;Port=3306;Allow User Variables=True;"
},
- "PayInfo": { //建行聚合支付信息
- "MERCHANTID": "", //商户号
- "POSID": "", //柜台号
- "BRANCHID": "", //分行号
- "pubKey": "", //公钥
- "USER_ID": "", //操作员号
- "PASSWORD": "", //密码
- "OutAddress": "http://127.0.0.1:12345" //外联地址
+ {
+ "ConnId": "WMBLOG_ORACLE",
+ "DBType": 3,
+ "Enabled": false,
+ "HitRate": 10,
+ "Connection": "Data Source=127.0.0.1/ops;User ID=OPS;Password=123456;Persist Security Info=True;Connection Timeout=60;"
},
- "nacos": {
- "ServerAddresses": [ "http://localhost:8848" ], // nacos 连接地址
- "DefaultTimeOut": 15000, // 默认超时时间
- "Namespace": "public", // 命名空间
- "ListenInterval": 10000, // 监听的频率
- "ServiceName": "blog.Core.Api", // 服务名
- "Port": "9291", // 服务端口号
- "RegisterEnabled": true // 是否直接注册nacos
+ {
+ "ConnId": "WMBLOG_DM",
+ "DBType": 5,
+ "Enabled": false,
+ "HitRate": 10,
+ "Connection": "PORT=5236;DATABASE=DAMENG;HOST=localhost;PASSWORD=SYSDBA;USER ID=SYSDBA;"
},
- "LogFiedOutPutConfigs": {
- "tcpAddressHost": "", // 输出elk的tcp连接地址
- "tcpAddressPort": 0, // 输出elk的tcp端口号
- "ConfigsInfo": [ // 配置的输出elk节点内容 常用语动态标识
- {
- "FiedName": "applicationName",
- "FiedValue": "Blog.Core.Api"
- }
- ]
+ {
+ "ConnId": "WMBLOG_KDBNDP",
+ "DBType": 6,
+ "Enabled": false,
+ "HitRate": 10,
+ "Connection": "Server=127.0.0.1;Port=54321;UID=SYSTEM;PWD=system;database=SQLSUGAR4XTEST1;"
}
+ ],
+ "Audience": {
+ "Secret": "sdfsdfsrty45634kkhllghtdgdfss345t678fs", //不要太短,16位+
+ "SecretFile": "C:\\my-file\\blog.core.audience.secret.txt", //安全。内容就是Secret
+ "Issuer": "Blog.Core",
+ "Audience": "wr"
+ },
+ "Mongo": {
+ "ConnectionString": "mongodb://nosql.data",
+ "Database": "BlogCoreDb"
+ },
+ "Startup": {
+ "Domain": "http://localhost:9291",
+ "Cors": {
+ "PolicyName": "CorsIpAccess", //策略名称
+ "EnableAllIPs": false, //当为true时,开放所有IP均可访问。
+ // 支持多个域名端口,注意端口号后不要带/斜杆:比如localhost:8000/,是错的
+ // 注意,http://127.0.0.1:1818 和 http://localhost:1818 是不一样的
+ "IPs": "http://127.0.0.1:2364,http://localhost:2364,http://127.0.0.1:6688,http://localhost:6688"
+ },
+ "AppConfigAlert": {
+ "Enabled": true
+ },
+ "ApiName": "Blog.Core",
+ "IdentityServer4": {
+ "Enabled": false, // 这里默认是false,表示使用jwt,如果设置为true,则表示系统使用Ids4模式
+ "AuthorizationUrl": "http://localhost:5004", // 认证中心域名
+ "ApiName": "blog.core.api" // 资源服务器
+ },
+ "Authing": {
+ "Enabled": false,
+ "Issuer": "https://uldr24esx31h-demo.authing.cn/oidc",
+ "Audience": "63d51c4205c2849803be5178",
+ "JwksUri": "https://uldr24esx31h-demo.authing.cn/oidc/.well-known/jwks.json"
+ },
+ "RedisMq": {
+ "Enabled": false //redis 消息队列
+ },
+ "MiniProfiler": {
+ "Enabled": false //性能分析开启
+ },
+ "Nacos": {
+ "Enabled": false //Nacos注册中心
+ }
+ },
+ "Middleware": {
+ "RequestResponseLog": {
+ "Enabled": true,
+ "LogToFile": {
+ "Enabled": false
+ },
+ "LogToDB": {
+ "Enabled": true
+ }
+ },
+ "IPLog": {
+ "Enabled": true,
+ "LogToFile": {
+ "Enabled": false
+ },
+ "LogToDB": {
+ "Enabled": true
+ }
+ },
+ "RecordAccessLogs": {
+ "Enabled": true,
+ "LogToFile": {
+ "Enabled": false
+ },
+ "LogToDB": {
+ "Enabled": true
+ },
+ "IgnoreApis": "/api/permission/getnavigationbar,/api/monitor/getids4users,/api/monitor/getaccesslogs,/api/monitor/server,/api/monitor/getactiveusers,/api/monitor/server,"
+ },
+ "SignalR": {
+ "Enabled": false
+ },
+ "SignalRSendLog": {
+ "Enabled": false
+ },
+ "QuartzNetJob": {
+ "Enabled": true
+ },
+ "Consul": {
+ "Enabled": false
+ },
+ "IpRateLimit": {
+ "Enabled": true
+ }
+ },
+ "IpRateLimiting": {
+ "EnableEndpointRateLimiting": true, //False: globally executed, true: executed for each
+ "StackBlockedRequests": false, //False: Number of rejections should be recorded on another counter
+ "RealIpHeader": "X-Real-IP",
+ "ClientIdHeader": "X-ClientId",
+ "IpWhitelist": [], //白名单
+ "EndpointWhitelist": [ "get:/api/xxx", "*:/api/yyy" ],
+ "ClientWhitelist": [ "dev-client-1", "dev-client-2" ],
+ "QuotaExceededResponse": {
+ "Content": "{{\"status\":429,\"msg\":\"访问过于频繁,请稍后重试\",\"success\":false}}",
+ "ContentType": "application/json",
+ "StatusCode": 429
+ },
+ "HttpStatusCode": 429, //返回状态码
+ "GeneralRules": [ //api规则,结尾一定要带*
+ {
+ "Endpoint": "*:/api/blog*",
+ "Period": "1m",
+ "Limit": 20
+ },
+ {
+ "Endpoint": "*/api/*",
+ "Period": "1s",
+ "Limit": 3
+ },
+ {
+ "Endpoint": "*/api/*",
+ "Period": "1m",
+ "Limit": 30
+ },
+ {
+ "Endpoint": "*/api/*",
+ "Period": "12h",
+ "Limit": 500
+ }
+ ]
+
+ },
+ "ConsulSetting": {
+ "ServiceName": "BlogCoreService",
+ "ServiceIP": "localhost",
+ "ServicePort": "9291",
+ "ServiceHealthCheck": "/healthcheck",
+ "ConsulAddress": "http://localhost:8500"
+ },
+ "PayInfo": { //建行聚合支付信息
+ "MERCHANTID": "", //商户号
+ "POSID": "", //柜台号
+ "BRANCHID": "", //分行号
+ "pubKey": "", //公钥
+ "USER_ID": "", //操作员号
+ "PASSWORD": "", //密码
+ "OutAddress": "http://127.0.0.1:12345" //外联地址
+ },
+ "nacos": {
+ "ServerAddresses": [ "http://localhost:8848" ], // nacos 连接地址
+ "DefaultTimeOut": 15000, // 默认超时时间
+ "Namespace": "public", // 命名空间
+ "ListenInterval": 10000, // 监听的频率
+ "ServiceName": "blog.Core.Api", // 服务名
+ "Port": "9291", // 服务端口号
+ "RegisterEnabled": true // 是否直接注册nacos
+ },
+ "LogFiedOutPutConfigs": {
+ "tcpAddressHost": "", // 输出elk的tcp连接地址
+ "tcpAddressPort": 0, // 输出elk的tcp端口号
+ "ConfigsInfo": [ // 配置的输出elk节点内容 常用语动态标识
+ {
+ "FiedName": "applicationName",
+ "FiedValue": "Blog.Core.Api"
+ }
+ ]
+ }
}
diff --git a/Blog.Core.Api/skyapm.json b/Blog.Core.Api/skyapm.json
index cd5ed0e..cdb0e60 100644
--- a/Blog.Core.Api/skyapm.json
+++ b/Blog.Core.Api/skyapm.json
@@ -11,7 +11,7 @@
},
"Logging": {
"Level": "Information",
- "FilePath": "Log/skyapm-{Date}.log"
+ "FilePath": "Logs/Skyapm/skyapm-{Date}.log"
},
"Transport": {
"Interval": 3000,
diff --git a/Blog.Core.Common/App.cs b/Blog.Core.Common/App.cs
index 008aea5..c2e2e70 100644
--- a/Blog.Core.Common/App.cs
+++ b/Blog.Core.Common/App.cs
@@ -1,14 +1,24 @@
using Blog.Core.Common.Core;
using Blog.Core.Common.HttpContextUser;
+using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Options;
using System;
+using System.Linq;
namespace Blog.Core.Common;
public class App
{
- public static IServiceProvider RootServices => InternalApp.RootServices ;
+ public static IServiceProvider RootServices => InternalApp.RootServices;
+
+ /// 获取Web主机环境,如,是否是开发环境,生产环境等
+ public static IWebHostEnvironment WebHostEnvironment => InternalApp.WebHostEnvironment;
+
+ /// 获取泛型主机环境,如,是否是开发环境,生产环境等
+ public static IHostEnvironment HostEnvironment => InternalApp.HostEnvironment;
///
/// 获取请求上下文
@@ -16,4 +26,55 @@ public class App
public static HttpContext HttpContext => RootServices?.GetService()?.HttpContext;
public static IUser User => HttpContext == null ? null : RootServices?.GetService();
+
+ /// 解析服务提供器
+ ///
+ ///
+ public static IServiceProvider GetServiceProvider(Type serviceType, bool mustBuild = false)
+ {
+ if (App.HostEnvironment == null || App.RootServices != null &&
+ InternalApp.InternalServices
+ .Where((u => u.ServiceType == (serviceType.IsGenericType ? serviceType.GetGenericTypeDefinition() : serviceType)))
+ .Any((u => u.Lifetime == ServiceLifetime.Singleton)))
+ return App.RootServices;
+ HttpContext httpContext = App.HttpContext;
+ if (httpContext?.RequestServices != null)
+ return httpContext.RequestServices;
+ if (App.RootServices != null)
+ {
+ IServiceScope scope = App.RootServices.CreateScope();
+ return scope.ServiceProvider;
+ }
+
+ if (mustBuild)
+ {
+ throw new ApplicationException("当前不可用,必须要等到 WebApplication Build后");
+ }
+
+ ServiceProvider serviceProvider = InternalApp.InternalServices.BuildServiceProvider();
+ return serviceProvider;
+ }
+
+
+ public static TService GetService(bool mustBuild = true) where TService : class => App.GetService(typeof(TService), null, mustBuild) as TService;
+
+ /// 获取请求生存周期的服务
+ ///
+ ///
+ ///
+ ///
+ public static TService GetService(IServiceProvider serviceProvider, bool mustBuild = true) where TService : class => App.GetService(typeof(TService), serviceProvider, mustBuild) as TService;
+
+ /// 获取请求生存周期的服务
+ ///
+ ///
+ ///
+ ///
+ public static object GetService(Type type, IServiceProvider serviceProvider = null, bool mustBuild = true) => (serviceProvider ?? App.GetServiceProvider(type, mustBuild)).GetService(type);
+
+ public static TOptions GetOptions(IServiceProvider serviceProvider = null) where TOptions : class, new()
+ {
+ IOptions service = App.GetService>(serviceProvider ?? App.RootServices, false);
+ return service?.Value;
+ }
}
\ No newline at end of file
diff --git a/Blog.Core.Common/Blog.Core.Common.csproj b/Blog.Core.Common/Blog.Core.Common.csproj
index fc0abb9..0662bac 100644
--- a/Blog.Core.Common/Blog.Core.Common.csproj
+++ b/Blog.Core.Common/Blog.Core.Common.csproj
@@ -18,20 +18,23 @@
-
+
-
+
+
+
+
+
-
-
-
+
+
@@ -45,6 +48,7 @@
+
diff --git a/Blog.Core.Common/Const/SqlSugarConst.cs b/Blog.Core.Common/Const/SqlSugarConst.cs
new file mode 100644
index 0000000..f5efd7e
--- /dev/null
+++ b/Blog.Core.Common/Const/SqlSugarConst.cs
@@ -0,0 +1,9 @@
+namespace Blog.Core.Common.Const;
+
+public class SqlSugarConst
+{
+ ///
+ /// 默认Log数据库标识
+ ///
+ public const string LogConfigId = "Log";
+}
\ No newline at end of file
diff --git a/Blog.Core.Common/Core/InternalApp.cs b/Blog.Core.Common/Core/InternalApp.cs
index c1ae8dc..62e0472 100644
--- a/Blog.Core.Common/Core/InternalApp.cs
+++ b/Blog.Core.Common/Core/InternalApp.cs
@@ -1,17 +1,34 @@
-using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
using System;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
namespace Blog.Core.Common.Core;
public static class InternalApp
{
+ public static IServiceCollection InternalServices;
+
/// 根服务
public static IServiceProvider RootServices;
- public static void ConfigureApplication(this WebApplication app)
- {
- app.Lifetime.ApplicationStarted.Register(() => { InternalApp.RootServices = app.Services; });
+ /// 获取Web主机环境
+ public static IWebHostEnvironment WebHostEnvironment;
- app.Lifetime.ApplicationStopped.Register(() => { InternalApp.RootServices = null; });
+ /// 获取泛型主机环境
+ public static IHostEnvironment HostEnvironment;
+
+ public static void ConfigureApplication(this WebApplicationBuilder wab)
+ {
+ HostEnvironment = wab.Environment;
+ WebHostEnvironment = wab.Environment;
+ InternalServices = wab.Services;
+ }
+
+
+ public static void ConfigureApplication(this IHost app)
+ {
+ RootServices = app.Services;
}
}
\ No newline at end of file
diff --git a/Blog.Core.Common/DB/Aop/SqlsugarAop.cs b/Blog.Core.Common/DB/Aop/SqlsugarAop.cs
index 3d83b00..c3d374a 100644
--- a/Blog.Core.Common/DB/Aop/SqlsugarAop.cs
+++ b/Blog.Core.Common/DB/Aop/SqlsugarAop.cs
@@ -1,12 +1,40 @@
-using Blog.Core.Model.Models.RootTkey;
+using Blog.Core.Common.LogHelper;
+using Blog.Core.Model.Models.RootTkey;
using Blog.Core.Model.Tenants;
using SqlSugar;
+using StackExchange.Profiling;
using System;
+using Serilog;
namespace Blog.Core.Common.DB.Aop;
public static class SqlSugarAop
{
+ public static void OnLogExecuting(ISqlSugarClient sqlSugarScopeProvider, string sql, SugarParameter[] p, ConnectionConfig config)
+ {
+ try
+ {
+ MiniProfiler.Current.CustomTiming($"ConnId:[{config.ConfigId}] SQL:", GetParas(p) + "【SQL语句】:" + sql);
+
+ if (!AppSettings.app(new string[] { "AppSettings", "SqlAOP", "Enabled" }).ObjToBool()) return;
+
+ if (AppSettings.app(new string[] { "AppSettings", "SqlAOP", "LogToConsole", "Enabled" }).ObjToBool() ||
+ AppSettings.app(new string[] { "AppSettings", "SqlAOP", "LogToFile", "Enabled" }).ObjToBool() ||
+ AppSettings.app(new string[] { "AppSettings", "SqlAOP", "LogToDB", "Enabled" }).ObjToBool())
+ {
+ using (LogContextExtension.Create.SqlAopPushProperty(sqlSugarScopeProvider))
+ {
+ Log.Information("------------------ \r\n ConnId:[{ConnId}]【SQL语句】: \r\n {Sql}",
+ config.ConfigId, UtilMethods.GetSqlString(config.DbType, sql, p));
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Log.Error("Error occured OnLogExcuting:" + e);
+ }
+ }
+
public static void DataExecuting(object oldValue, DataFilterModel entityInfo)
{
if (entityInfo.EntityValue is BaseEntity root)
diff --git a/Blog.Core.Common/DB/BaseDBConfig.cs b/Blog.Core.Common/DB/BaseDBConfig.cs
index 1d86369..d8c3ee5 100644
--- a/Blog.Core.Common/DB/BaseDBConfig.cs
+++ b/Blog.Core.Common/DB/BaseDBConfig.cs
@@ -12,6 +12,7 @@ namespace Blog.Core.Common.DB
* 目前是多库操作,默认加载的是appsettings.json设置为true的第一个db连接。
*/
public static (List allDbs, List slaveDbs) MutiConnectionString => MutiInitConn();
+ public static ConnectionConfig LogConfig; //日志库
private static string DifDBConnOfSecurity(params string[] conn)
{
@@ -107,8 +108,6 @@ namespace Blog.Core.Common.DB
return mutiDBOperate;
}
-
-
}
diff --git a/Blog.Core.Common/Helper/RecursionHelper.cs b/Blog.Core.Common/Helper/RecursionHelper.cs
index 9b27a37..b4cbd68 100644
--- a/Blog.Core.Common/Helper/RecursionHelper.cs
+++ b/Blog.Core.Common/Helper/RecursionHelper.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Linq;
namespace Blog.Core.Common.Helper
@@ -8,9 +9,8 @@ namespace Blog.Core.Common.Helper
///
public static class RecursionHelper
{
- public static void LoopToAppendChildren(List all, PermissionTree curItem, int pid, bool needbtn)
+ public static void LoopToAppendChildren(List all, PermissionTree curItem, long pid, bool needbtn)
{
-
var subItems = all.Where(ee => ee.Pid == curItem.value).ToList();
var btnItems = subItems.Where(ss => ss.isbtn == true).ToList();
@@ -28,6 +28,7 @@ namespace Blog.Core.Common.Helper
{
subItems = subItems.Where(ss => ss.isbtn == false).ToList();
}
+
if (subItems.Count > 0)
{
curItem.children = new List();
@@ -49,14 +50,15 @@ namespace Blog.Core.Common.Helper
{
//subItem.disabled = true;//禁用当前节点
}
+
LoopToAppendChildren(all, subItem, pid, needbtn);
}
}
+
public static void LoopToAppendChildren(List all, DepartmentTree curItem, int pid)
{
-
var subItems = all.Where(ee => ee.Pid == curItem.value).ToList();
-
+
if (subItems.Count > 0)
{
curItem.children = new List();
@@ -73,15 +75,14 @@ namespace Blog.Core.Common.Helper
{
//subItem.disabled = true;//禁用当前节点
}
+
LoopToAppendChildren(all, subItem, pid);
}
}
-
public static void LoopNaviBarAppendChildren(List all, NavigationBar curItem)
{
-
var subItems = all.Where(ee => ee.pid == curItem.id).ToList();
if (subItems.Count > 0)
@@ -102,7 +103,6 @@ namespace Blog.Core.Common.Helper
}
-
public static void LoopToAppendChildrenT(List all, T curItem, string parentIdName = "Pid", string idName = "value", string childrenName = "children")
{
var subItems = all.Where(ee => ee.GetType().GetProperty(parentIdName).GetValue(ee, null).ToString() == curItem.GetType().GetProperty(idName).GetValue(curItem, null).ToString()).ToList();
@@ -113,12 +113,47 @@ namespace Blog.Core.Common.Helper
LoopToAppendChildrenT(all, subItem);
}
}
+
+ ///
+ /// 将父子级数据结构转换为普通list
+ ///
+ ///
+ ///
+ public static List TreeToList(List list, Action> action = null)
+ {
+ List results = new List();
+ foreach (var item in list)
+ {
+ results.Add(item);
+ OperationChildData(results, item, action);
+ }
+
+ return results;
+ }
+
+ ///
+ /// 递归子级数据
+ ///
+ /// 树形列表数据
+ /// Item
+ public static void OperationChildData(List allList, T item, Action> action)
+ {
+ dynamic dynItem = item;
+ if (dynItem.Children == null) return;
+ if (dynItem.Children.Count <= 0) return;
+ allList.AddRange(dynItem.Children);
+ foreach (var subItem in dynItem.Children)
+ {
+ action?.Invoke(item, subItem, allList);
+ OperationChildData(allList, subItem, action);
+ }
+ }
}
public class PermissionTree
{
- public int value { get; set; }
- public int Pid { get; set; }
+ public long value { get; set; }
+ public long Pid { get; set; }
public string label { get; set; }
public int order { get; set; }
public bool isbtn { get; set; }
@@ -139,8 +174,8 @@ namespace Blog.Core.Common.Helper
public class NavigationBar
{
- public int id { get; set; }
- public int pid { get; set; }
+ public long id { get; set; }
+ public long pid { get; set; }
public int order { get; set; }
public string name { get; set; }
public bool IsHide { get; set; } = false;
@@ -158,15 +193,13 @@ namespace Blog.Core.Common.Helper
public bool requireAuth { get; set; } = true;
public bool NoTabPage { get; set; } = false;
public bool keepAlive { get; set; } = false;
-
-
}
public class NavigationBarPro
{
- public int id { get; set; }
- public int parentId { get; set; }
+ public long id { get; set; }
+ public long parentId { get; set; }
public int order { get; set; }
public string name { get; set; }
public bool IsHide { get; set; } = false;
@@ -184,4 +217,4 @@ namespace Blog.Core.Common.Helper
public string icon { get; set; }
public bool show { get; set; } = false;
}
-}
+}
\ No newline at end of file
diff --git a/Blog.Core.Common/HttpPolly/HttpPollyHelper.cs b/Blog.Core.Common/Https/HttpPolly/HttpPollyHelper.cs
similarity index 98%
rename from Blog.Core.Common/HttpPolly/HttpPollyHelper.cs
rename to Blog.Core.Common/Https/HttpPolly/HttpPollyHelper.cs
index f1a1e84..1187d71 100644
--- a/Blog.Core.Common/HttpPolly/HttpPollyHelper.cs
+++ b/Blog.Core.Common/Https/HttpPolly/HttpPollyHelper.cs
@@ -6,7 +6,7 @@ using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
-namespace Blog.Core.Common.HttpPolly
+namespace Blog.Core.Common.Https.HttpPolly
{
public class HttpPollyHelper : IHttpPollyHelper
{
@@ -35,7 +35,7 @@ namespace Blog.Core.Common.HttpPolly
var stringContent = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json");
var response = await client.PostAsync(url, stringContent);
-
+
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
string result = await response.Content.ReadAsStringAsync();
@@ -72,7 +72,7 @@ namespace Blog.Core.Common.HttpPolly
var stringContent = new StringContent(request, Encoding.UTF8, "application/json");
var response = await client.PostAsync(url, stringContent);
-
+
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
string result = await response.Content.ReadAsStringAsync();
@@ -110,7 +110,7 @@ namespace Blog.Core.Common.HttpPolly
var stringContent = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json");
var response = await client.PostAsync(url, stringContent);
-
+
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
return await response.Content.ReadAsStringAsync();
@@ -146,7 +146,7 @@ namespace Blog.Core.Common.HttpPolly
var stringContent = new StringContent(request, Encoding.UTF8, "application/json");
var response = await client.PostAsync(url, stringContent);
-
+
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
return await response.Content.ReadAsStringAsync();
@@ -182,7 +182,7 @@ namespace Blog.Core.Common.HttpPolly
}
var response = await client.GetAsync(url);
-
+
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
string result = await response.Content.ReadAsStringAsync();
@@ -219,7 +219,7 @@ namespace Blog.Core.Common.HttpPolly
}
var response = await client.GetAsync(url);
-
+
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
return await response.Content.ReadAsStringAsync(); ;
@@ -256,7 +256,7 @@ namespace Blog.Core.Common.HttpPolly
var stringContent = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json");
var response = await client.PutAsync(url, stringContent);
-
+
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
string result = await response.Content.ReadAsStringAsync();
@@ -294,7 +294,7 @@ namespace Blog.Core.Common.HttpPolly
var stringContent = new StringContent(request, Encoding.UTF8, "application/json");
var response = await client.PutAsync(url, stringContent);
-
+
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
string result = await response.Content.ReadAsStringAsync();
@@ -331,7 +331,7 @@ namespace Blog.Core.Common.HttpPolly
}
var response = await client.DeleteAsync(url);
-
+
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
string result = await response.Content.ReadAsStringAsync();
diff --git a/Blog.Core.Common/HttpPolly/IHttpPollyHelper.cs b/Blog.Core.Common/Https/HttpPolly/IHttpPollyHelper.cs
similarity index 96%
rename from Blog.Core.Common/HttpPolly/IHttpPollyHelper.cs
rename to Blog.Core.Common/Https/HttpPolly/IHttpPollyHelper.cs
index a3c8b3f..da8bd5a 100644
--- a/Blog.Core.Common/HttpPolly/IHttpPollyHelper.cs
+++ b/Blog.Core.Common/Https/HttpPolly/IHttpPollyHelper.cs
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
-namespace Blog.Core.Common.HttpPolly
+namespace Blog.Core.Common.Https.HttpPolly
{
public interface IHttpPollyHelper
{
diff --git a/Blog.Core.Common/Https/RequestIpUtility.cs b/Blog.Core.Common/Https/RequestIpUtility.cs
new file mode 100644
index 0000000..ac7e28f
--- /dev/null
+++ b/Blog.Core.Common/Https/RequestIpUtility.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using Microsoft.AspNetCore.Http;
+
+namespace Blog.Core.Common.Https;
+
+public static class RequestIpUtility
+{
+ public static string GetRequestIp(this HttpContext context)
+ {
+ string ip = SplitCsv(GetHeaderValueAs(context, "X-Forwarded-For")).FirstOrDefault();
+
+ if (string.IsNullOrWhiteSpace(ip))
+ ip = SplitCsv(GetHeaderValueAs(context, "X-Real-IP")).FirstOrDefault();
+
+ if (string.IsNullOrWhiteSpace(ip) && context.Connection?.RemoteIpAddress != null)
+ ip = context.Connection.RemoteIpAddress.ToString();
+
+ if (string.IsNullOrWhiteSpace(ip))
+ ip = GetHeaderValueAs(context, "REMOTE_ADDR");
+
+ return ip;
+ }
+
+ public static bool IsLocal(this HttpContext context)
+ {
+ return GetRequestIp(context) is "127.0.0.1" or "::1" || context.Request?.IsLocal() == true;
+ }
+
+
+ public static bool IsLocal(this HttpRequest req)
+ {
+ var connection = req.HttpContext.Connection;
+ if (connection.RemoteIpAddress != null)
+ {
+ if (connection.LocalIpAddress != null)
+ {
+ return connection.RemoteIpAddress.Equals(connection.LocalIpAddress);
+ }
+ else
+ {
+ return IPAddress.IsLoopback(connection.RemoteIpAddress);
+ }
+ }
+
+ // for in memory TestServer or when dealing with default connection info
+ if (connection.RemoteIpAddress == null && connection.LocalIpAddress == null)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+
+ private static T GetHeaderValueAs(HttpContext context, string headerName)
+ {
+ if (context.Request?.Headers?.TryGetValue(headerName, out var values) ?? false)
+ {
+ string rawValues = values.ToString();
+
+ if (!string.IsNullOrWhiteSpace(rawValues))
+ return (T) Convert.ChangeType(values.ToString(), typeof(T));
+ }
+
+ return default;
+ }
+
+ private static List SplitCsv(string csvList)
+ {
+ if (string.IsNullOrWhiteSpace(csvList))
+ return new List();
+
+ return csvList
+ .TrimEnd(',')
+ .Split(',')
+ .AsEnumerable()
+ .Select(s => s.Trim())
+ .ToList();
+ }
+}
\ No newline at end of file
diff --git a/Blog.Core.Common/Hubs/ChatHub.cs b/Blog.Core.Common/Hubs/ChatHub.cs
index ff15c97..1c58c8a 100644
--- a/Blog.Core.Common/Hubs/ChatHub.cs
+++ b/Blog.Core.Common/Hubs/ChatHub.cs
@@ -83,7 +83,8 @@ namespace Blog.Core.Hubs
//2、服务端主动向客户端发送数据,名字千万不能错
if (AppSettings.app(new string[] { "Middleware", "SignalRSendLog", "Enabled" }).ObjToBool())
{
- await Clients.All.ReceiveUpdate(LogLock.GetLogData());
+ //TODO 主动发送错误消息
+ //await Clients.All.ReceiveUpdate(LogLock.GetLogData());
}
diff --git a/Blog.Core.Common/LogHelper/LogContextExtension.cs b/Blog.Core.Common/LogHelper/LogContextExtension.cs
new file mode 100644
index 0000000..bce80cb
--- /dev/null
+++ b/Blog.Core.Common/LogHelper/LogContextExtension.cs
@@ -0,0 +1,42 @@
+using Serilog.Context;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+
+namespace Blog.Core.Common.LogHelper;
+
+public class LogContextExtension : IDisposable
+{
+ private readonly Stack _disposableStack = new Stack();
+
+ public static LogContextExtension Create => new();
+
+ public void AddStock(IDisposable disposable)
+ {
+ _disposableStack.Push(disposable);
+ }
+
+ public IDisposable SqlAopPushProperty(ISqlSugarClient db)
+ {
+ AddStock(LogContext.PushProperty(LogContextStatic.LogSource, LogContextStatic.AopSql));
+ AddStock(LogContext.PushProperty(LogContextStatic.SqlOutToConsole,
+ AppSettings.app(new string[] { "AppSettings", "SqlAOP", "LogToConsole", "Enabled" }).ObjToBool()));
+ AddStock(LogContext.PushProperty(LogContextStatic.SqlOutToFile,
+ AppSettings.app(new string[] { "AppSettings", "SqlAOP", "LogToFile", "Enabled" }).ObjToBool()));
+ AddStock(LogContext.PushProperty(LogContextStatic.OutToDb,
+ AppSettings.app(new string[] { "AppSettings", "SqlAOP", "LogToDb", "Enabled" }).ObjToBool()));
+
+ AddStock(LogContext.PushProperty(LogContextStatic.SugarActionType, db.SugarActionType));
+
+ return this;
+ }
+
+
+ public void Dispose()
+ {
+ while (_disposableStack.Count > 0)
+ {
+ _disposableStack.Pop().Dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Blog.Core.Common/LogHelper/LogContextStatic.cs b/Blog.Core.Common/LogHelper/LogContextStatic.cs
new file mode 100644
index 0000000..52a8167
--- /dev/null
+++ b/Blog.Core.Common/LogHelper/LogContextStatic.cs
@@ -0,0 +1,42 @@
+using System.IO;
+
+namespace Blog.Core.Common.LogHelper;
+
+public class LogContextStatic
+{
+ static LogContextStatic()
+ {
+ if (!Directory.Exists(BaseLogs))
+ {
+ Directory.CreateDirectory(BaseLogs);
+ }
+ }
+
+ public static readonly string BaseLogs = "Logs";
+ public static readonly string BasePathLogs = @"Logs";
+
+ public static readonly string LogSource = "LogSource";
+ public static readonly string AopSql = "AopSql";
+ public static readonly string SqlOutToConsole = "OutToConsole";
+ public static readonly string SqlOutToFile = "SqlOutToFile";
+ public static readonly string OutToDb = "OutToDb";
+ public static readonly string SugarActionType = "SugarActionType";
+
+ public static readonly string FileMessageTemplate = "{NewLine}Date:{Timestamp:yyyy-MM-dd HH:mm:ss.fff}{NewLine}LogLevel:{Level}{NewLine}Message:{Message}{NewLine}{Exception}" + new string('-', 100);
+
+
+ public static string Combine(string path1)
+ {
+ return Path.Combine(BaseLogs, path1);
+ }
+
+ public static string Combine(string path1, string path2)
+ {
+ return Path.Combine(BaseLogs, path1, path2);
+ }
+
+ public static string Combine(string path1, string path2, string path3)
+ {
+ return Path.Combine(BaseLogs, path1, path2, path3);
+ }
+}
\ No newline at end of file
diff --git a/Blog.Core.Common/LogHelper/LogLock.cs b/Blog.Core.Common/LogHelper/LogLock.cs
index 70c5f7f..2c9be9a 100644
--- a/Blog.Core.Common/LogHelper/LogLock.cs
+++ b/Blog.Core.Common/LogHelper/LogLock.cs
@@ -1,5 +1,4 @@
using Blog.Core.Common.Helper;
-using log4net;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
@@ -7,12 +6,12 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
+using Serilog;
namespace Blog.Core.Common.LogHelper
{
public class LogLock
{
- private static readonly ILog log = LogManager.GetLogger(typeof(LogLock));
static ReaderWriterLockSlim LogWriteLock = new ReaderWriterLockSlim();
static int WritedCount = 0;
static int FailedCount = 0;
@@ -53,12 +52,14 @@ namespace Blog.Core.Common.LogHelper
default:
break;
}
+
if (AppSettings.app(new string[] { AppSetingNodeName, AppSetingName, "Enabled" }).ObjToBool())
{
if (AppSettings.app(new string[] { AppSetingNodeName, AppSetingName, "LogToDB", "Enabled" }).ObjToBool())
{
OutSql2LogToDB(prefix, traceId, dataParas, IsHeader);
}
+
if (AppSettings.app(new string[] { AppSetingNodeName, AppSetingName, "LogToFile", "Enabled" }).ObjToBool())
{
OutSql2LogToFile(prefix, traceId, dataParas, IsHeader);
@@ -90,6 +91,7 @@ namespace Blog.Core.Common.LogHelper
{
Directory.CreateDirectory(folderPath);
}
+
//string logFilePath = Path.Combine(path, $@"{filename}.log");
var logFilePath = FileHelper.GetAvailableFileWithPrefixOrderSize(folderPath, prefix);
switch (prefix)
@@ -98,47 +100,48 @@ namespace Blog.Core.Common.LogHelper
AOPLogInfo apiLogAopInfo = JsonConvert.DeserializeObject(dataParas[1]);
//记录被拦截方法信息的日志信息
var dataIntercept = "" +
- $"【操作时间】:{apiLogAopInfo.RequestTime}\r\n" +
- $"【当前操作用户】:{ apiLogAopInfo.OpUserName} \r\n" +
- $"【当前执行方法】:{ apiLogAopInfo.RequestMethodName} \r\n" +
- $"【携带的参数有】: {apiLogAopInfo.RequestParamsName} \r\n" +
- $"【携带的参数JSON】: {apiLogAopInfo.RequestParamsData} \r\n" +
- $"【响应时间】:{apiLogAopInfo.ResponseIntervalTime}\r\n" +
- $"【执行完成时间】:{apiLogAopInfo.ResponseTime}\r\n" +
- $"【执行完成结果】:{apiLogAopInfo.ResponseJsonData}\r\n";
+ $"【操作时间】:{apiLogAopInfo.RequestTime}\r\n" +
+ $"【当前操作用户】:{apiLogAopInfo.OpUserName} \r\n" +
+ $"【当前执行方法】:{apiLogAopInfo.RequestMethodName} \r\n" +
+ $"【携带的参数有】: {apiLogAopInfo.RequestParamsName} \r\n" +
+ $"【携带的参数JSON】: {apiLogAopInfo.RequestParamsData} \r\n" +
+ $"【响应时间】:{apiLogAopInfo.ResponseIntervalTime}\r\n" +
+ $"【执行完成时间】:{apiLogAopInfo.ResponseTime}\r\n" +
+ $"【执行完成结果】:{apiLogAopInfo.ResponseJsonData}\r\n";
dataParas = new string[] { dataIntercept };
break;
case "AOPLogEx":
AOPLogExInfo apiLogAopExInfo = JsonConvert.DeserializeObject(dataParas[1]);
var dataInterceptEx = "" +
- $"【操作时间】:{apiLogAopExInfo.ApiLogAopInfo.RequestTime}\r\n" +
- $"【当前操作用户】:{ apiLogAopExInfo.ApiLogAopInfo.OpUserName} \r\n" +
- $"【当前执行方法】:{ apiLogAopExInfo.ApiLogAopInfo.RequestMethodName} \r\n" +
- $"【携带的参数有】: {apiLogAopExInfo.ApiLogAopInfo.RequestParamsName} \r\n" +
- $"【携带的参数JSON】: {apiLogAopExInfo.ApiLogAopInfo.RequestParamsData} \r\n" +
- $"【响应时间】:{apiLogAopExInfo.ApiLogAopInfo.ResponseIntervalTime}\r\n" +
- $"【执行完成时间】:{apiLogAopExInfo.ApiLogAopInfo.ResponseTime}\r\n" +
- $"【执行完成结果】:{apiLogAopExInfo.ApiLogAopInfo.ResponseJsonData}\r\n" +
- $"【执行完成异常信息】:方法中出现异常:{apiLogAopExInfo.ExMessage}\r\n" +
- $"【执行完成异常】:方法中出现异常:{apiLogAopExInfo.InnerException}\r\n";
+ $"【操作时间】:{apiLogAopExInfo.ApiLogAopInfo.RequestTime}\r\n" +
+ $"【当前操作用户】:{apiLogAopExInfo.ApiLogAopInfo.OpUserName} \r\n" +
+ $"【当前执行方法】:{apiLogAopExInfo.ApiLogAopInfo.RequestMethodName} \r\n" +
+ $"【携带的参数有】: {apiLogAopExInfo.ApiLogAopInfo.RequestParamsName} \r\n" +
+ $"【携带的参数JSON】: {apiLogAopExInfo.ApiLogAopInfo.RequestParamsData} \r\n" +
+ $"【响应时间】:{apiLogAopExInfo.ApiLogAopInfo.ResponseIntervalTime}\r\n" +
+ $"【执行完成时间】:{apiLogAopExInfo.ApiLogAopInfo.ResponseTime}\r\n" +
+ $"【执行完成结果】:{apiLogAopExInfo.ApiLogAopInfo.ResponseJsonData}\r\n" +
+ $"【执行完成异常信息】:方法中出现异常:{apiLogAopExInfo.ExMessage}\r\n" +
+ $"【执行完成异常】:方法中出现异常:{apiLogAopExInfo.InnerException}\r\n";
dataParas = new string[] { dataInterceptEx };
break;
}
+
var now = DateTime.Now;
string logContent = String.Join("\r\n", dataParas);
if (IsHeader)
{
logContent = (
- "--------------------------------\r\n" +
- DateTime.Now + "|\r\n" +
- String.Join("\r\n", dataParas) + "\r\n"
- );
+ "--------------------------------\r\n" +
+ DateTime.Now + "|\r\n" +
+ String.Join("\r\n", dataParas) + "\r\n"
+ );
}
else
{
logContent = (
- dataParas[1] + ",\r\n"
- );
+ dataParas[1] + ",\r\n"
+ );
}
//if (logContent.IsNotEmptyOrNull() && logContent.Length > 500)
@@ -148,12 +151,12 @@ namespace Blog.Core.Common.LogHelper
if (isWrt)
{
File.WriteAllText(logFilePath, logContent);
-
}
else
{
File.AppendAllText(logFilePath, logContent);
}
+
WritedCount++;
}
catch (Exception e)
@@ -170,14 +173,15 @@ namespace Blog.Core.Common.LogHelper
LogWriteLock.ExitWriteLock();
}
}
+
public static void OutSql2LogToDB(string prefix, string traceId, string[] dataParas, bool IsHeader = true)
{
- log4net.LogicalThreadContext.Properties["LogType"] = prefix;
- log4net.LogicalThreadContext.Properties["TraceId"] = traceId;
- if (dataParas.Length >= 2)
- {
- log4net.LogicalThreadContext.Properties["DataType"] = dataParas[0];
- }
+ //log4net.LogicalThreadContext.Properties["LogType"] = prefix;
+ //log4net.LogicalThreadContext.Properties["TraceId"] = traceId;
+ //if (dataParas.Length >= 2)
+ //{
+ // log4net.LogicalThreadContext.Properties["DataType"] = dataParas[0];
+ //}
dataParas = dataParas.Skip(1).ToArray();
@@ -186,32 +190,37 @@ namespace Blog.Core.Common.LogHelper
{
logContent = (String.Join("", dataParas));
}
+
switch (prefix)
{
//DEBUG | INFO | WARN | ERROR | FATAL
case "AOPLog":
- log.Info(logContent);
+ //TODO 是否需要输出?
+ //Log.Information(logContent);
break;
case "AOPLogEx":
- log.Error(logContent);
+ Log.Error(logContent);
break;
case "RequestIpInfoLog":
- log.Debug(logContent);
+ //TODO 是否需要Debug输出?
+ //Log.Debug(logContent);
break;
case "RecordAccessLogs":
- log.Debug(logContent);
+ //TODO 是否需要Debug输出?
+ //Log.Debug(logContent);
break;
case "SqlLog":
- log.Info(logContent);
+ Log.Information(logContent);
break;
case "RequestResponseLog":
- log.Debug(logContent);
+ //TODO 是否需要Debug输出?
+ //Log.Debug(logContent);
break;
default:
break;
}
-
}
+
///
/// 读取文件内容
///
@@ -287,6 +296,7 @@ namespace Blog.Core.Common.LogHelper
{
LogWriteLock.ExitReadLock();
}
+
return s;
}
@@ -315,7 +325,6 @@ namespace Blog.Core.Common.LogHelper
}
}
}
-
}
return requestInfos;
@@ -336,16 +345,18 @@ namespace Blog.Core.Common.LogHelper
if (!string.IsNullOrEmpty(aoplogContent))
{
aopLogs = aoplogContent.Split("--------------------------------")
- .Where(d => !string.IsNullOrEmpty(d) && d != "\n" && d != "\r\n")
- .Select(d => new LogInfo
- {
- Datetime = d.Split("|")[0].ObjToDate(),
- Content = d.Split("|")[1]?.Replace("\r\n", "
"),
- LogColor = "AOP",
- }).ToList();
+ .Where(d => !string.IsNullOrEmpty(d) && d != "\n" && d != "\r\n")
+ .Select(d => new LogInfo
+ {
+ Datetime = d.Split("|")[0].ObjToDate(),
+ Content = d.Split("|")[1]?.Replace("\r\n", "
"),
+ LogColor = "AOP",
+ }).ToList();
}
}
- catch (Exception) { }
+ catch (Exception)
+ {
+ }
try
{
@@ -354,17 +365,19 @@ namespace Blog.Core.Common.LogHelper
if (!string.IsNullOrEmpty(exclogContent))
{
excLogs = exclogContent.Split("--------------------------------")
- .Where(d => !string.IsNullOrEmpty(d) && d != "\n" && d != "\r\n")
- .Select(d => new LogInfo
- {
- Datetime = (d.Split("|")[0]).Split(',')[0].ObjToDate(),
- Content = d.Split("|")[1]?.Replace("\r\n", "
"),
- LogColor = "EXC",
- Import = 9,
- }).ToList();
+ .Where(d => !string.IsNullOrEmpty(d) && d != "\n" && d != "\r\n")
+ .Select(d => new LogInfo
+ {
+ Datetime = (d.Split("|")[0]).Split(',')[0].ObjToDate(),
+ Content = d.Split("|")[1]?.Replace("\r\n", "
"),
+ LogColor = "EXC",
+ Import = 9,
+ }).ToList();
}
}
- catch (Exception) { }
+ catch (Exception)
+ {
+ }
try
@@ -374,16 +387,18 @@ namespace Blog.Core.Common.LogHelper
if (!string.IsNullOrEmpty(sqllogContent))
{
sqlLogs = sqllogContent.Split("--------------------------------")
- .Where(d => !string.IsNullOrEmpty(d) && d != "\n" && d != "\r\n")
- .Select(d => new LogInfo
- {
- Datetime = d.Split("|")[0].ObjToDate(),
- Content = d.Split("|")[1]?.Replace("\r\n", "
"),
- LogColor = "SQL",
- }).ToList();
+ .Where(d => !string.IsNullOrEmpty(d) && d != "\n" && d != "\r\n")
+ .Select(d => new LogInfo
+ {
+ Datetime = d.Split("|")[0].ObjToDate(),
+ Content = d.Split("|")[1]?.Replace("\r\n", "
"),
+ LogColor = "SQL",
+ }).ToList();
}
}
- catch (Exception) { }
+ catch (Exception)
+ {
+ }
//try
//{
@@ -422,14 +437,17 @@ namespace Blog.Core.Common.LogHelper
{
aopLogs.AddRange(excLogs);
}
+
if (sqlLogs != null)
{
aopLogs.AddRange(sqlLogs);
}
+
if (reqresLogs != null)
{
aopLogs.AddRange(reqresLogs);
}
+
aopLogs = aopLogs.OrderByDescending(d => d.Import).ThenByDescending(d => d.Datetime).Take(100).ToList();
return aopLogs;
@@ -450,7 +468,8 @@ namespace Blog.Core.Common.LogHelper
Logs = GetRequestInfo(ReadType.Prefix);
apiWeeks = (from n in Logs
- group n by new { n.Week, n.Url } into g
+ group n by new { n.Week, n.Url }
+ into g
select new ApiWeek
{
week = g.Key.Week,
@@ -459,7 +478,6 @@ namespace Blog.Core.Common.LogHelper
}).ToList();
//apiWeeks = apiWeeks.OrderByDescending(d => d.count).Take(8).ToList();
-
}
catch (Exception)
{
@@ -489,10 +507,12 @@ namespace Blog.Core.Common.LogHelper
jsonBuilder.Append(item.count);
jsonBuilder.Append("\",");
}
+
if (apiweeksCurrentWeek.Count > 0)
{
jsonBuilder.Remove(jsonBuilder.Length - 1, 1);
}
+
jsonBuilder.Append("},");
}
@@ -500,6 +520,7 @@ namespace Blog.Core.Common.LogHelper
{
jsonBuilder.Remove(jsonBuilder.Length - 1, 1);
}
+
jsonBuilder.Append("]");
//columns.AddRange(apiWeeks.OrderByDescending(d => d.count).Take(8).Select(d => d.url).ToList());
@@ -521,7 +542,8 @@ namespace Blog.Core.Common.LogHelper
Logs = GetRequestInfo(ReadType.Prefix);
apiDates = (from n in Logs
- group n by new { n.Date } into g
+ group n by new { n.Date }
+ into g
select new ApiDate
{
date = g.Key.Date,
@@ -529,7 +551,6 @@ namespace Blog.Core.Common.LogHelper
}).ToList();
apiDates = apiDates.OrderByDescending(d => d.date).Take(7).ToList();
-
}
catch (Exception)
{
@@ -552,7 +573,8 @@ namespace Blog.Core.Common.LogHelper
apiDates = (from n in Logs
where n.Datetime.ObjToDate() >= DateTime.Today
- group n by new { hour = n.Datetime.ObjToDate().Hour } into g
+ group n by new { hour = n.Datetime.ObjToDate().Hour }
+ into g
select new ApiDate
{
date = g.Key.hour.ToString("00"),
@@ -560,7 +582,6 @@ namespace Blog.Core.Common.LogHelper
}).ToList();
apiDates = apiDates.OrderBy(d => d.date).Take(24).ToList();
-
}
catch (Exception)
{
@@ -580,14 +601,15 @@ namespace Blog.Core.Common.LogHelper
/// 精确查找一个
///
Accurate,
+
///
/// 指定前缀,模糊查找全部
///
Prefix,
+
///
/// 指定前缀,最新一个文件
///
PrefixLatest
}
-
-}
+}
\ No newline at end of file
diff --git a/Blog.Core.Extensions/Blog.Core.Extensions.csproj b/Blog.Core.Extensions/Blog.Core.Extensions.csproj
index 451d24f..9eae3d9 100644
--- a/Blog.Core.Extensions/Blog.Core.Extensions.csproj
+++ b/Blog.Core.Extensions/Blog.Core.Extensions.csproj
@@ -18,10 +18,10 @@
-
+
@@ -35,6 +35,7 @@
+
diff --git a/Blog.Core.Extensions/Middlewares/ExceptionHandlerMiddleware.cs b/Blog.Core.Extensions/Middlewares/ExceptionHandlerMiddleware.cs
index 85d96e9..aed5776 100644
--- a/Blog.Core.Extensions/Middlewares/ExceptionHandlerMiddleware.cs
+++ b/Blog.Core.Extensions/Middlewares/ExceptionHandlerMiddleware.cs
@@ -4,14 +4,13 @@ using System.Threading.Tasks;
using Blog.Core.Model;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
+using Serilog;
namespace Blog.Core.Extensions.Middlewares
{
public class ExceptionHandlerMiddleware
{
private readonly RequestDelegate _next;
- private static readonly log4net.ILog Log =
- log4net.LogManager.GetLogger(typeof(ExceptionHandlerMiddleware));
public ExceptionHandlerMiddleware(RequestDelegate next)
{
@@ -48,7 +47,9 @@ namespace Blog.Core.Extensions.Middlewares
context.Response.ContentType = "application/json";
- await context.Response.WriteAsync(JsonConvert.SerializeObject((new ApiResponse(StatusCode.CODE500, e.Message)).MessageModel)).ConfigureAwait(false);
+ await context.Response
+ .WriteAsync(JsonConvert.SerializeObject(new ApiResponse(StatusCode.CODE500, e.Message).MessageModel))
+ .ConfigureAwait(false);
}
}
-}
+}
\ No newline at end of file
diff --git a/Blog.Core.Extensions/Middlewares/IpLimitMiddleware.cs b/Blog.Core.Extensions/Middlewares/IpLimitMiddleware.cs
index 958d6ff..7fe68fc 100644
--- a/Blog.Core.Extensions/Middlewares/IpLimitMiddleware.cs
+++ b/Blog.Core.Extensions/Middlewares/IpLimitMiddleware.cs
@@ -1,8 +1,8 @@
-using System;
-using AspNetCoreRateLimit;
+using AspNetCoreRateLimit;
using Blog.Core.Common;
-using log4net;
using Microsoft.AspNetCore.Builder;
+using System;
+using Serilog;
namespace Blog.Core.Extensions.Middlewares
{
@@ -11,7 +11,6 @@ namespace Blog.Core.Extensions.Middlewares
///
public static class IpLimitMiddleware
{
- private static readonly ILog Log = LogManager.GetLogger(typeof(IpLimitMiddleware));
public static void UseIpLimitMiddle(this IApplicationBuilder app)
{
if (app == null) throw new ArgumentNullException(nameof(app));
diff --git a/Blog.Core.Extensions/Middlewares/IpLogMiddleware.cs b/Blog.Core.Extensions/Middlewares/IpLogMiddleware.cs
index b6b91bd..ccd0d7a 100644
--- a/Blog.Core.Extensions/Middlewares/IpLogMiddleware.cs
+++ b/Blog.Core.Extensions/Middlewares/IpLogMiddleware.cs
@@ -1,10 +1,10 @@
-using System;
-using System.Threading.Tasks;
-using Blog.Core.Common;
+using Blog.Core.Common;
using Blog.Core.Common.LogHelper;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
+using System;
+using System.Threading.Tasks;
namespace Blog.Core.Extensions.Middlewares
{
@@ -19,7 +19,6 @@ namespace Blog.Core.Extensions.Middlewares
///
private readonly RequestDelegate _next;
private readonly IWebHostEnvironment _environment;
- private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(IpLogMiddleware));
///
///
diff --git a/Blog.Core.Extensions/Middlewares/MiniProfilerMiddleware.cs b/Blog.Core.Extensions/Middlewares/MiniProfilerMiddleware.cs
index 068c4a0..49e3b70 100644
--- a/Blog.Core.Extensions/Middlewares/MiniProfilerMiddleware.cs
+++ b/Blog.Core.Extensions/Middlewares/MiniProfilerMiddleware.cs
@@ -1,7 +1,7 @@
-using System;
-using Blog.Core.Common;
-using log4net;
+using Blog.Core.Common;
using Microsoft.AspNetCore.Builder;
+using System;
+using Serilog;
namespace Blog.Core.Extensions.Middlewares
{
@@ -10,7 +10,6 @@ namespace Blog.Core.Extensions.Middlewares
///
public static class MiniProfilerMiddleware
{
- private static readonly ILog Log = LogManager.GetLogger(typeof(MiniProfilerMiddleware));
public static void UseMiniProfilerMiddleware(this IApplicationBuilder app)
{
if (app == null) throw new ArgumentNullException(nameof(app));
diff --git a/Blog.Core.Extensions/Middlewares/SignalRSendMiddleware.cs b/Blog.Core.Extensions/Middlewares/SignalRSendMiddleware.cs
index 1909c08..f15df7b 100644
--- a/Blog.Core.Extensions/Middlewares/SignalRSendMiddleware.cs
+++ b/Blog.Core.Extensions/Middlewares/SignalRSendMiddleware.cs
@@ -36,6 +36,7 @@ namespace Blog.Core.Extensions.Middlewares
{
if (AppSettings.app("Middleware", "SignalR", "Enabled").ObjToBool())
{
+ //TODO 主动发送错误消息
await _hubContext.Clients.All.SendAsync("ReceiveUpdate", LogLock.GetLogData());
}
await _next(context);
diff --git a/Blog.Core.Extensions/Middlewares/SwaggerMiddleware.cs b/Blog.Core.Extensions/Middlewares/SwaggerMiddleware.cs
index 099b257..73af77d 100644
--- a/Blog.Core.Extensions/Middlewares/SwaggerMiddleware.cs
+++ b/Blog.Core.Extensions/Middlewares/SwaggerMiddleware.cs
@@ -1,10 +1,10 @@
-using System;
-using System.IO;
-using System.Linq;
-using Blog.Core.Common;
-using log4net;
+using Blog.Core.Common;
using Microsoft.AspNetCore.Builder;
using Swashbuckle.AspNetCore.SwaggerUI;
+using System;
+using System.IO;
+using System.Linq;
+using Serilog;
using static Blog.Core.Extensions.CustomApiVersion;
namespace Blog.Core.Extensions.Middlewares
@@ -14,7 +14,6 @@ namespace Blog.Core.Extensions.Middlewares
///
public static class SwaggerMiddleware
{
- private static readonly ILog Log = LogManager.GetLogger(typeof(SwaggerMiddleware));
public static void UseSwaggerMiddle(this IApplicationBuilder app, Func streamHtml)
{
if (app == null) throw new ArgumentNullException(nameof(app));
@@ -24,10 +23,7 @@ namespace Blog.Core.Extensions.Middlewares
{
//根据版本名称倒序 遍历展示
var apiName = AppSettings.app(new string[] { "Startup", "ApiName" });
- typeof(ApiVersions).GetEnumNames().OrderByDescending(e => e).ToList().ForEach(version =>
- {
- c.SwaggerEndpoint($"/swagger/{version}/swagger.json", $"{apiName} {version}");
- });
+ typeof(ApiVersions).GetEnumNames().OrderByDescending(e => e).ToList().ForEach(version => { c.SwaggerEndpoint($"/swagger/{version}/swagger.json", $"{apiName} {version}"); });
c.SwaggerEndpoint($"https://petstore.swagger.io/v2/swagger.json", $"{apiName} pet");
@@ -38,12 +34,13 @@ namespace Blog.Core.Extensions.Middlewares
Log.Error(msg);
throw new Exception(msg);
}
+
c.IndexStream = streamHtml;
c.DocExpansion(DocExpansion.None); //->修改界面打开时自动折叠
if (Permissions.IsUseIds4)
{
- c.OAuthClientId("blogadminjs");
+ c.OAuthClientId("blogadminjs");
}
@@ -52,4 +49,4 @@ namespace Blog.Core.Extensions.Middlewares
});
}
}
-}
+}
\ No newline at end of file
diff --git a/Blog.Core.Extensions/ServiceExtensions/AppConfigSetup.cs b/Blog.Core.Extensions/ServiceExtensions/AppConfigSetup.cs
index 0622e76..0336567 100644
--- a/Blog.Core.Extensions/ServiceExtensions/AppConfigSetup.cs
+++ b/Blog.Core.Extensions/ServiceExtensions/AppConfigSetup.cs
@@ -76,10 +76,10 @@ namespace Blog.Core.Extensions
var ipLogOpen = AppSettings.app(new string[] { "Middleware", "IPLog", "Enabled" }).ObjToBool();
var recordAccessLogsOpen = AppSettings.app(new string[] { "Middleware", "RecordAccessLogs", "Enabled" }).ObjToBool();
ConsoleHelper.WriteSuccessLine($"OPEN Log: " +
- (requestResponseLogOpen ? "RequestResponseLog √," : "") +
- (ipLogOpen ? "IPLog √," : "") +
- (recordAccessLogsOpen ? "RecordAccessLogs √," : "")
- );
+ (requestResponseLogOpen ? "RequestResponseLog √," : "") +
+ (ipLogOpen ? "IPLog √," : "") +
+ (recordAccessLogsOpen ? "RecordAccessLogs √," : "")
+ );
// 事务AOP
if (!AppSettings.app(new string[] { "AppSettings", "TranAOP", "Enabled" }).ObjToBool())
@@ -213,7 +213,6 @@ namespace Blog.Core.Extensions
Console.WriteLine();
}
-
}
public static void AddAppTableConfigSetup(this IServiceCollection services, IHostEnvironment env)
@@ -222,7 +221,6 @@ namespace Blog.Core.Extensions
if (AppSettings.app(new string[] { "Startup", "AppConfigAlert", "Enabled" }).ObjToBool())
{
-
if (env.IsDevelopment())
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
@@ -230,6 +228,7 @@ namespace Blog.Core.Extensions
}
#region 程序配置
+
List configInfos = new()
{
new string[] { "当前环境", Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") },
@@ -238,7 +237,7 @@ namespace Blog.Core.Extensions
new string[] { "RabbitMQ消息列队", AppSettings.app("RabbitMQ", "Enabled") },
new string[] { "事件总线(必须开启消息列队)", AppSettings.app("EventBus", "Enabled") },
new string[] { "redis消息队列", AppSettings.app("Startup", "RedisMq", "Enabled") },
- new string[] { "是否多库", AppSettings.app("MutiDBEnabled" ) },
+ new string[] { "是否多库", AppSettings.app("MutiDBEnabled") },
new string[] { "读写分离", AppSettings.app("CQRSEnabled") },
};
@@ -253,17 +252,19 @@ namespace Blog.Core.Extensions
TableStyle = TableStyle.Alternative
}.Writer(ConsoleColor.Blue);
Console.WriteLine();
+
#endregion 程序配置
#region AOP
+
List aopInfos = new()
-{
+ {
new string[] { "Redis缓存AOP", AppSettings.app("AppSettings", "RedisCachingAOP", "Enabled") },
new string[] { "内存缓存AOP", AppSettings.app("AppSettings", "MemoryCachingAOP", "Enabled") },
- new string[] { "服务日志AOP", AppSettings.app("AppSettings", "LogAOP", "Enabled" ) },
- new string[] { "事务AOP", AppSettings.app("AppSettings", "TranAOP", "Enabled" ) },
- new string[] { "Sql执行AOP", AppSettings.app("AppSettings", "SqlAOP", "OutToLogFile", "Enabled" ) },
- new string[] { "Sql执行AOP控制台输出", AppSettings.app("AppSettings", "SqlAOP", "OutToConsole", "Enabled" ) },
+ new string[] { "服务日志AOP", AppSettings.app("AppSettings", "LogAOP", "Enabled") },
+ new string[] { "事务AOP", AppSettings.app("AppSettings", "TranAOP", "Enabled") },
+ new string[] { "Sql执行AOP", AppSettings.app("AppSettings", "SqlAOP", "Enabled") },
+ new string[] { "Sql执行AOP控制台输出", AppSettings.app("AppSettings", "SqlAOP", "LogToConsole", "Enabled") },
};
new ConsoleTable
@@ -277,15 +278,17 @@ namespace Blog.Core.Extensions
TableStyle = TableStyle.Alternative
}.Writer(ConsoleColor.Blue);
Console.WriteLine();
+
#endregion AOP
#region 中间件
+
List MiddlewareInfos = new()
{
new string[] { "请求纪录中间件", AppSettings.app("Middleware", "RecordAccessLogs", "Enabled") },
- new string[] { "IP记录中间件", AppSettings.app("Middleware", "IPLog", "Enabled" ) },
- new string[] { "请求响应日志中间件", AppSettings.app("Middleware", "RequestResponseLog", "Enabled" ) },
- new string[] { "SingnalR实时发送请求数据中间件", AppSettings.app("Middleware", "SignalR", "Enabled" ) },
+ new string[] { "IP记录中间件", AppSettings.app("Middleware", "IPLog", "Enabled") },
+ new string[] { "请求响应日志中间件", AppSettings.app("Middleware", "RequestResponseLog", "Enabled") },
+ new string[] { "SingnalR实时发送请求数据中间件", AppSettings.app("Middleware", "SignalR", "Enabled") },
new string[] { "IP限流中间件", AppSettings.app("Middleware", "IpRateLimit", "Enabled") },
new string[] { "性能分析中间件", AppSettings.app("Startup", "MiniProfiler", "Enabled") },
new string[] { "Consul注册服务", AppSettings.app("Middleware", "Consul", "Enabled") },
@@ -302,10 +305,9 @@ namespace Blog.Core.Extensions
TableStyle = TableStyle.Alternative
}.Writer(ConsoleColor.Blue);
Console.WriteLine();
+
#endregion 中间件
-
}
-
}
}
-}
+}
\ No newline at end of file
diff --git a/Blog.Core.Extensions/ServiceExtensions/AutofacModuleRegister.cs b/Blog.Core.Extensions/ServiceExtensions/AutofacModuleRegister.cs
index 7f2997b..4351962 100644
--- a/Blog.Core.Extensions/ServiceExtensions/AutofacModuleRegister.cs
+++ b/Blog.Core.Extensions/ServiceExtensions/AutofacModuleRegister.cs
@@ -6,20 +6,18 @@ using Blog.Core.IRepository.Base;
using Blog.Core.IServices.BASE;
using Blog.Core.Model;
using Blog.Core.Repository.Base;
+using Blog.Core.Repository.UnitOfWorks;
using Blog.Core.Services.BASE;
-using log4net;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
-using Blog.Core.Repository.UnitOfWorks;
+using Serilog;
namespace Blog.Core.Extensions
{
public class AutofacModuleRegister : Autofac.Module
{
- private static readonly ILog log = LogManager.GetLogger(typeof(AutofacModuleRegister));
-
protected override void Load(ContainerBuilder builder)
{
var basePath = AppContext.BaseDirectory;
@@ -34,39 +32,39 @@ namespace Blog.Core.Extensions
if (!(File.Exists(servicesDllFile) && File.Exists(repositoryDllFile)))
{
var msg = "Repository.dll和service.dll 丢失,因为项目解耦了,所以需要先F6编译,再F5运行,请检查 bin 文件夹,并拷贝。";
- log.Error(msg);
+ Log.Error(msg);
throw new Exception(msg);
}
// AOP 开关,如果想要打开指定的功能,只需要在 appsettigns.json 对应对应 true 就行。
var cacheType = new List();
- if (AppSettings.app(new string[] {"AppSettings", "RedisCachingAOP", "Enabled"}).ObjToBool())
+ if (AppSettings.app(new string[] { "AppSettings", "RedisCachingAOP", "Enabled" }).ObjToBool())
{
builder.RegisterType();
cacheType.Add(typeof(BlogRedisCacheAOP));
}
- if (AppSettings.app(new string[] {"AppSettings", "MemoryCachingAOP", "Enabled"}).ObjToBool())
+ if (AppSettings.app(new string[] { "AppSettings", "MemoryCachingAOP", "Enabled" }).ObjToBool())
{
builder.RegisterType();
cacheType.Add(typeof(BlogCacheAOP));
}
- if (AppSettings.app(new string[] {"AppSettings", "TranAOP", "Enabled"}).ObjToBool())
+ if (AppSettings.app(new string[] { "AppSettings", "TranAOP", "Enabled" }).ObjToBool())
{
builder.RegisterType();
cacheType.Add(typeof(BlogTranAOP));
}
- if (AppSettings.app(new string[] {"AppSettings", "LogAOP", "Enabled"}).ObjToBool())
+ if (AppSettings.app(new string[] { "AppSettings", "LogAOP", "Enabled" }).ObjToBool())
{
builder.RegisterType();
cacheType.Add(typeof(BlogLogAOP));
}
- builder.RegisterGeneric(typeof(BaseRepository<>)).As(typeof(IBaseRepository<>)).InstancePerDependency();//注册仓储
- builder.RegisterGeneric(typeof(BaseServices<>)).As(typeof(IBaseServices<>)).InstancePerDependency();//注册服务
+ builder.RegisterGeneric(typeof(BaseRepository<>)).As(typeof(IBaseRepository<>)).InstancePerDependency(); //注册仓储
+ builder.RegisterGeneric(typeof(BaseServices<>)).As(typeof(IBaseServices<>)).InstancePerDependency(); //注册服务
// 获取 Service.dll 程序集服务,并注册
var assemblysServices = Assembly.LoadFrom(servicesDllFile);
diff --git a/Blog.Core.Extensions/ServiceExtensions/HttpPollySetup.cs b/Blog.Core.Extensions/ServiceExtensions/HttpPollySetup.cs
index e8e3929..b3147ca 100644
--- a/Blog.Core.Extensions/ServiceExtensions/HttpPollySetup.cs
+++ b/Blog.Core.Extensions/ServiceExtensions/HttpPollySetup.cs
@@ -1,4 +1,4 @@
-using Blog.Core.Common.HttpPolly;
+using Blog.Core.Common.Https.HttpPolly;
using Blog.Core.Model;
using Microsoft.Extensions.DependencyInjection;
using Polly;
diff --git a/Blog.Core.Extensions/ServiceExtensions/SerilogSetup.cs b/Blog.Core.Extensions/ServiceExtensions/SerilogSetup.cs
new file mode 100644
index 0000000..a112409
--- /dev/null
+++ b/Blog.Core.Extensions/ServiceExtensions/SerilogSetup.cs
@@ -0,0 +1,37 @@
+using Blog.Core.Common;
+using Blog.Core.Common.LogHelper;
+using Blog.Core.Serilog.Extensions;
+using Microsoft.Extensions.Hosting;
+using Serilog;
+using Serilog.Debugging;
+using System;
+using System.IO;
+
+namespace Blog.Core.Extensions.ServiceExtensions;
+
+public static class SerilogSetup
+{
+ public static IHostBuilder AddSerilogSetup(this IHostBuilder host)
+ {
+ if (host == null) throw new ArgumentNullException(nameof(host));
+
+ var loggerConfiguration = new LoggerConfiguration()
+ .ReadFrom.Configuration(AppSettings.Configuration)
+ .Enrich.FromLogContext()
+ //输出到控制台
+ .WriteToConsole()
+ //将日志保存到文件中
+ .WriteToFile();
+ //配置日志库
+ //.WriteToLogBatching();
+
+ Log.Logger = loggerConfiguration.CreateLogger();
+
+ //Serilog 内部日志
+ var file = File.CreateText(LogContextStatic.Combine($"SerilogDebug{DateTime.Now:yyyyMMdd}.txt"));
+ SelfLog.Enable(TextWriter.Synchronized(file));
+
+ host.UseSerilog();
+ return host;
+ }
+}
\ No newline at end of file
diff --git a/Blog.Core.Extensions/ServiceExtensions/SqlsugarSetup.cs b/Blog.Core.Extensions/ServiceExtensions/SqlsugarSetup.cs
index 3ecf224..3440b8a 100644
--- a/Blog.Core.Extensions/ServiceExtensions/SqlsugarSetup.cs
+++ b/Blog.Core.Extensions/ServiceExtensions/SqlsugarSetup.cs
@@ -1,6 +1,7 @@
using Blog.Core.Common;
+using Blog.Core.Common.Const;
using Blog.Core.Common.DB;
-using Blog.Core.Common.Helper;
+using Blog.Core.Common.DB.Aop;
using Blog.Core.Common.LogHelper;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
@@ -9,7 +10,6 @@ using StackExchange.Profiling;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
-using Blog.Core.Common.DB.Aop;
namespace Blog.Core.Extensions
{
@@ -48,7 +48,7 @@ namespace Blog.Core.Extensions
BaseDBConfig.MutiConnectionString.allDbs.ForEach(m =>
{
- listConfig.Add(new ConnectionConfig()
+ var config = new ConnectionConfig()
{
ConfigId = m.ConnId.ObjToString().ToLower(),
ConnectionString = m.Connection,
@@ -56,29 +56,6 @@ namespace Blog.Core.Extensions
IsAutoCloseConnection = true,
// Check out more information: https://github.com/anjoy8/Blog.Core/issues/122
//IsShardSameThread = false,
- AopEvents = new AopEvents
- {
- OnLogExecuting = (sql, p) =>
- {
- if (AppSettings.app(new string[] { "AppSettings", "SqlAOP", "Enabled" }).ObjToBool())
- {
- if (AppSettings.app(new string[] { "AppSettings", "SqlAOP", "LogToFile", "Enabled" }).ObjToBool())
- {
- Parallel.For(0, 1, e =>
- {
- MiniProfiler.Current.CustomTiming("SQL:", GetParas(p) + "【SQL语句】:" + sql);
- //LogLock.OutSql2Log("SqlLog", new string[] { GetParas(p), "【SQL语句】:" + sql });
- LogLock.OutLogAOP("SqlLog", "", new string[] { sql.GetType().ToString(), GetParas(p), "【SQL语句】:" + sql });
-
- });
- }
- if (AppSettings.app(new string[] { "AppSettings", "SqlAOP", "LogToConsole", "Enabled" }).ObjToBool())
- {
- ConsoleHelper.WriteColorLine(string.Join("\r\n", new string[] { "--------", $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} :" + GetWholeSql(p, sql) }), ConsoleColor.DarkCyan);
- }
- }
- },
- },
MoreSettings = new ConnMoreSettings()
{
//IsWithNoLockQuery = true,
@@ -99,15 +76,29 @@ namespace Blog.Core.Extensions
}
},
InitKeyType = InitKeyType.Attribute
+ };
+ if (SqlSugarConst.LogConfigId.Equals(m.ConnId))
+ {
+ BaseDBConfig.LogConfig = config;
}
- );
+
+ listConfig.Add(config);
});
+
+ if (BaseDBConfig.LogConfig is null)
+ {
+ throw new ApplicationException("未配置Log库连接");
+ }
+
return new SqlSugarScope(listConfig, db =>
{
listConfig.ForEach(config =>
{
var dbProvider = db.GetConnectionScope((string)config.ConfigId);
+ // 打印SQL语句
+ dbProvider.Aop.OnLogExecuting = (s, parameters) => SqlSugarAop.OnLogExecuting(dbProvider,s, parameters, config);
+
// 数据审计
dbProvider.Aop.DataExecuting = SqlSugarAop.DataExecuting;
diff --git a/Blog.Core.Extensions/ServiceExtensions/SwaggerSetup.cs b/Blog.Core.Extensions/ServiceExtensions/SwaggerSetup.cs
index 449b6a4..85dff62 100644
--- a/Blog.Core.Extensions/ServiceExtensions/SwaggerSetup.cs
+++ b/Blog.Core.Extensions/ServiceExtensions/SwaggerSetup.cs
@@ -1,7 +1,7 @@
using Blog.Core.Common;
-using log4net;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
+using Serilog;
using Swashbuckle.AspNetCore.Filters;
using System;
using System.Collections.Generic;
@@ -17,10 +17,6 @@ namespace Blog.Core.Extensions
///
public static class SwaggerSetup
{
-
- private static readonly ILog log =
- LogManager.GetLogger(typeof(SwaggerSetup));
-
public static void AddSwaggerSetup(this IServiceCollection services)
{
if (services == null) throw new ArgumentNullException(nameof(services));
@@ -59,7 +55,7 @@ namespace Blog.Core.Extensions
}
catch (Exception ex)
{
- log.Error("Blog.Core.xml和Blog.Core.Model.xml 丢失,请检查并拷贝。\n" + ex.Message);
+ Log.Error("Blog.Core.xml和Blog.Core.Model.xml 丢失,请检查并拷贝。\n" + ex.Message);
}
// 开启加权小锁
@@ -82,12 +78,13 @@ namespace Blog.Core.Extensions
Implicit = new OpenApiOAuthFlow
{
AuthorizationUrl = new Uri($"{AppSettings.app(new string[] { "Startup", "IdentityServer4", "AuthorizationUrl" })}/connect/authorize"),
- Scopes = new Dictionary {
+ Scopes = new Dictionary
{
- "blog.core.api","ApiResource id"
+ {
+ "blog.core.api", "ApiResource id"
+ }
}
}
- }
}
});
}
@@ -97,14 +94,11 @@ namespace Blog.Core.Extensions
c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}(注意两者之间是一个空格)\"",
- Name = "Authorization",//jwt默认的参数名称
- In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
+ Name = "Authorization", //jwt默认的参数名称
+ In = ParameterLocation.Header, //jwt默认存放Authorization信息的位置(请求头中)
Type = SecuritySchemeType.ApiKey
});
}
-
-
-
});
services.AddSwaggerGenNewtonsoftSupport();
}
@@ -124,11 +118,11 @@ namespace Blog.Core.Extensions
/// V1 版本
///
V1 = 1,
+
///
/// V2 版本
///
V2 = 2,
}
}
-
-}
+}
\ No newline at end of file
diff --git a/Blog.Core.Serilog.Es/Blog.Core.Serilog.Es.csproj b/Blog.Core.Serilog.Es/Blog.Core.Serilog.Es.csproj
index 5cf8202..398aab4 100644
--- a/Blog.Core.Serilog.Es/Blog.Core.Serilog.Es.csproj
+++ b/Blog.Core.Serilog.Es/Blog.Core.Serilog.Es.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/Blog.Core.Serilog/Blog.Core.Serilog.csproj b/Blog.Core.Serilog/Blog.Core.Serilog.csproj
new file mode 100644
index 0000000..07fa26f
--- /dev/null
+++ b/Blog.Core.Serilog/Blog.Core.Serilog.csproj
@@ -0,0 +1,13 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/Blog.Core.Serilog/Extensions/LoggerConfigurationExtensions.cs b/Blog.Core.Serilog/Extensions/LoggerConfigurationExtensions.cs
new file mode 100644
index 0000000..2736aa1
--- /dev/null
+++ b/Blog.Core.Serilog/Extensions/LoggerConfigurationExtensions.cs
@@ -0,0 +1,121 @@
+using Blog.Core.Common;
+using Blog.Core.Common.LogHelper;
+using Serilog;
+using Serilog.Events;
+using Serilog.Filters;
+using SqlSugar;
+
+namespace Blog.Core.Serilog.Extensions;
+
+public static class LoggerConfigurationExtensions
+{
+ public static LoggerConfiguration WriteToSqlServer(this LoggerConfiguration loggerConfiguration)
+ {
+ var logConnectionStrings = AppSettings.app("LogConnectionStrings");
+ if (logConnectionStrings.IsNullOrEmpty()) return loggerConfiguration;
+
+ //输出SQL
+ //loggerConfiguration = loggerConfiguration.WriteTo.Logger(lg =>
+ // lg.FilterSqlLog().WriteTo.MSSqlServer(logConnectionStrings, new MSSqlServerSinkOptions()
+ // {
+ // TableName = "SqlLog",
+ // AutoCreateSqlTable = true
+ // }));
+
+ //输出普通日志
+ //loggerConfiguration = loggerConfiguration.WriteTo.Logger(lg =>
+ // lg.FilterRemoveSqlLog().Filter.ByIncludingOnly(p => p.Level >= LogEventLevel.Error)
+ // .WriteTo.MSSqlServer(logConnectionStrings, new MSSqlServerSinkOptions()
+ // {
+ // TableName = "ErrorLog",
+ // AutoCreateSqlTable = true
+ // }));
+ //loggerConfiguration = loggerConfiguration.WriteTo.Logger(lg =>
+ // lg.FilterRemoveSqlLog().Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Warning)
+ // .WriteTo.MSSqlServer(logConnectionStrings, new MSSqlServerSinkOptions()
+ // {
+ // TableName = "WarningLog",
+ // AutoCreateSqlTable = true
+ // }));
+ //loggerConfiguration = loggerConfiguration.WriteTo.Logger(lg =>
+ // lg.FilterRemoveSqlLog().Filter.ByIncludingOnly(p => p.Level <= LogEventLevel.Information)
+ // .WriteTo.MSSqlServer(logConnectionStrings, new MSSqlServerSinkOptions()
+ // {
+ // TableName = "InformationLog",
+ // AutoCreateSqlTable = true
+ // }));
+
+ return loggerConfiguration;
+ }
+
+ public static LoggerConfiguration WriteToConsole(this LoggerConfiguration loggerConfiguration)
+ {
+ //输出普通日志
+ loggerConfiguration = loggerConfiguration.WriteTo.Logger(lg =>
+ lg.FilterRemoveSqlLog().WriteTo.Console());
+
+ //输出SQL
+ loggerConfiguration = loggerConfiguration.WriteTo.Logger(lg =>
+ lg.FilterSqlLog().Filter.ByIncludingOnly(Matching.WithProperty(LogContextStatic.SqlOutToConsole, s => s))
+ .WriteTo.Console());
+
+ return loggerConfiguration;
+ }
+
+ public static LoggerConfiguration WriteToFile(this LoggerConfiguration loggerConfiguration)
+ {
+ //输出SQL
+ loggerConfiguration = loggerConfiguration.WriteTo.Logger(lg =>
+ lg.FilterSqlLog().Filter.ByIncludingOnly(Matching.WithProperty(LogContextStatic.SqlOutToFile, s => s))
+ .WriteTo.Async(s => s.File(LogContextStatic.Combine(LogContextStatic.AopSql, @"AopSql.txt"), rollingInterval: RollingInterval.Day,
+ outputTemplate: LogContextStatic.FileMessageTemplate, retainedFileCountLimit: 31)));
+ //输出普通日志
+ loggerConfiguration = loggerConfiguration.WriteTo.Logger(lg =>
+ lg.FilterRemoveSqlLog().WriteTo.Async(s => s.File(LogContextStatic.Combine(LogContextStatic.BasePathLogs, @"Log.txt"), rollingInterval: RollingInterval.Day,
+ outputTemplate: LogContextStatic.FileMessageTemplate, retainedFileCountLimit: 31)));
+ return loggerConfiguration;
+ }
+
+ public static LoggerConfiguration FilterSqlLog(this LoggerConfiguration lc)
+ {
+ lc = lc.Filter.ByIncludingOnly(Matching.WithProperty(LogContextStatic.LogSource, s => LogContextStatic.AopSql.Equals(s)));
+ return lc;
+ }
+
+ public static IEnumerable FilterSqlLog(this IEnumerable batch)
+ {
+ return batch.Where(s => s.WithProperty(LogContextStatic.LogSource, q => LogContextStatic.AopSql.Equals(q)))
+ .Where(s => s.WithProperty(LogContextStatic.SugarActionType,
+ q => !new[] { SugarActionType.UnKnown, SugarActionType.Query }.Contains(q)));
+ }
+
+ public static LoggerConfiguration FilterRemoveSqlLog(this LoggerConfiguration lc)
+ {
+ lc = lc.Filter.ByIncludingOnly(WithProperty(LogContextStatic.LogSource, s => !LogContextStatic.AopSql.Equals(s)));
+ return lc;
+ }
+
+ public static IEnumerable FilterRemoveOtherLog(this IEnumerable batch)
+ {
+ return batch.Where(s => WithProperty(LogContextStatic.LogSource,
+ q => !LogContextStatic.AopSql.Equals(q))(s));
+ }
+
+ public static Func WithProperty(string propertyName, Func predicate)
+ {
+ //如果不包含属性 也认为是true
+ return e =>
+ {
+ if (!e.Properties.TryGetValue(propertyName, out var propertyValue)) return true;
+
+ return propertyValue is ScalarValue { Value: T value } && predicate(value);
+ };
+ }
+
+ public static bool WithProperty(this LogEvent e, string key, Func predicate)
+ {
+ if (!e.Properties.TryGetValue(key, out var propertyValue)) return false;
+
+ return propertyValue is ScalarValue { Value: T value } && predicate(value);
+ }
+}
\ No newline at end of file
diff --git a/Blog.Core.Serilog/Utility/SerilogRequestUtility.cs b/Blog.Core.Serilog/Utility/SerilogRequestUtility.cs
new file mode 100644
index 0000000..cab7ae5
--- /dev/null
+++ b/Blog.Core.Serilog/Utility/SerilogRequestUtility.cs
@@ -0,0 +1,34 @@
+using Microsoft.AspNetCore.Http;
+using Serilog.Events;
+
+namespace Blog.Core.Serilog.Utility;
+
+public class SerilogRequestUtility
+{
+ private static readonly List _ignoreUrl = new()
+ {
+ "/job",
+ };
+
+ private static LogEventLevel DefaultGetLevel(
+ HttpContext ctx,
+ double _,
+ Exception? ex)
+ {
+ return ex is null && ctx.Response.StatusCode <= 499 ? LogEventLevel.Information : LogEventLevel.Error;
+ }
+
+ public static LogEventLevel GetRequestLevel(HttpContext ctx, double _, Exception? ex) =>
+ ex is null && ctx.Response.StatusCode <= 499 ? IgnoreRequest(ctx) : LogEventLevel.Error;
+
+ private static LogEventLevel IgnoreRequest(HttpContext ctx)
+ {
+ var path = ctx.Request.Path.Value;
+ if (path.IsNullOrEmpty())
+ {
+ return LogEventLevel.Information;
+ }
+
+ return _ignoreUrl.Any(s => path.StartsWith(s)) ? LogEventLevel.Verbose : LogEventLevel.Information;
+ }
+}
\ No newline at end of file
diff --git a/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs b/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
index 1dcc57e..1d501c3 100644
--- a/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
+++ b/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
@@ -34,7 +34,7 @@ namespace Blog.Core.Tasks
}
public async Task Run(IJobExecutionContext context)
{
-
+
// 可以直接获取 JobDetail 的值
var jobKey = context.JobDetail.Key;
var jobId = jobKey.Name;
@@ -94,7 +94,7 @@ namespace Blog.Core.Tasks
Parallel.For(0, 1, e =>
{
- LogLock.OutLogAOP("ACCESSTRENDLOG","",new string[] { activeUserVMs.GetType().ToString(), JsonConvert.SerializeObject(activeUserVMs) }, false);
+ LogLock.OutLogAOP("ACCESSTRENDLOG", "", new string[] { activeUserVMs.GetType().ToString(), JsonConvert.SerializeObject(activeUserVMs) }, false);
});
}
diff --git a/Blog.Core.Tasks/QuartzNet/Jobs/Job_OperateLog_Quartz.cs b/Blog.Core.Tasks/QuartzNet/Jobs/Job_OperateLog_Quartz.cs
index 18c4c29..abcd81e 100644
--- a/Blog.Core.Tasks/QuartzNet/Jobs/Job_OperateLog_Quartz.cs
+++ b/Blog.Core.Tasks/QuartzNet/Jobs/Job_OperateLog_Quartz.cs
@@ -17,19 +17,21 @@ namespace Blog.Core.Tasks
{
public class Job_OperateLog_Quartz : JobBase, IJob
{
- private readonly IOperateLogServices _operateLogServices;
+ private readonly IOperateLogServices _operateLogServices;
private readonly IWebHostEnvironment _environment;
- public Job_OperateLog_Quartz(IOperateLogServices operateLogServices,IWebHostEnvironment environment, ITasksQzServices tasksQzServices,ITasksLogServices tasksLogServices)
- :base(tasksQzServices, tasksLogServices)
+ public Job_OperateLog_Quartz(IOperateLogServices operateLogServices, IWebHostEnvironment environment, ITasksQzServices tasksQzServices, ITasksLogServices tasksLogServices)
+ : base(tasksQzServices, tasksLogServices)
{
- _operateLogServices = operateLogServices;
- _environment = environment;
+ _operateLogServices = operateLogServices;
+ _environment = environment;
}
+
public async Task Execute(IJobExecutionContext context)
{
var executeLog = await ExecuteJob(context, async () => await Run(context));
}
+
public async Task Run(IJobExecutionContext context)
{
@@ -78,7 +80,4 @@ namespace Blog.Core.Tasks
}
}
}
-
-
-
-}
+}
\ No newline at end of file
diff --git a/Blog.Core.Tests/DependencyInjection/DI_Test.cs b/Blog.Core.Tests/DependencyInjection/DI_Test.cs
index ff2c74c..d425fa0 100644
--- a/Blog.Core.Tests/DependencyInjection/DI_Test.cs
+++ b/Blog.Core.Tests/DependencyInjection/DI_Test.cs
@@ -59,7 +59,6 @@ namespace Blog.Core.Tests
services.AddAutoMapper(typeof(Startup));
services.AddSingleton(new AppSettings(basePath));
- services.AddSingleton(new LogLock(basePath));
services.AddScoped();
services.AddScoped();
diff --git a/Blog.Core.sln b/Blog.Core.sln
index c8f6150..bf4f65c 100644
--- a/Blog.Core.sln
+++ b/Blog.Core.sln
@@ -57,6 +57,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blog.Core.Serilog.Es", "Blo
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ocelot.Provider.Nacos", "Ocelot.Provider.Nacos\Ocelot.Provider.Nacos.csproj", "{6463FB13-5F01-4A1D-8B62-A454FB3812EB}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blog.Core.Serilog", "Blog.Core.Serilog\Blog.Core.Serilog.csproj", "{7F9057F0-ED8D-4694-B590-7D75C012DF00}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -119,6 +121,10 @@ Global
{6463FB13-5F01-4A1D-8B62-A454FB3812EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6463FB13-5F01-4A1D-8B62-A454FB3812EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6463FB13-5F01-4A1D-8B62-A454FB3812EB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7F9057F0-ED8D-4694-B590-7D75C012DF00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7F9057F0-ED8D-4694-B590-7D75C012DF00}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7F9057F0-ED8D-4694-B590-7D75C012DF00}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7F9057F0-ED8D-4694-B590-7D75C012DF00}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE