From observability-skill
Use this skill when implementing .NET observability, logging, tracing, or metrics. Covers Serilog (structured logging, message templates, enrichers, sinks), Seq (querying, signals, dashboards), Elastic APM (native agent, ITracer, transactions, spans, distributed tracing), OpenTelemetry (ActivitySource, Meter, OTLP exporters), APM-log correlation (trace.id injection, W3C TraceContext), naming conventions (transaction names, span names, metric names, avoiding high-cardinality), and instrumentation patterns (middleware, action filters, IHttpClientFactory, EF Core, background services). Targets .NET 8+ (LTS). Prefers DI-first approach (ITracer, ILogger<T>) over static accessors. Invoke when: configuring Serilog or logging pipeline, setting up Elastic APM or OpenTelemetry, adding manual instrumentation (transactions, spans, activities), correlating logs with traces, debugging observability issues (missing traces, broken correlation, high-cardinality names), or when the user asks about logging, tracing, metrics, or monitoring patterns.
How this skill is triggered — by the user, by Claude, or both
Slash command
/observability-skill:observabilityThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
You are implementing observability for a .NET application. Read the relevant reference docs below based on what you're building. **Always use DI-first patterns** — inject `ITracer`, `ILogger<T>`, etc. rather than using static accessors.
You are implementing observability for a .NET application. Read the relevant reference docs below based on what you're building. Always use DI-first patterns — inject ITracer, ILogger<T>, etc. rather than using static accessors.
Good observability answers three questions: What happened? (logs), Where did it happen? (traces), How much? (metrics). Every signal should be correlated — a single request should be traceable across logs, spans, and metrics via trace context. See 12-observability-philosophy.md for the full framework.
Read the relevant docs based on your task:
Log.Information("Processing order {OrderId}", orderId) not Log.Information($"Processing order {orderId}"). Interpolation defeats structured logging.CurrentTransaction — _tracer.CurrentTransaction can be null when no transaction is active (background threads, startup code). Always guard: _tracer.CurrentTransaction?.StartSpan(...).Activity.Current — Activity.Current is null when no listener is registered or no parent activity exists. Always guard before accessing properties.try/finally { span.End(); } or the using pattern.span.CaptureException(ex) or activity?.SetStatus(ActivityStatusCode.Error) in the catch block, before the finally block ends the span.[LogMasked] attributes or custom destructuring policies.IHttpClientFactory. For message queues, manually inject/extract trace context.GET /api/orders/{id}) not resolved paths (GET /api/orders/12345).ITracer and ILogger<T> via constructor injection. Only use Agent.Tracer or Serilog.Log.Logger in non-DI contexts (startup, static helpers).Microsoft.AspNetCore to Warning, System.Net.Http to Warning, Microsoft.EntityFrameworkCore.Database.Command to Warning (or Information if you need query logging).LogContext.PushProperty for request-scoped enrichment — Don't repeat the same property on every log call. Push it once at the middleware/filter level.Task.Run, IHostedService) loses ambient trace context. Explicitly capture and restore Activity.Current or start a new transaction linked to the parent.Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub cpike5/cpike-agent-skills --plugin observability-skill