CodeGym /Kurse /C# SELF /Logging: Microsoft.Extensi...

Logging: Microsoft.Extensions.Logging

C# SELF
Level 64, Lektion 0
Verfügbar

1. Einführung

Im Programmieren ist Logging nicht einfach nur "irgendwas in die Konsole schreiben". Logging ist deine Blackbox, dein GPS-Tracker und dein Instrumentenfeld in einem. Ohne Logs wird ein großes Programm zur Blackbox-Rätselbox: "Warum ist der Service hängen geblieben?", "Warum hat der Nutzer die Mail nicht bekommen?", "Hat überhaupt jemand dieses Modul in den letzten 3 Monaten gestartet?" — auf all diese Fragen kann man oft nur antworten, wenn Logs gespeichert und verfügbar sind.

Warum Logging in der Praxis wichtig ist?

Fehlerfinden und Diagnose
Wenn das Programm abgestürzt ist — die Logs sagen dir, wo und warum. Wenn es nicht abgestürzt ist, aber sich merkwürdig verhält — die Logs zeigen die Schritte, die dazu geführt haben.

Monitoring des Zustands
Über Logs kann man sehen, ob das System gerade funktioniert, wie viele Anfragen beim Server ankommen, ob Fehler auftreten, wer was macht.

Sicherheit
Logging von Versuchen unautorisierter Zugriffe, verdächtiger Aktivitäten, Authentifizierungsfehlern.

Audit
Wer hat was wann gemacht. Wenn ein böser Admin gekündigt und Daten gelöscht hat, kann man anhand der Logs alles rekonstruieren (oder zumindest verstehen, was genau passiert ist).

Unterstützung in Entwicklung und Betrieb
Logs sind nicht nur für den Programmierer, sondern auch für Tester, Operatoren, Admins. In sechs Monaten wirst du dir selbst sagen: 'Danke, dass ich Logs hinzugefügt habe!'

Von Console.WriteLine zu industriellem Logging

Die erste Reaktion von Anfängern: "Reicht nicht einfach Console.WriteLine?". Für kleine Lernprogramme ist das oft genug. Aber sobald die Anwendung auf einem Server läuft, parallel arbeitet oder von Dutzenden/Hunderten Nutzern verwendet wird, ist die Konsole nicht mehr hilfreich. Man braucht:

  • Wichtige Informationen von Debug-Informationen trennen.
  • Logs nicht nur in die Konsole, sondern auch in Dateien, Datenbanken, zentralisierte Systeme schicken.
  • Den Detaillierungsgrad der Logs ändern können (mindestens — nur Errors, maximal — alles).
  • Automatisch Einträge mit Datum, Zeit und Zusatzinfos ergänzen.
  • Flexible Konfiguration.
  • Und vor allem — den Code nicht jedes Mal ändern müssen, um Logs an einen anderen Ort umzuleiten.

Hier beginnt die Ära der "echten" Logger.

2. Grundlagen eines modernen Logging-Systems in .NET

Im .NET-Ökosystem gibt es ein standardisiertes, mächtiges und flexibles Framework fürs Logging — Microsoft.Extensions.Logging. Es ist Teil der "neuen Welle" von .NET-Bibliotheken, die mit ASP.NET Core kamen, wird aber inzwischen überall verwendet: auf Servern, im Desktop und sogar in mobilen Apps.

Was macht dieses Framework gut?

  • Abstraktion — es bindet dich nicht an eine konkrete Implementierung (der Logger kann in Datei, Konsole, Cloud oder gleichzeitig in mehrere Ziele schreiben).
  • Unterstützung von Logging-Leveln (Trace, Debug, Information, Warning, Error, Critical).
  • Integration in den DI-Container und Einbindung in alle modernen .NET-Anwendungen.
  • Reiche Ecosystem-Erweiterungen: strukturierte Logs, erweiterte Formatter und Integrationen.

Wichtige Konzepte und Klassen

Lass uns die Schlüsselobjekte anschauen, die wir für die Arbeit mit Microsoft.Extensions.Logging brauchen:

