| name | dotnet-observability |
| description | Configure OpenTelemetry tracing, metrics, and Serilog structured logging for .NET 10 applications. Use when user says "add logging", "set up tracing", "OpenTelemetry", "Serilog", "observability", "monitoring", "metrics", "distributed tracing", "structured logging", or asks about debugging production issues. |
| metadata | {"author":"Claude-DotNet-Ultimate","version":"1.0.0","category":"observability"} |
Observability Stack
Architecture
Application
├── Serilog (Structured Logging)
│ ├── Console Sink (dev)
│ ├── File Sink (rolling daily, 100MB)
│ └── Seq Sink (aggregation)
├── OpenTelemetry Tracing
│ ├── ASP.NET Core Instrumentation
│ ├── HTTP Client Instrumentation
│ ├── EF Core Instrumentation
│ ├── MassTransit Source
│ └── OTLP Exporter
└── OpenTelemetry Metrics
├── ASP.NET Core Metrics
├── HTTP Client Metrics
├── Runtime Metrics
└── OTLP Exporter
Serilog Configuration
Structured Logging Patterns
logger.LogInformation(
"Order {OrderId} created for customer {CustomerId} with {ItemCount} items",
orderId, customerId, items.Count);
using (logger.BeginScope(new Dictionary<string, object>
{
["CorrelationId"] = correlationId,
["UserId"] = userId
}))
{
logger.LogInformation("Processing payment");
}
logger.LogInformation($"Order {orderId} created");
logger.LogInformation("Order " + orderId + " created");
Log Levels
| Level | When to Use | Example |
|---|
| Trace | Detailed flow tracing | Method entry/exit |
| Debug | Development info | Variable values, state |
| Information | Normal operations | "Order created", "Request completed" |
| Warning | Recoverable issues | "Retry attempt 2/3", "Cache miss" |
| Error | Exceptions, failures | "Payment failed", unhandled exception |
| Fatal | System crash | "Database unreachable", data corruption |
Minimum Levels by Environment
| Source | Development | Production |
|---|
| Default | Debug | Information |
| Microsoft | Information | Warning |
| Microsoft.EFCore | Warning | Warning |
| MassTransit | Information | Warning |
OpenTelemetry Custom Tracing
public sealed class OrderService
{
private static readonly ActivitySource Source = new("ClaudeDotNetUltimate.Orders");
public async Task<Result<Guid>> CreateOrderAsync(CreateOrderCommand command, CancellationToken ct)
{
using var activity = Source.StartActivity("CreateOrder");
activity?.SetTag("customer.id", command.CustomerId);
activity?.SetTag("order.items_count", command.Items.Count);
try
{
var order = Order.Create(command.CustomerId, );
activity?.AddEvent(new ActivityEvent("OrderCreated",
tags: new ActivityTagsCollection { ["order.id"] = order.Id.Value }));
await repository.AddAsync(order, ct);
activity?.AddEvent(new ActivityEvent("OrderPersisted"));
activity?.SetStatus(ActivityStatusCode.Ok);
return order.Id.Value;
}
catch (Exception ex)
{
activity?.SetStatus(ActivityStatusCode.Error, ex.Message);
activity?.RecordException(ex);
throw;
}
}
}
Custom Metrics
public static class OrderMetrics
{
private static readonly Meter Meter = new("ClaudeDotNetUltimate.Orders");
public static readonly Counter<long> OrdersCreated =
Meter.CreateCounter<long>("orders.created", "orders", "Total orders created");
public static readonly Histogram<double> OrderProcessingDuration =
Meter.CreateHistogram<double>("orders.processing.duration", "ms", "Order processing time");
public static readonly UpDownCounter<int> ActiveOrders =
Meter.CreateUpDownCounter<int>("orders.active", "orders", "Currently active orders");
}
OrderMetrics.OrdersCreated.Add(1, new KeyValuePair<string, object?>("status", "success"));
Required Enrichment Properties
Every log entry must include:
Application — Service name
Environment — Development/Staging/Production
MachineName — Server/container hostname
ThreadId — For async debugging
Version — Application version
Sensitive Data Rules
NEVER log:
- Passwords or tokens
- Credit card numbers
- Social security numbers
- API keys or secrets
- PII without consent
Use sanitization:
logger.LogInformation("User {Email} logged in", email.MaskEmail());
Environment Variables
| Variable | Description |
|---|
OTEL_EXPORTER_OTLP_ENDPOINT | OpenTelemetry collector endpoint |
OTEL_SERVICE_NAME | Service name for traces |
SEQ_URL | Seq log aggregation URL |