Skip to main content
skill CX Codex

logging — Claude Code skill for .NET 10 health checks and correlation

A .NET 10 observability skill: splits liveness from readiness, wires correlation IDs, and sets log levels.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add codewithmukesh/dotnet-claude-kit --skill logging -a claude-code
Open on GitHub

What logging does

This skill owns the cross-cutting parts of observability that don't belong in a Serilog or OpenTelemetry setup. First piece: correlation ID middleware. It reads X-Correlation-Id from the request or generates one, stores it in HttpContext.Items, echoes it back in the response header, and pushes it onto LogContext so every log event in that request carries it. Register it early in the pipeline, otherwise downstream logs miss the ID.

Second piece: health checks. You get /health/live with no dependency checks and /health/ready filtered by the ready tag, covering the database, Redis and RabbitMQ. The split matters. Liveness failing means "restart me"; readiness failing means "stop routing traffic here". Merge them into one /health and a slow database will restart your app in a loop — worth checking against whatever your orchestrator expects.

There's also a log-level table: Debug in development, Information for business events, Warning as the production default. Deep Serilog configuration and traces with metrics live in the serilog and opentelemetry skills; this one just connects them. Logging secrets or PII at Information level is called out as an anti-pattern, with the fix shown in code.

What it helps with

  • split liveness and readiness into separate endpoints
  • carry a correlation ID through every log line of a request
  • pick a default log level for production
  • attach database, Redis and RabbitMQ checks to readiness
  • keep passwords and PII out of logs

Example prompts for the agent

  • Set up observability in .NET 10 with health checks and correlation IDs
  • Add /health/live and /health/ready with checks tagged ready
  • What log level should be the production default?

How to install logging

1Skills CLI (Vercel)

npx skills add codewithmukesh/dotnet-claude-kit --skill logging -a claude-code

2Manually: put the files in place

~/.claude/skills/logging/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/logging/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about logging

How do I install logging in Claude?

Run npx skills add codewithmukesh/dotnet-claude-kit --skill logging -a claude-code. The skill file lands at ~/.claude/skills/logging/SKILL.md.

What does the logging skill do?

It ties the observability pieces together for .NET 10 and owns the cross-cutting parts: health check endpoints, correlation IDs and log-level strategy. Serilog and OpenTelemetry setup is delegated to their own skills.

How is logging different from the serilog and opentelemetry skills?

Serilog handles structured logs and the AddSerilog() bootstrap, while opentelemetry covers traces and metrics with OTLP export. This skill sticks to health endpoints, correlation IDs and log levels.

Source text

SKILL.md · MIT
---
name: logging
description: >
  Observability overview and glue for .NET 10: how the pieces fit together,
  plus the cross-cutting parts owned here — ASP.NET health check endpoints
  (/health), correlation IDs, and log-level strategy. For deep Serilog setup
  load `serilog`; for traces and metrics load `opentelemetry`. Load this
  skill when setting up observability from scratch, wiring health check
  endpoints or correlation IDs, or when the user says "logging",
  "observability", "monitoring setup", "liveness", "readiness", or "ILogger".
---

# Logging & Observability

## Core Principles

1. **Structured logging with Serilog** — Every log entry is a structured event with named properties, not a formatted string. This enables searching, filtering, and alerting. All setup (two-stage bootstrap, `AddSerilog()`, sinks, enrichers) lives in the **serilog** skill — that skill's `AddSerilog()`-over-`UseSerilog()` guidance is canonical.
2. **OpenTelemetry for distributed tracing** — Traces connect requests across services; metrics track system health over time. Full setup lives in the **opentelemetry** skill.
3. **Health checks for operational readiness** — Every service exposes `/health` endpoints for load balancers and orchestrators. Liveness and readiness are separate questions and separate endpoints.
4. **Correlation IDs for request tracing** — Every request gets a unique ID that flows through all log entries and downstream service calls, so one user complaint maps to one filtered log stream.

## Patterns

### How the Pieces Fit Together

| Concern | Owner | Skill |
|---------|-------|-------|
| Structured application logs | Serilog (`AddSerilog()`) | `serilog` |
| Request summary logging | `UseSerilogRequestLogging()` | `serilog` |
| Traces + metrics + OTLP export | OpenTelemetry SDK | `opentelemetry` |
| Health endpoints, correlation IDs, log-level strategy | This skill | `logging` |

Wire logging first (you need logs to debug the rest), then health checks, then tracing.

### Correlation IDs

```csharp
// Middleware to set correlation ID
public class CorrelationIdMiddleware(RequestDelegate next)
{
    private const string CorrelationIdHeader = "X-Correlation-Id";

    public async Task InvokeAsync(HttpContext context)
    {
        var correlationId = context.Request.Headers[CorrelationIdHeader].FirstOrDefault()
            ?? Guid.NewGuid().ToString();

        context.Items["CorrelationId"] = correlationId;
        context.Response.Headers[CorrelationIdHeader] = correlationId;

        using (LogContext.PushProperty("CorrelationId", correlationId))
        {
            await next(context);
        }
    }
}

// Program.cs — register early so every downstream log carries the ID
app.UseMiddleware<CorrelationIdMiddleware>();
```

