Verwenden von „Microsoft.Extensions.Logging“ in EF Core

Microsoft.Extensions.Logging ist ein erweiterbarer Protokollierungsmechanismus mit Plug-In-Anbietern für viele gängige Protokollierungssysteme. Sowohl von Microsoft bereitgestellte Plug-Ins (z. B Microsoft.Extensions.Logging.Console) als auch Plug-Ins von Drittanbietern (z. B. Serilog.Extensions.Logging) sind als NuGet-Pakete verfügbar.

Entity Framework Core (EF Core) lässt sich vollständig in Microsoft.Extensions.Logging integrieren. Erwägen Sie jedoch die einfache Protokollierung für eine einfachere Methode zum Protokollieren, insbesondere für Anwendungen, die keine Abhängigkeitseinschleusung verwenden.

ASP.NET Core-Anwendungen

Microsoft.Extensions.Logging wird standardmäßig in ASP.NET Core-Anwendungen verwendet. Wenn Sie AddDbContext oder AddDbContextPool aufrufen, verwendet EF Core automatisch die Protokollierungseinrichtung, die über den regulären ASP.NET-Mechanismus konfiguriert wurde.

Andere Anwendungstypen

Andere Anwendungstypen können den GenericHost verwenden, um dieselben Abhängigkeitseinschleusungsmuster abzurufen, wie in ASP.NET Core verwendet werden. AddDbContext oder AddDbContextPool können dann wie in ASP.NET Core-Anwendungen verwendet werden.

Microsoft.Extensions.Logging kann auch für Anwendungen verwendet werden, die keine Abhängigkeitseinschleusung verwenden, obwohl die einfache Protokollierung einfacher einzurichten sein kann.

Microsoft.Extensions.Logging erfordert die Erstellung von LoggerFactory. Diese Factory sollte an einer beliebigen Stelle als statische/globale Instanz gespeichert und jedes Mal verwendet werden, wenn ein DbContext erstellt wird. Beispielsweise ist es üblich, die Logger-Factory als statische Eigenschaft im DbContext zu speichern.

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

Diese Singleton-/globale Instanz sollte dann bei EF Core auf dem DbContextOptionsBuilder registriert werden. Beispiel:

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

Abrufen detaillierter Nachrichten

Tipp

OnConfiguring wird weiterhin aufgerufen, wenn AddDbContext verwendet wird oder eine DbContextOptions-Instanz an den DbContext-Konstruktor übergeben wird. Dadurch ist es der ideale Ort, um die Kontextkonfiguration anzuwenden, unabhängig davon, wie der DbContext konstruiert wird.

Sensible Daten

Standardmäßig schließt EF Core die Werte von Daten in Ausnahmenachrichten nicht ein. Dies liegt daran, dass solche Daten vertraulich sein können und im Produktionsbetrieb offenbart werden können, wenn eine Ausnahme nicht behandelt wird.

Die Kenntnis von Datenwerten, insbesondere für Schlüssel, kann jedoch bei dem Debuggen sehr hilfreich sein. Dies kann in EF Core durch Aufrufen von EnableSensitiveDataLogging() aktiviert werden. Beispiel:

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

Detaillierte Abfrageausnahmen

Aus Leistungsgründen umschließt EF Core nicht jeden Aufruf, um einen Wert vom Datenbankanbieter in einem Try-Catch-Block zu lesen. Dies führt jedoch manchmal zu Ausnahmen, die schwer zu diagnostizieren sind, insbesondere dann, wenn die Datenbank einen NULL-Wert zurückgibt, obwohl das Modell dies nicht zulässt.

Das Aktivieren von EnableDetailedErrors führt dazu, dass EF diese Try-Catch-Blöcke einführt und dadurch detailliertere Fehler bereitstellt. Beispiel:

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

Konfiguration für bestimmte Nachrichten

Mit der EF Core-API ConfigureWarnings können Anwendungen ändern, was passiert, wenn ein bestimmtes Ereignis auftritt. Dies kann verwendet werden, um Folgendes zu tun:

  • Ändern der Protokollebene, auf der das Ereignis protokolliert wird
  • Vollständiges Überspringen der Protokollierung des Ereignisses
  • Auslösen einer Ausnahme, wenn das Ereignis auftritt

Ändern der Protokollebene für ein Ereignis

Manchmal kann es hilfreich sein, die vordefinierte Protokollebene für ein Ereignis zu ändern. Dies kann z. B. für die Promo von zwei zusätzliche Ereignisse von LogLevel.Debug zu LogLevel.Information verwendet werden:

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

Unterdrücken der Protokollierung eines Ereignisses

Auf ähnliche Weise kann ein einzelnes Ereignis aus der Protokollierung ausgeschlossen werden. Dies ist besonders nützlich, um eine Warnung zu ignorieren, die überprüft und verstanden wurde. Beispiel:

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

Auslösen für ein Ereignis

Schließlich kann EF Core so konfiguriert werden, dass es für ein bestimmtes Ereignis auslöst. Dies ist besonders nützlich, um eine Warnung in einen Fehler zu ändern. (Tatsächlich war dies der ursprüngliche Zweck der ConfigureWarnings-Methode, daher der Name.) Zum Beispiel:

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

Filtern und andere Konfigurationen

Einen Leitfaden zur Protokollfilterung und zu anderen Konfigurationen finden Sie unter Protokollierung in .NET.

EF Core-Protokollierungsereignisse werden in einem der Folgenden definiert:

  • CoreEventId für Ereignisse, die allen EF Core-Datenbankanbietern gemeinsam sind
  • RelationalEventId für Ereignisse, die allen relationalen Datenbankanbietern gemeinsam sind
  • Eine ähnliche Klasse für Ereignisse, die für den aktuellen Datenbankanbieter spezifisch sind. Beispiel: SqlServerEventId für den SQL Server-Anbieter.

Diese Definitionen enthalten die Ereignis-IDs, die Protokollebene und die Kategorie für jedes Ereignis, das von Microsoft.Extensions.Logging verwendet wird.