前言
Serilog是 .NET 上的一个原生结构化高性能日志库,这个库能实现一些比内置库更高度的定制。日志持久化是其中一个非常重要的功能,生产环境通常很难挂接调试器或者某些bug的触发条件很奇怪。为了在脱离调试环境的情况下尽可能保留更多线索来辅助解决生产问题,持久化的日志就显得很重要了。目前Serilog支持文件和部分数据库持久化,文件日志的查找分析比较麻烦,而使用数据库持久化则会导致特定数据库依赖。既然有EF Core这种专门负责抽象底层数据库的持久化框架,为何不直接使用呢。怀着这样的心情去Nuget找了一圈,结果一无所获,无奈又只能自己写一个。
新书宣传
有关新书的更多介绍欢迎查看《C#与.NET6 开发从入门到实践》上市,作者亲自来打广告了!
正文
对代码感兴趣的朋友可以移步Github。这里直接介绍一下基本用法。
这个库分为四个包:实体模型包定义基本实体类型;基本扩展包定义了模拟日志类别和严重性级别筛选的过滤器,方便为不同的输出目标自定义过滤器(内置的筛选器仅支持在全局使用,且会对所有输出目标生效,粒度不够细,只能自己写一个基于过滤器的扩展模拟相同的行为);配置扩展包定义了从IConfiguration
读取并构建过滤器的辅助方法,支持配置的实时自动更新;EF Core服务包定义了基于EF Core的Serilog的Sink,Sink实现批处理接口,能避免频繁向数据库插入单条日志记录。方便为分离项目的解决方案按需引用,减少无关类型的污染。
以在ASP.NET Core中使用为例:
实体模型和上下文
public class YourLogRecord : LogRecord
{
public int YourProperty { get; set; }
}
public class YourApplicationDbContext : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// 使用默认类型。
modelBuilder.UseLogRecord(b =>
{
b.ToTable($"{nameof(LogRecord)}s");
});
// 使用自定义类型,需要继承LogRecord。
modelBuilder.UseLogRecord<YourLogRecord>(b =>
{
b.ToTable($"{nameof(YourLogRecord)}s");
});
}
}
public class YourLogDbContext : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.UseLogRecord(b =>
{
b.ToTable($"{nameof(LogRecord)}s", tb => tb.ExcludeFromMigrations());
});
modelBuilder.UseLogRecord<YourLogRecord>(b =>
{
b.ToTable($"{nameof(YourLogRecord)}s", tb => tb.ExcludeFromMigrations());
});
}
}
需要注意,一定要使用两个不同的上下文类型,其中一个专用于存储日志数据。因为EF Core本身也会产生日志,如果使用一个上下文,一般配置下一定会产生无限循环。EF Core产生日志,通过EF Core写入日志,写入日志会导致产生新的EF Core日志……读取日志可以使用日志上下文,这样的话日志实体只需要日志上下文配置即可。不过还是推荐在主要上下文同时注册日志模型,这样读取日志产生的EF Core日志就可以安全的写入了。
使用两个上下文的情况下可以在日志上下文中配置实体从迁移中排除,把日志表迁移托管给主上下文。
服务注册
// 注册主上下文
services.AddDbContext<YourApplicationDbContext>(options =>
{
options.UseSqlite("app.db")
});
// 注册日志上下文
services.AddDbContext<YourLogDbContext>(options =>
{
// 重要!
// 抑制此上下文的命令执行相关日志生成以消除无限写入循环。
options.ConfigureWarnings(b => b.Ignore(RelationalEventId.CommandExecuted, RelationalEventId.CommandError));
options.UseSqlite("app.db")
});
// 注册日志过滤器配置监视器管理器服务。
services.AddMinimumLevelOverridableSerilogFilterConfigurationMonitorManager();
基础使用(Program.cs)
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog((hostBuilder, serviceProvider, configuration) =>
{
configuration
.ReadFrom.Configuration(hostBuilder.Configuration)
.ReadFrom.Services(serviceProvider)
.WriteTo.Logger(internalConfiguration =>
{
internalConfiguration
.Filter.ByIncludingOnly(
// 添加一个基于配置监视器的日志过滤器
new MinimumLevelOverridableSerilogFilterConfigurationMonitor(
serviceProvider,
// 配置路径
"SerilogFilterExtensions:EntityFrameworkCore"
).Filter)
// 使用默认日志类型
.WriteTo.EntityFrameworkCore(
serviceProvider.GetRequiredService<IServiceScopeFactory>(),
// 日志上下文提取工厂,取决于上下文服务应该如何获取,例如使用上下文工厂服务或者直接获取
static sp => sp.GetRequiredService<YourLogDbContext>(),
// 日志的JSON序列化选项
new()
{
ReferenceHandler = ReferenceHandler.IgnoreCycles,
Encoder = JavaScriptEncoder.Create(UnicodeRanges.All)
});
// 使用自定义日志类型
.WriteTo.EntityFrameworkCore<YourLogDbContext, YourLogRecord>(
serviceProvider.GetRequiredService<IServiceScopeFactory>(),
static sp => sp.GetRequiredService<YourLogDbContext>(),
new()
{
ReferenceHandler = ReferenceHandler.IgnoreCycles,
Encoder = JavaScriptEncoder.Create(UnicodeRanges.All)
});
});
}, writeToProviders: true);
Serilog的内置日志级别筛选仅可用于全局,无法针对各个Sink独立配置,因此笔者只能自己实现一个相同效果的过滤器。其中CoreDX.Serilog.Extensions
是过滤器本体,可手动基于代码构建,CoreDX.Serilog.Extensions.Configuration
是配置扩展,可自动监控配置。配置应该类似以下结构:
{
"SerilogFilterExtensions": {
"EntityFrameworkCore": {
"Default": "Warning",
"Override": {
"Microsoft.AspNetCore.DataProtection.KeyManagement": "Error",
"Microsoft.AspNetCore.DataProtection.Repositories": "Error",
"Microsoft.EntityFrameworkCore.Database.Command": "Error",
"Microsoft.EntityFrameworkCore.Model.Validation": "Error"
}
}
}
}
结语
为了实现对 .NETStantard 2.0 的兼容代码上使用了条件编译预处理实现一份代码一个项目同时编译到所有框架,最大程度共用代码简化代码管理。其中 .NET 6 以下使用Json.NET序列化,其他的使用System.Text.Json序列化。
许可证:MIT
代码仓库:CoreDX.Serilog.Sinks.EntityFrameworkCore – Github
Nuget:CoreDX.Serilog.Sinks.EntityFrameworkCore
Nuget:CoreDX.Serilog.Sinks.EntityFrameworkCore.Models
Nuget:CoreDX.Serilog.Extensions
Nuget:CoreDX.Serilog.Extensions.Configuration
QQ群
读者交流QQ群:540719365
欢迎读者和广大朋友一起交流,如发现本书错误也欢迎通过博客园、QQ群等方式告知笔者。
本文地址:https://www.cnblogs.com/coredx/p/18298297.html
1.本站内容仅供参考,不作为任何法律依据。用户在使用本站内容时,应自行判断其真实性、准确性和完整性,并承担相应风险。
2.本站部分内容来源于互联网,仅用于交流学习研究知识,若侵犯了您的合法权益,请及时邮件或站内私信与本站联系,我们将尽快予以处理。
3.本文采用知识共享 署名4.0国际许可协议 [BY-NC-SA] 进行授权
4.根据《计算机软件保护条例》第十七条规定“为了学习和研究软件内含的设计思想和原理,通过安装、显示、传输或者存储软件等方式使用软件的,可以不经软件著作权人许可,不向其支付报酬。”您需知晓本站所有内容资源均来源于网络,仅供用户交流学习与研究使用,版权归属原版权方所有,版权争议与本站无关,用户本人下载后不能用作商业或非法用途,需在24个小时之内从您的电脑中彻底删除上述内容,否则后果均由用户承担责任;如果您访问和下载此文件,表示您同意只将此文件用于参考、学习而非其他用途,否则一切后果请您自行承担,如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。
5.本站是非经营性个人站点,所有软件信息均来自网络,所有资源仅供学习参考研究目的,并不贩卖软件,不存在任何商业目的及用途
暂无评论内容