Wie hören Sie auf zu raten und beginnen, Ihren Code vollständig zu durchschauen?
Haben Sie schon einmal nachts vor dem Monitor gesessen, in Logs gestarrt, die einen Fehler schreien, aber über die Ursache schweigen? Oder versucht zu verstehen, warum Ihr Mikroservice in C# 10 Sekunden braucht, obwohl gestern alles flog? Kommt Ihnen bekannt vor? Willkommen in der Welt, in der Ihr Code ohne Observability eine Blackbox ist.
In diesem Artikel halten wir keine langweiligen Vorträge. Wir zerlegen die drei Säulen der Observability: Tracing, Metriken und Logs – und zeigen, wie Sie sie mit C# kombinieren. Sie erfahren, wie Sie aufhören, Brände zu löschen, und beginnen, sie zu verhindern. Los geht's!
Was ist Observability und warum ist es nicht nur "Logging"?
Viele verwechseln Observability mit einfachem Log-Sammeln. Aber der Unterschied ist enorm. Observability ist eine Eigenschaft des Systems, die es Ihnen erlaubt, beliebige Fragen über seinen Zustand zu stellen, ohne neuen Code hinzuzufügen. Die drei Säulen, auf denen alles basiert:
- Logs – diskrete Ereignisse. "Benutzer hat Button gedrückt", "Verbindungsfehler". Das ist "Was ist passiert?".
- Metriken – aggregierte Daten. "Anfragen pro Sekunde", "Speichernutzung". Das ist "Wie viel und wie oft?".
- Traces – der Weg einer Anfrage durch das System. "Anfrage kam, ging zur DB, dann zum Cache, kam zurück". Das ist "Warum so lange?".
In der C# .NET-Ökosystem werden diese drei Säulen mit Bibliotheken wie OpenTelemetry vereint. Und jetzt schauen wir uns an, wie das im Code aussieht.
Experiment: Wir schreiben eine Anwendung mit Observability
Stellen Sie sich vor, wir haben einen einfachen Dienst auf ASP.NET Core, der Bestellungen verarbeitet. Wir möchten sehen:
- Jeden Schritt der Bestellverarbeitung (Tracing).
- Wie viele Bestellungen verarbeitet wurden und mit welchem Fehler (Metriken).
- Details zu Ausnahmen (Logs).
Schritt 1: Logging mit Serilog einrichten
Beginnen wir mit dem Verständlichsten – den Logs. Wir verwenden Serilog (aber NLog geht auch). Es kann strukturierte Logs schreiben, die später einfach zu parsen sind.
// NuGet: Serilog, Serilog.AspNetCore, Serilog.Sinks.Consoleusing Serilog;
// Konfiguration in Program.csLog.Logger = new LoggerConfiguration() .WriteTo.Console() .WriteTo.File("logs/app.log", rollingInterval: RollingInterval.Day) .Enrich.WithProperty("Application", "OrderService") .CreateLogger();
var builder = WebApplication.CreateBuilder(args);builder.Host.UseSerilog(); // Ersetzt den Standard-Logger
// Beispielverwendung im Controller[ApiController][Route("api/[controller]")]public class OrderController : ControllerBase{ private readonly ILogger<OrderController> _logger;
public OrderController(ILogger<OrderController> logger) => _logger = logger;
[HttpPost] public IActionResult CreateOrder(Order order) { _logger.LogInformation("Creating order {OrderId} for user {User}", order.Id, order.UserId); // ... Logik ... _logger.LogWarning("Order {OrderId} is delayed due to stock issues", order.Id); return Ok(); }}Beachten Sie: Wir verwenden benannte Platzhalter ({OrderId}). Das ist nicht nur Text – es sind strukturierte Daten. In Elasticsearch oder Grafana Loki können Sie alle Logs nach einer bestimmten OrderId durchsuchen.
Schritt 2: Metriken mit Prometheus und .NET
Metriken sind für die "Zahlen" zuständig. Wie viele Anfragen pro Sekunde? Wie viele 500-Fehler? In C# verwenden wir Meters aus System.Diagnostics.Metrics oder die Bibliothek prometheus-net.
Erstellen wir einen einfachen Zähler für verarbeitete Bestellungen:
// NuGet: prometheus-net.AspNetCoreusing Prometheus;
// In Program.cs Metriken hinzufügenvar builder = WebApplication.CreateBuilder(args);