Вбудована консоль ASP.NET Core відмінно підходить для розробки. Проте в Production вам потрібен надійний спосіб зберігати логи: записувати їх у текстові файли з ротацією (новий файл щодня), відправляти в базу даних або надсилати у хмарні сервіси на кшталт DataDog, SEQ чи Application Insights.
Хоча стандартний ILogger на це здатен за допомогою додаткових провайдерів, індустріальним стандартом (де-факто) у світі .NET є бібліотека Serilog.
Serilog створений з нуля для підтримки Структурованого логування. Він надзвичайно швидкий, налаштовується дуже просто і має сотні "раковин" (Sinks) — плагінів для запису логів куди завгодно: від файлів до Slack.
Давайте замінимо стандартний логер ASP.NET Core на Serilog!
Через NuGet (або в терміналі dotnet add package) вам потрібно додати:
Serilog.AspNetCore (основний пакет ядра)Serilog.Sinks.Console (щоб писати в консоль своїми, красивішими кольорами)Serilog.Sinks.File (щоб писати логи в файл на диску)У Minimal APIs Serilog радить налаштовувати логер перед тим, як створювати WebApplicationBuilder, щоб у разі падіння на старті, ми встигли це залогувати.
using Serilog;
// 1. Попереднє налаштування (до builder'а)
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.WriteTo.Console()
.WriteTo.File("logs/myapp-.txt", rollingInterval: RollingInterval.Day)
.CreateLogger();
try
{
Log.Information("Старт додатку...");
var builder = WebApplication.CreateBuilder(args);
// 2. Вказуємо ASP.NET використовувати Serilog замість стандартної системи
builder.Host.UseSerilog();
var app = builder.Build();
app.MapGet("/", (ILogger<Program> logger) =>
{
// Цей виклик тепер автоматично пройде через Serilog!
logger.LogInformation("Отримано запит до головної сторінки.");
return "Serilog is working!";
});
app.Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "Додаток впав під час запуску");
}
finally
{
// 3. Закриваємо потоки файлів
Log.CloseAndFlush();
}
Анатомія коду:
RollingInterval.Day. Це означає, що Serilog самостійно створюватиме новий текстовий файл щодня (myapp-20241014.txt, myapp-20241015.txt) і писати туди журнали подій.builder.Host.UseSerilog(), ми замінили всю внутрішню систему ASP.NET Core. Будь-які компоненти фреймворку (чи ваші власні роути), які проситимуть ILogger<T>, автоматично отримуватимуть екземпляр Serilog, самі цього не знаючи!try-catch гарантує, що якщо додаток впаде через неправильні налаштування DI (наприклад), ми зможемо знайти причину в наших файлах.Часто вам потрібно знати відповіді на питання:
/api/users?Навіщо писати цей код вручну у кожному маршруті? Ми можемо використати вбудований HttpLoggingMiddleware (починаючи з ASP.NET Core 6+).
using Microsoft.AspNetCore.HttpLogging;
var builder = WebApplication.CreateBuilder(args);
// 1. Налаштовуємо деталізацію (що саме логувати)
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.RequestPath | // Шлях URL
HttpLoggingFields.RequestMethod | // Метод GET/POST
HttpLoggingFields.RequestHeaders | // Заголовки (напр. User-Agent)
HttpLoggingFields.ResponseStatusCode; // Статус відповіді (200, 404)
});
var app = builder.Build();
// 2. Вмикаємо Middleware
app.UseHttpLogging();
app.MapGet("/hello", () => "Welcome to HTTP Logging");
app.Run();
Після підключення app.UseHttpLogging(), фреймворк автоматично перехоплюватиме кожен запит і створюватиме гарні записи рівня Information із вибраними полями (LoggingFields).
RequestBody на Production.Якщо вбудованого UseHttpLogging вам недостатньо або він здається надто важким, створити власний кастомний Middleware для логування надзвичайно просто (ми робили щось подібне у розділі про Middleware).
var app = WebApplication.CreateBuilder(args).Build();
// Кастомний Inline Middleware для хронометража
app.Use(async (context, next) =>
{
var logger = context.RequestServices.GetRequiredService<ILogger<Program>>();
// Запам'ятовуємо час початку і шлях
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
var path = context.Request.Path;
try
{
// Відпускаємо запит далі по конвеєру
await next();
// Запит повернувся назад (усе ок)
stopwatch.Stop();
logger.LogInformation("Запит {Path} завершено за {ms} мс (Статус: {StatusCode})",
path, stopwatch.ElapsedMilliseconds, context.Response.StatusCode);
}
catch (Exception ex)
{
// Якщо хтось "впав" далі у конвеєрі
stopwatch.Stop();
logger.LogError(ex, "Запит {Path} впав з помилкою після {ms} мс",
path, stopwatch.ElapsedMilliseconds);
// Прокидаємо помилку далі (важливо!)
throw;
}
});
app.MapGet("/fast", () => "It was fast!");
app.MapGet("/slow", async () => { await Task.Delay(1000); return "It was slow..."; });
app.Run();
Анатомія коду:
ILogger прямо з поточного контексту (context.RequestServices).Stopwatch для точнішого вимірювання часу запиту.next() у try-catch. Завдяки цьому ми ловимо абсолютно всі помилки, які стаються в будь-якому з наших роутів, і красиво їх логуємо, перш ніж додаток поверне 500 помилку клієнту. Це паттерн "Global Exception Handling & Logging", який використовується у 99% комерційних проєктів.logs/). Відкрийте його та подивіться на вміст.app.UseHttpLogging(), але налаштуйте його так (через AddHttpLogging), щоб він логував АБСОЛЮТНО все (HttpLoggingFields.All).
Зробіть POST запит через Postman або Swagger, передавши якийсь JSON у тіло запиту (Body).
Подивіться в консоль логів. Знайдіть свій JSON там.LoggerConfiguration так, щоб він використовував .Enrich.WithMachineName() та .Enrich.WithThreadId(). (Вам доведеться завантажити відповідні NuGet пакети Serilog.Enrichers).
Розкажіть, який додатковий контекст додався до ваших записів і чому він корисний у мікросервісній архітектурі (де у вас працює кілька копій додатку на різних або одному сервері).Логування в ASP.NET Core: Основи
Уявіть, що ви ведете щоденник. Коли все добре, ви записуєте туди дрібні радощі. Коли виникає проблема — ви описуєте її детально, щоб потім проаналізувати. Логування (Logging) у програмуванні — це ведення такого "щоденника" вашим додатком.
Управління станом: HttpContext.Items та Cookies
Веб працює поверх протоколу HTTP, який за своєю природою не має стану (Stateless). Це означає, що сервер не пам'ятає вас між першим і другим запитом. Для сервера кожен запит — ніби від абсолютно нового користувача.