Serilog

codewithmukesh/dotnet-claude-kit/skills/serilog

作者 codewithmukesh23300897f4d1無授權條款754 個星標收錄於 2026年10月8日更新於 2026年10月8日儲存庫2 個月前更新

Structured logging with Serilog for .NET 10 applications. Covers two-stage bootstrap, appsettings configuration, enrichers, sinks, request logging, destructuring, and Serilog.Expressions. Load this skill when setting up Serilog, configuring log sinks, enrichers, or structured logging, or when the user mentions "Serilog", "structured logging", "log enrichment", "Seq", "LogContext", "UseSerilog", "WriteTo", "message template", "Serilog.Expressions", "request logging", "log sink", "rolling file", or "audit log".

僅含說明

Serilog

Core Principles

  1. Two-stage initialization — Create a bootstrap logger for startup, then replace it with the full logger after DI is ready. This captures startup errors that would otherwise be lost.
  2. AddSerilog() over UseSerilog() — Use builder.Services.AddSerilog() (the modern API) instead of builder.Host.UseSerilog(). It integrates with DI services via ReadFrom.Services(services).
  3. Message templates, not interpolation — {PropertyName} syntax creates structured data that can be queried. String interpolation ($"...") breaks structure and allocates even when the log level is disabled.
  4. Configure via appsettings.json — Keep log levels, sinks, and overrides in configuration so they can change per environment without redeployment.

Patterns

Two-Stage Bootstrap Setup

csharp
using Serilog;
// Stage 1: Bootstrap logger — captures startup errors before DILog.Logger = new LoggerConfiguration()    .MinimumLevel.Override("Microsoft", LogEventLevel.Information)    .Enrich.FromLogContext()    .WriteTo.Console()    .CreateBootstrapLogger();
try{    Log.Information("Starting application");
    var builder = WebApplication.CreateBuilder(args);
    // Stage 2: Full logger with DI and configuration    builder.Services.AddSerilog((services, lc) => lc        .ReadFrom.Configuration(builder.Configuration)        .ReadFrom.Services(services)        .Enrich.FromLogContext()        .Enrich.WithMachineName()        .Enrich.WithEnvironmentName()        .Enrich.WithProperty("Application", "MyApp.Api"));
    var app = builder.Build();
    app.UseSerilogRequestLogging(options =>    {        options.EnrichDiagnosticContext = (diagnosticContext, httpContext) =>        {            diagnosticContext.Set("RequestHost", httpContext.Request.Host.Value);            diagnosticContext.Set("UserAgent",                httpContext.Request.Headers.UserAgent.ToString());        };    });
    app.Run();}catch (Exception ex){    Log.Fatal(ex, "Application terminated unexpectedly");}finally{    await Log.CloseAndFlushAsync();}

appsettings.json Configuration

json
{  "Serilog": {    "MinimumLevel": {      "Default": "Information",      "Override": {        "Microsoft": "Warning",        "Microsoft.AspNetCore": "Warning",        "Microsoft.EntityFrameworkCore": "Warning",        "Microsoft.Hosting.Lifetime": "Information",        "System": "Warning"      }    },    "WriteTo": [      {        "Name": "Console",        "Args": {          "outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}"        }      },      {        "Name": "File",        "Args": {          "path": "logs/app-.log",          "rollingInterval": "Day",          "retainedFileCountLimit": 30,          "fileSizeLimitBytes": 104857600        }      },      {        "Name": "Seq",        "Args": { "serverUrl": "http://localhost:5341" }      }    ],    "Enrich": ["FromLogContext", "WithMachineName", "WithEnvironmentName"],    "Destructure": [      { "Name": "ToMaximumDepth", "Args": { "maximumDestructuringDepth": 4 } },      { "Name": "ToMaximumStringLength", "Args": { "maximumStringLength": 1024 } },      { "Name": "ToMaximumCollectionCount", "Args": { "maximumCollectionCount": 10 } }    ]  }}

Override section uses namespace prefixes matched against SourceContext. More specific prefixes take precedence.

Request Logging Middleware

