十年河东,十年河西,莫欺少年穷
学无止境,精益求精
说起来这个类,让我想起一个人,一个说话口吃,嫉妒心强...的人,总之,我讨厌他,但是,不得不说,这个人的EF底层搞的还是不错的,于是,就把他的这块代码抄了过来,分享给大家。
日之类如下:
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Logging;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace FranchiseeContext
{
public class MyEFLogger : ILogger
{
private readonly string categoryName;
private const string line = "\r\n---------------------------------------------------------------------------------------------------------------------------";
public MyEFLogger(string categoryName) => this.categoryName = categoryName;
public bool IsEnabled(LogLevel logLevel) => true;
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
//ef core执行数据库查询时的categoryName为Microsoft.EntityFrameworkCore.Database.Command,日志级别为Information
if (categoryName == "Microsoft.EntityFrameworkCore.Database.Command" && logLevel == LogLevel.Information)
{
var logContent = Environment.NewLine + formatter(state, exception) + line;
LogHelper.WriteLog(logContent, "logs/myef", DateTime.Now.ToString("yyyyMMdd") + ".sql");
}
}
public IDisposable BeginScope<TState>(TState state) => null;
}
public class EFLoggerProvider : ILoggerProvider
{
public ILogger CreateLogger(string categoryName) => new MyEFLogger(categoryName);
public void Dispose() { }
}
/// <summary>
/// 日志帮助类
/// </summary>
public static class LogHelper
{
private static readonly ConcurrentQueue<LogModel> _que = new ConcurrentQueue<LogModel>();
private static readonly ManualResetEvent _mre = new ManualResetEvent(false);
private static Thread _thread = new Thread(new ThreadStart(WriteLog)) { IsBackground = true, Priority = ThreadPriority.BelowNormal };
/// <summary>
/// 写日志
/// </summary>
public static void WriteLog(string log)
{
_que.Enqueue(new LogModel
{
Message = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}:{log}\r\n",
Path = "logs/",
FileName = DateTime.Now.ToString("yyyy_MM_dd") + ".log"
});
_mre.Set();
}
/// <summary>
/// 写日志
/// </summary>
/// <param name="log"></param>
/// <param name="path"></param>
public static void WriteLog(string log, string path)
{
_que.Enqueue(new LogModel
{
Message = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}:{log}\r\n",
Path = path,
FileName = DateTime.Now.ToString("yyyy_MM_dd") + ".log"
});
_mre.Set();
}
public static void WriteLog(string log, string path, string fileName)
{
_que.Enqueue(new LogModel
{
Message = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}:{log}\r\n",
Path = path,
FileName = fileName
});
_mre.Set();
}
/// <summary>
/// 启动日志线程
/// </summary>
public static void Register()
{
try { _thread.Abort(); } catch { }
_thread.Start();
}
private static void WriteLog()
{
while (true)
{
_mre.WaitOne();
while (_que.Count > 0 && _que.TryDequeue(out LogModel log))
{
string dirPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, log.Path);
if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
string filePath = Path.Combine(dirPath, log.FileName);
if (!File.Exists(filePath)) File.Create(filePath).Close();
File.AppendAllText(filePath, log.Message);
}
_mre.Reset();
Thread.Sleep(1);
}
}
}
public class LogModel
{
/// <summary>
/// 目录
/// </summary>
public string Path { get; set; }
/// <summary>
/// 文件名
/// </summary>
public string FileName { get; set; }
/// <summary>
/// 信息
/// </summary>
public string Message { get; set; }
}
}
View Code
那么怎么记录生成的SQL呢,这个就需要在启动类中注入服务,然后在数据库上下文类中调用日志方法。
启动类:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
//允许跨域
app.UseCors(builder => builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
// 启用Swagger中间件
app.UseSwagger(c => c.RouteTemplate = "swagger/{documentName}/swagger.json");
// 配置SwaggerUI
app.UseSwaggerUI(c =>
{
//c.SwaggerEndpoint($"/swagger/demo/swagger.json", "demo");
c.SwaggerEndpoint($"/swagger/v1/swagger.json", "V1");
});
//
//注册异常中间件
app.UseMiddleware<ExceptionMiddlewares>();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
//启动日志---------------------------记录EF生成的SQL
LogHelper.Register();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
View Code
数据库上下文需要调用如下方法【我用的是DB First】:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
optionsBuilder.UseMySql("server=.top;port=;database=;user=root;password=", x => x.ServerVersion("10.5.4-mariadb"));
}
//------------------------------------用于记录生成的SQL--------------------------------
optionsBuilder.UseLoggerFactory(new LoggerFactory(new List<ILoggerProvider> { new EFLoggerProvider() })); //增加日志工厂
}
View Code
还行吧,挺好用的。
@天才卧龙的博客