EF日志记录和诊断
系列文章列表,点击展示/隐藏
正文
Entity Framework 中的日志记录与诊断
在当今的软件开发中,日志记录是每个应用程序不可或缺的一部分。它对于调试、故障排除、性能优化、监控、告警以及安全审计等方面都至关重要。Entity Framework 提供了多种机制来生成日志和获取诊断信息。接下来,我们将深入探讨如何使用这些机制。
ToQueryString:快速查看生成的查询
查看 Entity Framework 生成的查询的最简单方法是使用 ToQueryString 方法。这个方法可以返回查询的字符串表示形式,非常适合快速调试。
.Where(p => p.Id == 1)
.Select(p => new { p.FirstName, p.LastName })
.ToQueryString();
Console.WriteLine(query);
// DECLARE @__p_0 bigint = CAST(1 AS bigint);
// SELECT[p].[FirstName], [p].[LastName]
// FROM[People] AS[p]
// WHERE[p].[Id] = @__p_0
这种方法简单易用,但功能有限。它仅适用于查询操作,而不适用于创建、修改或删除操作。因此,建议仅在调试时使用。
简单日志记录:记录所有 EF 操作
如果你希望记录所有 EF 操作的日志,包括事务管理和迁移,可以在配置 DbContext 时启用简单日志记录。
DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.LogTo(Console.WriteLine)
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
LogTo 方法接受一个字符串委托,EF 会为每个生成的日志消息调用此委托。通常,我们会使用 Console.WriteLine 将日志输出到控制台,但你也可以使用 Debug.WriteLine 将日志输出到调试窗口,或者使用 StreamWriter 将日志写入文件。
默认情况下,EF 不会在异常消息中包含数据值。如果你希望启用这一功能,可以使用 EnableSensitiveDataLogging 方法。此外,EnableDetailedErrors 方法会为每个数据库调用添加 try-catch 块,这对于诊断某些难以排查的异常非常有帮助。
需要注意的是,简单日志记录仅适用于开发阶段的调试。你不希望在生产环境中暴露敏感数据,同时 try-catch 块也可能会降低性能。
你还可以通过过滤日志来查找特定问题。
DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.LogTo(Console.WriteLine, LogLevel.Warning)
.LogTo(Console.WriteLine, new[] { CoreEventId.SaveChangesCompleted });
高级日志记录:使用 Microsoft.Extensions.Logging
对于高级日志记录,你可以使用 UseLoggerFactory 方法结合 Microsoft.Extensions.Logging 来实现。你可以使用 Microsoft 自带的日志记录器,也可以使用其他支持的日志记录器,例如 Serilog。
.WriteTo.Console()
.CreateLogger();
builder.Logging.ClearProviders();
builder.Logging.AddProvider(
new SerilogLoggerProvider(logger));
{
public DbSet<Person> People { get; set; }
private readonly ILoggerFactory _loggerFactory;
public MyContext(DbContextOptions<MyContext> options,
ILoggerFactory loggerFactory) : base(options)
{
_loggerFactory = loggerFactory;
}
protected override void OnConfiguring(
DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseLoggerFactory(_loggerFactory);
}
这种方法适用于所有环境,包括生产环境。不过,一定要注意不要记录敏感数据,或者配置日志记录器以避免暴露敏感数据。
拦截器:拦截数据库操作
拦截器允许你在数据库操作发送到数据库之前或之后进行拦截,并且可以对其进行修改。拦截器也可以用于日志记录和诊断。
Entity Framework 提供了多种拦截器接口,例如:
- IDbCommandInterceptor:拦截命令的创建和执行、命令失败以及命令的 DbDataReader 的释放。
- IDbConnectionInterceptor:拦截连接的打开和关闭以及连接失败。
- IDbTransactionInterceptor:拦截与事务和保存点相关的所有操作。
要注册拦截器,你需要在配置 DbContext 时使用 AddInterceptors 方法。
{
public override InterceptionResult<DbDataReader> ReaderExecuting(
DbCommand command,
CommandEventData eventData,
InterceptionResult<DbDataReader> result)
{
Console.WriteLine(command.CommandText);
return base.ReaderExecuting(command, eventData, result);
}
}
DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.AddInterceptors(new CommandQueryInterceptor());
你可以注册多个拦截器,但需要注意的是,拦截器是按 DbContext 注册的。
诊断监听器:跨多个 DbContext 实例的诊断
诊断监听器可以提供与拦截器相同的信息,但它可以跨当前 .NET 进程中的多个 DbContext 实例工作。
诊断监听器是 .NET 中的标准机制,但它并不是为日志记录而设计的。它更适合用于诊断。要使用诊断监听器,你需要创建一个观察者并将其注册为全局对象。
{
public void OnCompleted()
=> throw new NotImplementedException();
public void OnError(Exception error)
=> throw new NotImplementedException();
public void OnNext(DiagnosticListener value)
{
// "Microsoft.EntityFrameworkCore"
if (value.Name == DbLoggerCategory.Name)
{
value.Subscribe(new KeyValueObserver());
}
}
}
在 OnNext 方法中,我们查找 EF 的 DiagnosticListener。
接下来,我们需要为特定的 EF 事件创建一个键值观察者。
{
public void OnCompleted()
=> throw new NotImplementedException();
public void OnError(Exception error)
=> throw new NotImplementedException();
public void OnNext(KeyValuePair<string, object> value)
{
if (value.Key == CoreEventId.ContextIntialized.Name)
{
var payload = (ContextIntializedEventData)value.Value;
Console.WriteLine($"EF is initializing {payload.Context.GetType().Name} ");
}
}
}
在 OnNext 方法中,我们查找负责上下文初始化的 EF 事件。
总结
日志记录和诊断在 Entity Framework 中至关重要,它们有助于调试、优化性能、确保安全合规、实时监控以及教育开发人员。Entity Framework 提供了多种诊断和日志记录的方法,每种方法都有其优缺点。了解并学习如何使用这些方法来满足你的需求是非常重要的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
2023-02-21 .Net6 + GraphQL + MongoDb拦截器
2022-02-21 关于Code Review
2022-02-21 使用 dotnet watch 时包含 CSHTML 文件
2022-02-21 记一次公司项目缓存击穿
2022-02-21 C# 9 特性二
2022-02-21 C# 9 特性三