Replaces the multiple per-request log events from ASP.NET Core with a single summary event.

csharp
app.UseSerilogRequestLogging(options =>{    options.MessageTemplate =        "HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms";
    options.GetLevel = (httpContext, elapsed, ex) => ex is not null        ? LogEventLevel.Error        : httpContext.Response.StatusCode >= 500            ? LogEventLevel.Error            : LogEventLevel.Information;
    options.EnrichDiagnosticContext = (diagnosticContext, httpContext) =>    {        diagnosticContext.Set("UserId",            httpContext.User.FindFirstValue(ClaimTypes.NameIdentifier) ?? "anonymous");    };});

Structured Logging and Destructuring

csharp
// Named properties — creates queryable structured datalogger.LogInformation("Order {OrderId} placed by {CustomerId} for {Total:C}",    orderId, customerId, total);
// @ operator preserves object structure as propertieslogger.LogInformation("Processing {@SensorInput}", sensorInput);// Output: Processing {"Latitude": 25, "Longitude": 134}
// $ operator forces ToString()logger.LogInformation("Received {$Data}", new[] { 1, 2, 3 });// Output: Received "System.Int32[]"

Scoped Properties with LogContext

csharp
using (LogContext.PushProperty("CorrelationId", correlationId))using (LogContext.PushProperty("TenantId", tenantId)){    logger.LogInformation("Processing order {OrderId}", orderId);    // CorrelationId and TenantId attached to ALL log events in this scope}

Requires .Enrich.FromLogContext() on the logger configuration.

OpenTelemetry Sink (OTLP Export)

Export Serilog events directly to any OTLP backend without the OpenTelemetry SDK:

csharp
.WriteTo.OpenTelemetry(options =>{    options.Endpoint = "http://localhost:4317";    options.Protocol = OtlpProtocol.Grpc;    options.ResourceAttributes = new Dictionary<string, object>    {        ["service.name"] = "MyApp.Api",        ["deployment.environment"] = "production"    };})

Serilog.Expressions for Filtering

Requires the Serilog.Expressions package.

csharp
// Exclude health check noise.Filter.ByExcluding("RequestPath like '/health%'")
// Route errors to a separate file.WriteTo.Conditional("@l = 'Error'",    wt => wt.File("logs/errors-.log", rollingInterval: RollingInterval.Day))

[LoggerMessage] Source Generator for Hot Paths

Built into Microsoft.Extensions.Logging.Abstractions — compile-time generated, zero allocations when the level is disabled.

csharp
public static partial class OrderLogs{    [LoggerMessage(Level = LogLevel.Information,        Message = "Order {OrderId} created for {CustomerId}")]    public static partial void OrderCreated(this ILogger logger, Guid orderId, Guid customerId);}
// Usagelogger.OrderCreated(order.Id, order.CustomerId);

Anti-patterns

Don't Use String Interpolation

csharp
// BAD — breaks structured logging, allocates even when level is disabledlogger.LogInformation($"Order {orderId} created for {customerId}");
// GOOD — message template with named parameterslogger.LogInformation("Order {OrderId} created for {CustomerId}", orderId, customerId);

Don't Skip CloseAndFlush

csharp
// BAD — async sinks (Seq, OTLP, Elasticsearch) lose buffered eventsapp.Run();
// GOOD — wrap in try/finallytry { app.Run(); }catch (Exception ex) { Log.Fatal(ex, "Unhandled exception"); }finally { await Log.CloseAndFlushAsync(); }

Don't Log Sensitive Data

csharp
// BAD — passwords and tokens in logslogger.LogInformation("Login: {Email} with password {Password}", email, password);
// GOOD — never log secrets, passwords, tokens, or PIIlogger.LogInformation("Login: {Email}", email);

Don't Destructure Without Limits

csharp
// BAD — large object graphs cause memory issues and massive log entrieslogger.LogInformation("Request: {@Request}", httpContext.Request);
// GOOD — configure destructuring limits.Destructure.ToMaximumDepth(4).Destructure.ToMaximumStringLength(1024).Destructure.ToMaximumCollectionCount(10)
// BETTER — destructure to specific properties.Destructure.ByTransforming<HttpRequest>(r => new { r.Method, r.Path })

Don't Use the Deprecated Elasticsearch Sink

csharp
// BAD — the Serilog.Sinks.Elasticsearch PACKAGE is deprecated// <PackageReference Include="Serilog.Sinks.Elasticsearch" />.WriteTo.Elasticsearch("http://localhost:9200")
// GOOD — same method name, but from the official Elastic.Serilog.Sinks// package, which writes ECS-formatted documents to data streams// <PackageReference Include="Elastic.Serilog.Sinks" />.WriteTo.Elasticsearch([new Uri("https://elastic.example.com:9200")], opts =>    opts.DataStream = new DataStreamName("logs", "myapp"))

Decision Guide

ScenarioRecommendation
Application loggingSerilog with AddSerilog() and appsettings.json
Log storage (development)Seq (free single-user) or Aspire Dashboard
Log storage (production)Seq, Elasticsearch (Elastic sink), or OTLP backend
Request loggingUseSerilogRequestLogging() (replaces per-request noise)
Scoped propertiesLogContext.PushProperty() in middleware
Log filteringSerilog.Expressions for expression-based filtering
High-performance paths[LoggerMessage] source generator
Audit trailsAuditTo (synchronous, exceptions propagate)
Log levels by environmentMinimumLevel.Override per namespace in appsettings
OpenTelemetry integrationSerilog.Sinks.OpenTelemetry (no SDK dependency)

來源與署名

來源:codewithmukesh/dotnet-claude-kit位於skills/serilog提交2330089

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架

更多來自 codewithmukesh/dotnet-claude-kit 的技能

Wrap Up

codewithmukesh

在 session 結束時把已完成工作、待辦事項與經驗寫入交接檔案,並在 session 開始時重新載入。

Productivity & Workflow7542 個月前更新

Workflow Mastery

codewithmukesh

Claude Code workflow mastery for .NET developers. Covers parallel execution with git worktrees, plan mode strategy, verification loops, auto-formatting hooks, permission setup for dotnet CLI, prompting techniques, subagent patterns, and context discipline — token budget management, MCP-first navigation, lazy loading, and subagent isolation — all adapted for the .NET ecosystem. Load this skill when setting up Claude Code for a .NET project, optimizing workflows, running parallel sessions, when context is running low or sessions feel sluggish, when exploring a large codebase efficiently, or when the user mentions "productivity", "workflow", "parallel", "worktree", "plan mode", "permissions", "hooks", "10x", "setup Claude Code", "speed up development", "context", "tokens", "budget", "running out of context", "too many files", or "large codebase". Inspired by tips from Boris Cherny (creator of Claude Code) and the Anthropic team.

待分類7542 個月前更新

Vertical Slice

codewithmukesh

指導 .NET 開發者以垂直切片架構組織應用程式,涵蓋功能資料夾、端點分組與處理常式模式。

Software Development7542 個月前更新

Testing

codewithmukesh

Testing strategy for .NET 10 applications. Covers xUnit v3, WebApplicationFactory for integration tests, Testcontainers for real database testing, Verify for snapshot testing, and the AAA pattern. Load this skill when writing tests, setting up test infrastructure, reviewing test coverage, or when the user mentions "test", "xUnit", "WebApplicationFactory", "Testcontainers", "integration test", "unit test", "bUnit", "snapshot test", "Verify", "test coverage", "AAA pattern", "WireMock", or "FakeTimeProvider".

待分類7542 個月前更新

Tdd

codewithmukesh

Guided test-driven development workflow for .NET 10 using xUnit v3, WebApplicationFactory, Testcontainers, and Verify snapshots. Follows the strict red-green-refactor cycle. Use when: "TDD", "test-driven", "let's TDD this", "red green refactor", "write the test first", or when building a feature with clear acceptance criteria.

待分類7542 個月前更新

Spec

codewithmukesh

透過結構化提問,把模糊的功能想法轉化為雙方確認並持久化的規格文件。

Productivity & Workflow7542 個月前更新