Klasse/Interface Zweck
ILogger<T>
Interface fürs Logging, typisiert nach Klasse
ILogger
Generisches Logger-Interface
ILoggerFactory
Factory zum Erstellen von Logger-Instanzen
ILoggingBuilder
Ermöglicht die Konfiguration von Logging in der Anwendung
LogLevel
Aufzählung der Log-Level (Trace, Debug, Information, ...)

Log-Level

Die Aufteilung der Nachrichten nach Wichtigkeit erlaubt es, "Rauschen" zu filtern und das Gesuchte zu finden:

Level (LogLevel) Wofür verwenden?
Trace
Maximal detaillierte Debug-Infos, "Rauschen", zeitliche Daten
Debug
Hauptsächliche Debug-Informationen
Information
Wichtige Ereignisnachrichten für den normalen Betrieb
Warning
Warnungen vor potentiellen Problemen, das System läuft weiter
Error
Fehler, die Aufmerksamkeit erfordern, aber die Anwendung lebt
Critical
Kritische Ausfälle, die das gesamte System bedrohen

3. Praxis: Logging in unsere Anwendung einbauen

Schreiben wir keinen abstrakten Code, sondern entwickeln unsere Demo-App weiter. Angenommen, wir haben bereits eine einfache Calculator-Klasse, die wir im Kurs erweitern.

Beispiel: Basis-Calculator

public class Calculator
{
    public int Add(int a, int b)
    {
        return a + b;
    }
    // Ostatnie metody...
}

Jetzt bauen wir Logging ein. Dazu brauchen wir das Interface ILogger<Calculator>, das wir von außen erhalten (z. B. via Dependency Injection, DI).

using Microsoft.Extensions.Logging;

public class Calculator
{
    private readonly ILogger<Calculator> _logger;

    public Calculator(ILogger<Calculator> logger)
    {
        _logger = logger;
    }

    public int Add(int a, int b)
    {
        int result = a + b;
        _logger.LogInformation("Addition performed: {A} + {B} = {Result}", a, b, result);
        return result;
    }
}

Interessante Anmerkung:
Statt String-Konkatenation unterstützen Logger Templates und benannte Parameter ({A}, {B}, {Result}), was strukturierte Logs ermöglicht und die automatische Verarbeitung und Suche erleichtert.

4. Wie man einen Logger in einer Konsolenanwendung erstellt und konfiguriert

1. NuGet-Pakete einbinden

In deinem Projekt brauchst du:

  • Microsoft.Extensions.Logging
  • Microsoft.Extensions.Logging.Console (wenn du in die Konsole schreiben willst)
  • (optional) andere Provider, falls benötigt

2. Logger konfigurieren

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

// Erstelle den DI-Container
var serviceProvider = new ServiceCollection()
    .AddLogging(builder => {
        builder.AddConsole(); // Ausgabe in die Konsole
        builder.SetMinimumLevel(LogLevel.Debug); // Minimales Log-Level
    })
    .BuildServiceProvider();

// Hole die Logger-Instanz des gewünschten Typs
var logger = serviceProvider.GetRequiredService<ILogger<Calculator>>();

var calculator = new Calculator(logger);
calculator.Add(5, 3); // Die Nachricht landet im Log

Typischer Anfängerfehler
"Warum erscheint das Log nicht in der Konsole?" — prüfe, ob der passende Provider hinzugefügt ist (.AddConsole()) und ob das minimale Log-Level korrekt gesetzt wurde (SetMinimumLevel). Ist das Level zu hoch, werden Nachrichten einfach gefiltert!

5. Nützliche Feinheiten

Fehler und ungewöhnliche Situationen loggen

Angenommen, wir wollen Division durch Null loggen. Fügen wir die entsprechende Methode hinzu:

public int Divide(int a, int b)
{
    if (b == 0)
    {
        _logger.LogError("Attempt to divide by zero! a={A}", a);
        throw new DivideByZeroException();
    }
    int result = a / b;
    _logger.LogInformation("Division performed: {A} / {B} = {Result}", a, b, result);
    return result;
}

Warum das wichtig ist?
In einer realen Anwendung ziehen Logs mit Level Error meist besondere Aufmerksamkeit auf sich: sie werden automatisch an Admins gesendet, in Monitoring hervorgehoben und für Alerts/Benachrichtigungen verwendet.

