Уявіть, що ви ведете щоденник. Коли все добре, ви записуєте туди дрібні радощі. Коли виникає проблема — ви описуєте її детально, щоб потім проаналізувати. Логування (Logging) у програмуванні — це ведення такого "щоденника" вашим додатком.
Коли додаток розгорнуто на реальному сервері (Production), ви не можете підключити до нього дебаггер (Visual Studio) і подивитися, чому сталася помилка. Логи — це єдине вікно у внутрішній світ вашої програми.
ASP.NET Core має потужну вбудовану систему логування, яка підтримує різні рівні деталізації та різні місця зберігання записів (Консоль, Файл, База даних, Хмарні сервіси).
ILoggerВзаємодія із системою логування завжди відбувається через інтерфейс ILogger (або узагальнену версію ILogger<T>).
Цей інтерфейс вже автоматично доданий у контейнер залежностей (DI), тому ми можемо легко отримати його у будь-якій кінцевій точці:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", (ILogger<Program> logger) =>
{
logger.LogInformation("Хтось щойно зайшов на головну сторінку!");
return "Hello logging!";
});
app.Run();
Анатомія коду:
ILogger<Program>. Категорія логера <Program> означає, що цей запис у журналі буде підписаний іменем "Program". Сюди зазвичай передають тип класу, де викликається логер, щоб легше було знайти, звідки прийшло повідомлення.LogInformation() робить запис із відповідним рівнем.Не всі події однаково важливі. Наприклад, успішне відкриття сторінки — це просто "Інформація", а от падіння бази даних — це "Критична помилка".
ASP.NET Core має 6 стандартних рівнів логування (від найнижчого до найвищого):
Інтерфейс ILogger має зручні методи-розширення для кожного з рівнів:
logger.LogTrace("...");
logger.LogDebug("...");
logger.LogInformation("...");
logger.LogWarning("...");
logger.LogError(new Exception("Oops"), "...");
logger.LogCritical("...");
Якщо у вас є об'єкт винятку (
Exception), завжди передавайте його першим аргументом уLogErrorабоLogCritical. Так система логування зможе правильно розпарсити (Stack Trace) і красиво відобразити його.
Логування споживає ресурси (процесор і пам'ять). Тому на Production ніхто не логує рівні Trace чи Debug.
Ви можете контролювати, події якого рівня має записувати логер, змінюючи appsettings.json.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
Що це означає?
"Default": "Information" — глобальне правило: записувати всі повідомлення рівнів Information, Warning, Error та Critical. Trace і Debug ігноруватимуться."Microsoft.AspNetCore": "Warning" — це перевизначення (override). Фреймворк ASP.NET Core сам по собі генерує тисячі логів. Це правило каже: "Для всіх компонентів від Microsoft, пишіть лише Warning і вище". Іншими словами — не спамте нас повідомленнями про те, який роут було викликано (бо це рівень Information)."Провайдер" — це те, куди фізично записуються логи.
Метод WebApplication.CreateBuilder автоматично налаштовує чотири провайдери:
Хоча стандартні налаштування покривають 90% потреб під час розробки, іноді вам потрібно додати новий провайдер або очистити старі.
var builder = WebApplication.CreateBuilder(args);
// Очищаємо всі стандартні провайдери
builder.Logging.ClearProviders();
// Вмикаємо лише вивід у консоль
builder.Logging.AddConsole();
// Або додаємо вивід у вікно дебагу Visual Studio
builder.Logging.AddDebug();
var app = builder.Build();
Раніше логи записували як звичайний текст:
// Погано: Звичайна конкатенація рядків (інтерполяція)
logger.LogInformation($"Користувач {username} змінив пароль о {DateTime.Now}");
Сучасні системи логування (наприклад, ELK Stack: Elasticsearch, Logstash, Kibana) вміють шукати і фільтрувати логи не як текст, а як об'єкти! ASP.NET Core підтримує цей формат.
// Добре: Структуроване логування (Semantic Logging)
logger.LogInformation("Користувач {UserId} оновив профіль з IP {IpAddress}", user.Id, ip);
Анатомія коду:
$ перед рядком (це не інтерполяція C#).{...}, а потім перераховуємо фактичні значення як аргументи через кому.{"Message": "Користувач 45 оновив профіль з IP 192.168.1.1", "UserId": 45, "IpAddress": "192.168.1.1"}.Знайти всі логи, де UserId = 45./test-logs, інжектуйте туди ILogger і викличте 5 методів логування для різних рівнів (від LogTrace до LogError).
Запустіть програму. Скільки записів ви бачите в консолі? Чому Trace та Debug не з'явилися?
Відкрийте appsettings.json та змініть Default рівень так, щоб у консоль виводилися абсолютно всі 5 повідомлень.Логування Exception Створіть маршрут, в якому ви штучно створюєте виняток:
try {
int x = 0; int y = 10 / x;
} catch (Exception ex) {
// Ваш код логування тут
}
Використайте правильний метод Log... і обов'язково передайте ex як перший параметр. Перевірте, чи відобразився Stack Trace у консолі.
Конфігурація: Паттерн Options
У попередньому розділі ми дізналися, що можемо діставати будь-яке налаштування просто викликавши config["Ключ:ВкладенийКлюч"].
Логування: Serilog та Middleware
Вбудована консоль ASP.NET Core відмінно підходить для розробки. Проте в Production вам потрібен надійний спосіб зберігати логи: записувати їх у текстові файли з ротацією (новий файл щодня), відправляти в базу даних або надсилати у хмарні сервіси на кшталт DataDog, SEQ чи Application Insights.