Логирование: ILogger, уровни, structured logging, Serilog

↑ 3.1 Хост, конфигурация и middleware pipeline · ← Предыдущая · → Следующая

Обязательно~3 мин чтенияУровень: middle

Зачем это на собесе

Логи — основа диагностики в проде. Спрашивают про уровни, structured logging и почему нельзя интерполировать строки.

Объяснение

ILogger<T> — абстракция логирования; провайдеры (Console, Serilog, OpenTelemetry) подключаются отдельно.

УровеньНазначение
Trace / Debugдетали отладки, выключены в проде
Informationзначимые события работы
Warningнештатная, но обработанная ситуация
Errorошибка операции
Criticalсбой приложения
// Structured logging: шаблон + параметры, а не интерполяция
logger.LogInformation("Order {OrderId} paid by {UserId} in {ElapsedMs} ms", order.Id, userId, ms);
 
// Исключение передаём отдельным параметром
logger.LogError(ex, "Failed to process order {OrderId}", order.Id);

Шаблон сохраняется как имя события, а параметры становятся полями — в Loki/Elasticsearch можно фильтровать по OrderId.

Source generator

public static partial class Log
{
    [LoggerMessage(EventId = 1001, Level = LogLevel.Information, Message = "Order {OrderId} paid")]
    public static partial void OrderPaid(this ILogger logger, Guid orderId);
}

Нет аллокаций на boxing и парсинг шаблона; удобно для горячих путей.

Serilog

builder.Host.UseSerilog((ctx, lc) => lc
    .ReadFrom.Configuration(ctx.Configuration)
    .Enrich.FromLogContext()
    .WriteTo.Console(new CompactJsonFormatter()));

Scopes и LogContext добавляют correlation id и tenant во все записи запроса.

Нюансы и подводные камни

  • $"..." в сообщении убивает structured logging и создаёт строку даже при выключенном уровне.
  • Не логируйте пароли, токены, персональные данные и тела запросов целиком.
  • Для тяжёлых аргументов проверяйте logger.IsEnabled(LogLevel.Debug).
  • Логируйте исключение один раз на границе, а не в каждом слое (иначе дубли).
  • Уровни по категориям задаются в Logging:LogLevel; Microsoft.AspNetCore обычно Warning.

Практика

  1. Настройте вывод в JSON и добавьте CorrelationId через scope.
  2. Перепишите три горячих лога на LoggerMessage.
  3. Отправьте логи в Seq/Loki и найдите запрос по OrderId.

Вопросы с ответами

Связанные темы