Verwendung von Kategorien und Scopes

Der Logger in .NET unterstützt sogenannte scopes — zusätzliche Metadaten, die automatisch zu allen Logs innerhalb eines Codeblocks hinzugefügt werden. Wenn du z. B. eine Web-Anfrage oder eine Nutzersession verarbeitest, kannst du deren ID in einen scope legen.

using (_logger.BeginScope("UserId: {UserId}", 42))
{
    _logger.LogInformation("Nachrichtenverarbeitung für Nutzer gestartet");
    // ...
}

Alle Nachrichten innerhalb des Blocks bekommen das zusätzliche Tag UserId: 42, was später hilft, Logs nach Nutzern oder Operationen zu filtern.

Beispiel: Log-Level in Aktion

_logger.LogTrace("This is Trace — fast niemand wird es sehen");
_logger.LogDebug("This is Debug — für Entwickler");
_logger.LogInformation("This is Information — für normale Betriebsereignisse");
_logger.LogWarning("This is Warning — Warnung vor einer möglichen Problematik");
_logger.LogError("This is Error — Fehler, der Aufmerksamkeit braucht");
_logger.LogCritical("This is Critical — Das System brennt, Feuerwehr rufen!");

Wenn du SetMinimumLevel(LogLevel.Information) gesetzt hast, siehst du nur Nachrichten der Level Information, Warning, Error, Critical.

Trick:
Lass Trace und Debug für detaillierte Diagnose während der Entwicklung an, auf Produktionsservern schaltet man meist nur Information und höher ein, um Logs nicht aufzublähen und Wichtiges nicht im "Rauschen" zu verlieren.

Visuelles Schema: Architektur des modernen Loggings

graph TD
A[Anwendungscode] --ILogger<YourClass>--> B[Microsoft.Extensions.Logging]
B --> C1[Console Provider]
B --> C2[File Provider]
B --> C3[Cloud/Database Provider]
C1 -.-> D1[Logs in der Konsole]
C2 -.-> D2[Logs in Datei]
C3 -.-> D3[Logs in Monitoring-System]

subgraph Providers
    C1
    C2
    C3
end

6. Zusätzliche Möglichkeiten und Erweiterungen

Strukturiertes Logging:
Parameterwerte kann man nicht nur in Strings speichern, sondern als Key-Value, was Suche und Aggregation ermöglicht (z. B. mit Seq, ELK/ElasticSearch oder Application Insights).

Logging-Provider:
Du kannst dutzende Provider hinzufügen: File, Windows EventLog, Azure usw.

Konfiguration des Loggings über appsettings.json
In ASP.NET Core lässt sich Logging flexibel über Konfigurationsdateien steuern, ohne die Anwendung neu zu kompilieren.

Beispiel für die Einstellung des minimalen Log-Levels über die Config (appsettings.json):

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "MyApp.Calculator": "Debug",
      "Microsoft": "Warning"
    }
  }
}

7. Typische Fehler bei der Arbeit mit Microsoft.Extensions.Logging

Fehler Nr.1: Falsche Wahl des Log-Levels.
Die Nutzung von LogInformation für Fehler statt LogError oder LogCritical erschwert das Auffinden von Problemen in Produktion.

Fehler Nr.2: Ignorieren von strukturiertem Logging.
String-Konkatenation statt Templates mit Platzhaltern ({Parameter}) raubt die Vorteile des strukturierten Loggings, z. B. die Suche nach Parametern.

Fehler Nr.3: Falsche Konfiguration der Log-Level.
Wenn das minimale Log-Level zu hoch gesetzt ist (z. B. Warning statt Debug), können wichtige Nachrichten herausgefiltert werden.

Fehler Nr.4: Zu viel oder zu wenig Logging.
Zu detaillierte Logs (z. B. Trace in Produktion) erzeugen Rauschen, während fehlende Logs die Diagnose erschweren.

2
Aufgabe
C# SELF, Level 64, Lektion 0
Gesperrt
Basis-Logging mit 'Microsoft.Extensions.Logging'
Basis-Logging mit 'Microsoft.Extensions.Logging'
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION