К основному содержанию
скилл CX Codex

serilog — скилл для Claude Code: установка и настройка логов

Скилл помогает настроить структурированное логирование Serilog в приложении .NET 10: уровни, приёмники, свойства событий и журналы HTTP-запросов.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add codewithmukesh/dotnet-claude-kit --skill serilog -a claude-code
Открыть на GitHub

Что делает serilog

Скилл описывает двухэтапный запуск Serilog: временный логгер ловит ошибки старта, затем AddSerilog() подключает конфигурацию и сервисы DI. Он разбирает appsettings.json, уровни и переопределения по SourceContext, а также приёмники Console, File, Seq и OTLP.

Для HTTP есть UseSerilogRequestLogging(): вместо нескольких событий ASP.NET Core он формирует одно итоговое событие на запрос. Можно добавить в него хост, UserAgent или идентификатор пользователя. Для свойств событий разбираются шаблоны сообщений, деструктуризация через @ и области LogContext.

Скилл также покрывает фильтры Serilog.Expressions, условную запись ошибок в отдельный файл и [LoggerMessage] для горячих путей. Для фильтров нужен пакет Serilog.Expressions; это повод проверить зависимости до добавления выражений в конфигурацию.

Какие задачи решает

  • настроить Serilog для приложения .NET 10
  • сохранить ошибки, возникшие до готовности DI
  • вынести уровни и приёмники журналов в appsettings.json
  • добавить свойства запроса через UseSerilogRequestLogging()
  • отфильтровать события с Serilog.Expressions

Примеры запросов агенту

  • Настрой Serilog с двухэтапным запуском в приложении .NET 10.
  • Добавь UseSerilogRequestLogging() и запиши UserId в события запросов.
  • Вынеси ошибки в logs/errors-.log через Serilog.Expressions.

Как установить serilog

1Через Skills CLI (Vercel)

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

2Вручную: положить файлы

~/.claude/skills/serilog/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/serilog/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Вопросы о serilog

Как установить serilog в Codex?

Выполните npx skills add codewithmukesh/dotnet-claude-kit --skill serilog -a codex. Файл скилла будет расположен в .agents/skills/serilog/SKILL.md.

Что делает скилл serilog?

Он даёт агенту инструкции по настройке структурированного логирования Serilog: начальная загрузка, конфигурация, приёмники, обогащение событий и журналы HTTP-запросов. Также рассматриваются деструктуризация и экспорт OTLP.

Что нужно для фильтров Serilog.Expressions?

Для выражений фильтрации требуется пакет Serilog.Expressions. С ним можно исключать запросы к проверке состояния и направлять ошибки в отдельный файл.

Исходный текст

SKILL.md · MIT
---
name: serilog
description: >
  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 DI
Log.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 data
logger.LogInformation("Order {OrderId} placed by {CustomerId} for {Total:C}",
    orderId, customerId, total);

// @ operator preserves object structure as properties
logger.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);
}

// Usage
logger.OrderCreated(order.Id, order.CustomerId);
```

## Anti-patterns

### Don't Use String Interpolation

```csharp
// BAD — breaks structured logging, allocates even when level is disabled
logger.LogInformation($"Order {orderId} created for {customerId}");

// GOOD — message template with named parameters
logger.LogInformation("Order {OrderId} created for {CustomerId}", orderId, customerId);
```

### Don't Skip CloseAndFlush

```csharp
// BAD — async sinks (Seq, OTLP, Elasticsearch) lose buffered events
app.Run();

// GOOD — wrap in try/finally
try { 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 logs
logger.LogInformation("Login: {Email} with password {Password}", email, password);

// GOOD — never log secrets, passwords, tokens, or PII
logger.LogInformation("Login: {Email}", email);
```

### Don't Destructure Without Limits

```csharp
// BAD — large object graphs cause memory issues and massive log entries
logger.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

| Scenario | Recommendation |
|----------|---------------|
| Application logging | Serilog 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 logging | `UseSerilogRequestLogging()` (replaces per-request noise) |
| Scoped properties | `LogContext.PushProperty()` in middleware |
| Log filtering | `Serilog.Expressions` for expression-based filtering |
| High-performance paths | `[LoggerMessage]` source generator |
| Audit trails | `AuditTo` (synchronous, exceptions propagate) |
| Log levels by environment | `MinimumLevel.Override` per namespace in appsettings |
| OpenTelemetry integration | `Serilog.Sinks.OpenTelemetry` (no SDK dependency) |

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

Похожие скиллы

Всё по теме «Бэкенд и API» →
logging-best-practices Mindrally Скилл задаёт правила логирования: структурный JSON, уровни, общие поля и работа с контекстом запроса. Пригодится, когда логи в проекте пишут кто как хочет. CX Codex +1 791установок go-logging cxuu Скилл для ИИ-агента, который подсказывает, как писать логи в Go: уровни, структурные поля, контекст запроса. Пригодится, когда проект на Go обрастает логами и надо навести порядок. CX Codex +1 1 000установок observability-and-instrumentation addyosmani Скилл учит агента добавлять структурированные логи, метрики и трейсы в код до деплоя. Пригодится при выпуске новых эндпоинтов, фоновых задач и интеграций. CX Codex +1 54 800установок otel-instrumentation dash0 Помогает агенту расставить спаны, метрики и логи OpenTelemetry так, чтобы телеметрия отвечала на вопросы, а не жгла бюджет. CX Codex +1 972установок observability официальный Vercel Labs Скилл настраивает сбор логов и метрик для приложений на Vercel. Помогает внедрить structured logging и подключить OpenTelemetry при сбоях. CX Codex GP ChatGPT 7установок aspireify Microsoft Скилл сканирует репозиторий, предлагает граф ресурсов и доводит AppHost до рабочего состояния. Пригодится сразу после aspire init. CX Codex +1 630установок

Из того же набора46

ef-core Набор паттернов Entity Framework Core для .NET 10. Помогает настроить DbContext, пакетные обновления, миграции и проекции запросов без лишней нагрузки на базу данных. CX Codex +1 2 800установок error-handling Задаёт стратегию обработки ошибок в .NET 10: Result, ProblemDetails, валидация и глобальный перехват исключений. Нужен при проектировании контрактов API. CX Codex +1 2 800установок architecture-advisor Задаёт вопросы про домен, команду и срок жизни системы, а потом советует архитектуру для .NET-проекта. Пригодится до того, как разложить решение по папкам. CX Codex +1 2 800установок docker Скилл настраивает контейнеризацию приложений на .NET 10: многоэтапную сборку, запуск под непривилегированным пользователем и проверку работоспособности. CX Codex +1 2 900установок vertical-slice Скилл помогает проектировать и писать .NET-приложения по принципам Vertical Slice Architecture вместо слоистой структуры. Пригодится при переносе логики в папки фич и настройке хэндлеров. CX Codex +1 2 900установок modern-csharp Подсказывает агенту синтаксис C# 14: первичные конструкторы, коллекционные выражения, ключевое слово field, блоки расширений. Пригодится, когда пишете новый код на C# или чистите старый. CX Codex +1 2 900установок outdated Собирает отчёт о здоровье зависимостей .NET: устаревшие NuGet-пакеты, уязвимые версии и ловушки с коммерческими лицензиями. CX Codex +1 2 800установок arch-check Сверяет кодовую базу с заявленной архитектурой: направление зависимостей, нарушения слоёв, утечки между модулями и циклы. Пригодится перед релизом или после крупной фичи. CX Codex +1 2 800установок

Спонсоры проекта

Компании, которые помогают держать аналитику открытой