logging-and-observabilitylisted
Install: claude install-skill Sarmkadan/dotnet-senior-skills
# Logging and Observability
## Structured logging, or it did not happen
Message templates with named placeholders, never interpolation:
```csharp
// WRONG: one opaque string; unsearchable, allocates even when Info is filtered out
_logger.LogInformation($"Order {order.Id} shipped to {order.Country}");
// RIGHT: queryable fields OrderId and Country, zero cost when the level is off
_logger.LogInformation("Order {OrderId} shipped to {Country}", order.Id, order.Country);
```
Interpolated strings pay formatting and boxing before the level check; templates defer both. More importantly, `OrderId` becomes a field you can filter on in Seq/ELK/App Insights - `$"..."` produces N unique strings that group as N distinct messages.
Rules:
- Placeholder names are PascalCase and consistent codebase-wide: pick `OrderId` once; `orderId`, `order_id`, and `Id` in different call sites split the same field three ways.
- Never pass a whole entity as a placeholder value - `{Order}` calls `ToString()` (useless) or, with `{@Order}` destructuring, serializes every property including the ones you must not log (below).
- CA2254 ("template should be a static expression") as error: a variable template defeats the entire mechanism.
## Levels have meanings
- **Trace/Debug**: developer forensics, off in production by default. Payload dumps live here or nowhere.
- **Information**: business-meaningful events - order placed, payment captured, user registered. Not "entering method X"; that is what tracing is