Ответ
Логирование — это систематическая запись событий, сообщений и данных о работе приложения во время его выполнения. Это критически важный инструмент для наблюдения за поведением системы в 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) только при необходимости, не перезаписывая код.
Ответ 18+ 🔞
Давай разберёмся с этим вашим логированием, а то народ как обезьяна с гранатой — пишет в консоль Console.WriteLine и думает, что он архитектор.
Представь, твоё приложение — это как мужик в бане после трёх бутылок пива. Оно может внезапно грохнуться, начать нести хуйню или просто молча обоссаться в углу. Логи — это как видеокамеры в этой бане. Без них ты никогда не поймёшь, кто, когда и на каком уроне наступил на мыло.
Зачем это, блядь, нужно?
- Отладка на проде. Ты ж не будешь к клиенту на сервер с отладчиком подключаться? Вот и я о том. Логи — это твои глаза и уши там, куда тебе доступ закрыт.
- Мониторинг. Чтобы понять, что система не просто "тормозит", а конкретно, сука, запрос к этой ебучей платежке в 300 миллисекунд упирается.
- Аудит. Чтобы когда придет менеджер с вопросом "а кто это заказ №666 удалил?", ты мог не пиздеть, а показать строчку в логах.
- Производительность. Найти узкое место — это как понять, кто в бане последний пиво допил. Без замеров — нихуя не ясно.
Уровни, или "Насколько всё плохо?" Смотри, как в больнице: есть "сопливит нос", а есть "клиническая смерть". Так и тут.
| Уровень | Для чего | Как в жизни |
|---|---|---|
| Trace | Совсем мелкая отладочная хуйня. Шаги алгоритма. | "Сделал шаг левой ногой, потом правой". В проде это обычно выключено, ибо овердохуища текста. |
| Debug | Инфа для разработчика. | "Кэш промахнулся по ключу user_228". На проде включаем, только когда всё ебнулось и надо копать. |
| Information | Нормальная работа приложения. | "Пользователь Vasya зашёл в систему". Это чтобы видеть, что оно живое. |
| Warning | Странно, но не смертельно. | "Не удалось отправить статистику, но работаем дальше". Как предупреждение "осторожно, двери закрываются". |
| Error | Конкретная операция не удалась. | "Не смог сохранить заказ в БД". Вот тут уже надо внимание обращать. |
| Critical | Всё, пиздец, система или часть умерла. | "База данных не отвечает". Поднимай всех, даже тех, кто в отпуске. |
Как это выглядит в коде, на примере Serilog Не будем как лохи писать строки-склеенки. Структурированное логирование — это когда ты не просто текст пишешь, а данные отдельно. Потом их можно искать, как в базе.
// Настраиваем это безобразие где-то в начале программы (Program.cs)
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information() // Всё ниже Info (Debug, Trace) игнорируем
.Enrich.FromLogContext() // Магия, чтобы добавлять контекст (типа requestId)
.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("Запускаем хост... Поехали!");
CreateHostBuilder(args).Build().Run();
}
catch (Exception ex)
{
// Если всё упало на старте — пишем самое страшное
Log.Fatal(ex, "Хост неожиданно сдох. Совсем.");
}
finally
{
// Всегда смываем за собой, иначе последние логи могут потеряться в буфере
Log.CloseAndFlush();
}
// А вот как этим пользоваться в сервисе
public class OrderService
{
private readonly ILogger<OrderService> _logger; // Инжектим
public void ProcessOrder(Order order)
{
// ВАЖНО: используем именованные параметры, а не интерполяцию строк!
// Это позволит искать потом все логи по OrderId, например.
_logger.LogInformation("Обрабатываем заказ {OrderId} для пользователя {UserId}",
order.Id, order.UserId); // Смотри, данные отдельно
try
{
// ... тут твоя бизнес-логика, которая может ебнуться ...
}
catch (PaymentException ex)
{
// Всегда передавай само исключение первым параметром в LogError/Critical!
// Иначе стектрейс потеряется, и ты будешь как слепой котёнок.
_logger.LogError(ex, "Платеж провалился для заказа {OrderId}", order.Id);
throw; // Пробрасываем дальше, логирование — не обработка ошибки!
}
}
}
Главные правила, чтобы не быть мудаком:
- Не логируй в циклах на высоких уровнях. Представь, что ты логируешь
Informationна каждую итерацию в цикле на 100000 элементов. Твои логи съедят всё место на диске быстрее, чем толпа хачей на фуршете. - Никаких паролей, токенов и персональных данных в логах. Это не просто плохо, это пиздец как опасно. Тебя потом по GDPR ебут так, что мало не покажется.
- Контекст — твой лучший друг.
requestId,userId,orderId— вот это всё. Без этого логи это как рассказ алкоголика: вроде и события были, но связать их нихуя не возможно. - Уровни настраивай через конфиг. Чтобы не пересобирать проект, когда на проде всё полетело к хуям и нужно включить
Debug. Вынес вappsettings.jsonи поменял на лету. - Логирование — не замена исключениям. Записали ошибку в лог — и что? Система должна знать, как её обработать. Лог — для тебя, исключение — для программы.