在 EF Core 中使用 Microsoft.Extensions.Logging

Microsoft.Extensions.Logging 是一种可扩展的日志记录机制,适用于很多常见日志记录系统的插件提供程序。 Microsoft 提供的插件(例如 Microsoft.Extensions.Logging.Console)和第三方插件(例如 Serilog.Extensions.Logging)都可作为 NuGet 包使用。

Entity Framework Core (EF Core) 与 Microsoft.Extensions.Logging 完全集成。 但是,请考虑使用简单的日志记录来获得更简单的日志记录方式,尤其是对于不使用依赖项注入的应用程序。

ASP.NET Core 应用程序

ASP.NET Core 应用程序中默认使用 Microsoft.Extensions.Logging。 调用 AddDbContextAddDbContextPool 可使 EF Core 自动使用通过常规 ASP.NET 机制配置的日志记录设置。

其他应用程序类型

其他应用程序类型可使用 GenericHost 获取与 ASP.NET Core 中使用的相同的依赖项注入模式。 然后,可像在 ASP.NET Core 应用程序中一样使用 AddDbContextAddDbContextPool

Microsoft.Extensions.Logging 也可用于不使用依赖项注入的应用程序,尽管设置简单的日志记录更容易。

Microsoft.Extensions.Logging 需要创建 LoggerFactory。 此工厂应存储为静态/全局实例,并在每次创建 DbContext 时使用。 例如,通常将记录器工厂存储为 DbContext 上的静态属性。

public static readonly ILoggerFactory MyLoggerFactory
    = LoggerFactory.Create(builder => { builder.AddConsole(); });

然后应在 DbContextOptionsBuilder 上向 EF Core 注册此单一实例/全局实例。 例如:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .UseLoggerFactory(MyLoggerFactory)
        .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFLogging;Trusted_Connection=True;ConnectRetryCount=0");

获取详细消息

提示

当使用 AddDbContext 或将 DbContextOptions 实例传递给 DbContext 构造函数时,仍会调用 OnConfiguring。 这使得它成为应用上下文配置的理想位置,而无需考虑如何构造 DbContext。

敏感数据

默认情况下,EF Core 不会在异常消息中包含任何数据的值。 这是因为这些数据可能是机密数据,如果不处理异常,可能会在生产使用中泄露这些数据。

但是,了解数据值(尤其是键值)在调试时非常有用。 可以通过调用 EnableSensitiveDataLogging() 在 EF Core 中启用此功能。 例如:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.EnableSensitiveDataLogging();

详细查询异常

出于性能原因,EF Core 不会在 try-catch 块中包装每个调用以从数据库提供程序读取值。 但是,这有时会导致难以诊断的异常,尤其是当数据库在模型不允许的情况下返回 NULL 时。

启用 EnableDetailedErrors 将导致 EF 引入这些 try-catch 块,从而提供更详细的错误。 例如:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.EnableDetailedErrors();

特定消息的配置

通过 EF Core ConfigureWarnings API,应用程序可以更改遇到特定事件时发生的情况。 这可以用于:

  • 更改记录事件的日志级别
  • 完全跳过事件记录
  • 发生事件时引发异常

更改事件的日志级别

有时,更改事件的预定义日志级别可能会很有用。 例如,这可用于将两个附加事件从 LogLevel.Debug 提升到 LogLevel.Information

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .ConfigureWarnings(
            b => b.Log(
                (RelationalEventId.ConnectionOpened, LogLevel.Information),
                (RelationalEventId.ConnectionClosed, LogLevel.Information)));

禁止记录事件

可以通过类似的方式取消记录单个事件。 这对于忽略已查看和了解的警告特别有用。 例如:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .ConfigureWarnings(b => b.Ignore(CoreEventId.DetachedLazyLoadingWarning));

针对事件引发异常

最后,EF Core 可以配置为针对给定事件引发异常。 这对于将警告更改为错误特别有用。 (这正是 ConfigureWarnings 方法的最初目的,并因此而得名。)例如:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .ConfigureWarnings(b => b.Throw(RelationalEventId.QueryPossibleUnintendedUseOfEqualsWarning));

筛选和其他配置

有关日志筛选和其他配置的指南,请参阅 .NET 中的日志记录

EF Core 日志记录事件在以下之一中定义:

  • CoreEventId,适用于所有 EF Core 数据库提供程序的通用事件
  • RelationalEventId,适用于所有关系数据库提供程序的通用事件
  • 一个类似类,适用于当前数据库提供程序特定的事件。 例如,SQL Server 提供程序的 SqlServerEventId

这些定义包含 Microsoft.Extensions.Logging 使用的每个事件的事件 ID、日志级别和类别。