Ответ
Логирование — это систематическая запись событий, сообщений и данных о работе приложения во время его выполнения. Это критически важный инструмент для наблюдения за поведением системы в production, отладки проблем и аудита действий.
Зачем нужно логирование?
- Отладка в production: Воспроизвести баг на продакшене часто невозможно. Логи — это "черный ящик" приложения.
- Мониторинг: Понимание состояния системы, выявление аномалий и медленных операций.
- Аудит: Отслеживание действий пользователей (кто, что и когда сделал).
- Анализ производительности: Поиск узких мест с помощью замеров времени выполнения операций.
- Сбор статистики.
Уровни логирования (от наиболее детального к наиболее критичному):
Обычно соответствуют стандарту Microsoft.Extensions.Logging.LogLevel.
| Уровень | Когда использовать | Пример |
|---|---|---|
| Trace | Детальная отладочная информация, шаги алгоритма. | Entering method Calculate with param: {id} |
| Debug | Информация для отладки во время разработки. | Cache miss for key: {key} |
| Information | Отслеживание общего потока работы приложения. | Request {requestId} started for user {userId} |
| Warning | Неожиданное, но некритичное событие. | Failed to connect to backup service, using primary. |
| Error | Ошибка, которая не позволила выполнить конкретную операцию. | Failed to process order {orderId}. |
| Critical | Критический сбой, требующий немедленного вмешательства. | Database is unavailable. |
Практический пример с Serilog и Structured Logging:
// Настройка (часто в Program.cs)
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.Enrich.FromLogContext() // Для добавления контекста
.WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}")
.WriteTo.File("logs/app-.txt", rollingInterval: RollingInterval.Day) // Ротация по дням
.WriteTo.Seq("http://localhost:5341") // Отправка в централизованное хранилище Seq
.CreateLogger();
try
{
Log.Information("Starting web host...");
CreateHostBuilder(args).Build().Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly");
}
finally
{
Log.CloseAndFlush(); // Важно для буферизованных приемников
}
// Использование в сервисе с structured logging
public class OrderService
{
private readonly ILogger<OrderService> _logger;
public void ProcessOrder(Order order)
{
// Используйте именованные placeholders для структурированного логирования
_logger.LogInformation("Processing order {OrderId} for user {UserId}",
order.Id, order.UserId);
try
{
// Бизнес-логика
}
catch (PaymentException ex)
{
// Всегда передавайте исключение как отдельный параметр
_logger.LogError(ex, "Payment failed for order {OrderId}", order.Id);
throw;
}
}
}
Best Practices:
- Избегайте логирования в цикле на высоких уровнях (Info, Warn, Error), чтобы не "завалить" логи.
- Не логируйте конфиденциальные данные (пароли, токены, ПД).
- Используйте разные приемники (sinks): Console для разработки, файл/база данных/специализированные системы (ELK Stack, Seq, Application Insights) для production.
- Контекст — это ключ: Всегда добавляйте идентификаторы запросов (
requestId), ID пользователей, сущностей. Это позволяет связать все логи, относящиеся к одной операции. - Настройте уровни логирования через конфигурацию, чтобы включать детальное логирование (Debug) только при необходимости, не перезаписывая код.