Why middleware: pushing the property once at the pipeline edge attaches it to every log event in the request scope — no per-call-site plumbing. Propagate the same header on outgoing `HttpClient` calls via a `DelegatingHandler` (see the **httpclient-factory** skill).

### Health Checks

```csharp
// Program.cs
builder.Services.AddHealthChecks()
    .AddNpgSql(builder.Configuration.GetConnectionString("Default")!,
        name: "database", tags: ["ready"])
    .AddRedis(builder.Configuration.GetConnectionString("Redis")!,
        name: "redis", tags: ["ready"])
    .AddRabbitMQ(builder.Configuration.GetConnectionString("RabbitMq")!,
        name: "rabbitmq", tags: ["ready"]);

// Map endpoints
app.MapHealthChecks("/health/live", new HealthCheckOptions
{
    Predicate = _ => false // No dependency checks — just "am I running?"
});

app.MapHealthChecks("/health/ready", new HealthCheckOptions
{
    Predicate = check => check.Tags.Contains("ready")
});
```

Why two endpoints: liveness failing means "restart me"; readiness failing means "stop sending traffic". Conflating them makes a slow database restart your app in a loop.

### Log-Level Strategy

| Level | Use for | Environment default |
|-------|---------|---------------------|
| Debug | Diagnostic detail, payload dumps (never PII in prod) | Development only |
| Information | Business events: order placed, job completed | Dev + staging |
| Warning | Recoverable anomalies: retry fired, fallback used | Everywhere — production default |
| Error | Failed operations that need attention | Everywhere |
| Fatal/Critical | App cannot continue | Everywhere |

Why Warning as the production default: Information-level request noise at scale costs real money in log storage and drowns the signals. Keep Information for genuine business events via namespace overrides (see the **serilog** skill's `MinimumLevel.Override` pattern).

## Anti-patterns

### Don't Log Sensitive Data

```csharp
// BAD — logging credentials
logger.LogInformation("User logged in: {Email} with password {Password}", email, password);

// GOOD — log identifiers, never secrets or PII at Information level
logger.LogInformation("User {UserId} logged in", userId);
```

### Don't Skip Health Check Tags

```csharp
// BAD — all checks run for liveness AND readiness
app.MapHealthChecks("/health");

// GOOD — separate liveness (am I running?) from readiness (can I serve traffic?)
app.MapHealthChecks("/health/live", new() { Predicate = _ => false });
app.MapHealthChecks("/health/ready", new() { Predicate = c => c.Tags.Contains("ready") });
```

### Don't Re-Implement What the Owning Skill Provides

```csharp
// BAD — hand-rolling Serilog bootstrap here from memory
builder.Host.UseSerilog(...);  // legacy API — the serilog skill forbids this

// GOOD — load the serilog skill and use its two-stage AddSerilog() bootstrap
builder.Services.AddSerilog((services, lc) => lc.ReadFrom.Configuration(builder.Configuration)...);
```

## Decision Guide

| Scenario | Recommendation |
|----------|---------------|
| Application logging setup | Load `serilog` — `AddSerilog()` two-stage bootstrap |
| Distributed tracing / metrics | Load `opentelemetry` — OTLP exporter |
| Custom business metrics | `IMeterFactory` + counters/histograms (`opentelemetry` skill) |
| Request tracing | Correlation ID middleware (this skill) |
| Container health | `/health/live` and `/health/ready` endpoints (this skill) |
| Log storage | Seq (development), Elastic/Grafana/OTLP backend (production) |
| Log levels | Debug in dev, Information in staging, Warning default in production |

© codewithmukesh · MIT · codewithmukesh/dotnet-claude-kit

Similar skills

Everything for Backend and APIs →

From the same set46

messaging A .NET skill that walks your agent through Wolverine or MassTransit setup, the outbox pattern, sagas, and RabbitMQ or Azure Service Bus brokers. CX Codex +1 2,800installs project-structure A skill that tells your agent how to lay out a .NET solution: central package versions, shared build properties, .slnx format and naming rules. CX Codex +1 2,800installs httpclient-factory Guides AI coding agents in configuring IHttpClientFactory and typed clients in .NET 10. Useful when building resilient HTTP pipelines and preventing socket exhaustion. CX Codex +1 2,800installs de-sloppify Runs a seven-step cleanup pass for .NET code, from formatting through CancellationToken propagation. Use it before a release or after larger changes and dependency updates. CX Codex +1 2,800installs ci-cd Generates CI/CD YAML pipelines for .NET projects. Useful when configuring GitHub Actions or Azure DevOps with build, test, format, and deployment stages. CX Codex +1 2,800installs resilience A skill that tells your coding agent how to build fault-tolerant calls in .NET 10 with Polly v8: retries, circuit breakers, timeouts, fallback. CX Codex +1 2,800installs authentication A skill that feeds your coding agent working patterns for ASP.NET Core auth: JWT bearer, OpenID Connect, Identity, authorization policies. CX Codex +1 2,800installs dependency-injection Guides dependency injection patterns in .NET 10, covering service lifetimes, keyed services, Scrutor decorators, and captive dependency fixes. CX Codex +1 2,800installs

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor