логування у файл з використанням бібліотеки Serilog
翻译'%20fill-opacity='.8'%20d='M3.256%203.913a3.083%203.083%200%200%200-.003%204.397L8%2012.998l4.743-4.684a3.085%203.085%200%200%200%20.001-4.4c-.6-.593-1.4-.914-2.233-.914a3.17%203.17%200%200%200-1.91.635L8%204.087l-.601-.452A3.17%203.17%200%200%200%205.489%203c-.834%200-1.634.321-2.233.913m10.19%205.111-4.748%204.69a.996.996%200%200%201-1.397%200L2.549%209.02a4.083%204.083%200%200%201%20.004-5.82A4.17%204.17%200%200%201%205.488%202c.907%200%201.787.29%202.512.835A4.17%204.17%200%200%201%2010.51%202c1.093%200%202.146.422%202.936%201.202a4.085%204.085%200%200%201%200%205.822'%20/%3e%3c/svg%3e)

| // dotnet add Soccer.WebAPI package Serilog.AspNetCore | |
| // dotnet add Soccer.WebAPI package Serilog.Sinks.File | |
| // dotnet add Soccer.WebAPI package Serilog.Formatting.Compact # для JSON | |
| // папка з логами буде в Soccer.WebAPI/logs/ | |
| // не забудьте додати в .gitignore: text**/logs/ | |
| using Soccer.Application.DependencyInjection; | |
| using Soccer.Infrastructure.DependencyInjection; | |
| using Soccer.Infrastructure.Persistence; | |
| using Soccer.WebAPI.Middleware; | |
| using Serilog; | |
| // Serilog: створюємо логер до побудови host, | |
| // щоб навіть помилки старту потрапляли в логи | |
| Log.Logger = new LoggerConfiguration() | |
| .MinimumLevel.Information() | |
| .MinimumLevel.Override("Microsoft.AspNetCore", Serilog.Events.LogEventLevel.Warning) | |
| .MinimumLevel.Override("Microsoft.Hosting.Lifetime", Serilog.Events.LogEventLevel.Information) | |
| .Enrich.FromLogContext() | |
| .WriteTo.Console() // термінал | |
| .WriteTo.File( // файл з ротацією | |
| path: "logs/log-.txt", | |
| rollingInterval: RollingInterval.Day, | |
| retainedFileCountLimit: 14, | |
| outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}") | |
| .CreateLogger(); | |
| try | |
| { | |
| var builder = WebApplication.CreateBuilder(args); | |
| // Serilog: підміняємо стандартні провайдери логування | |
| builder.Host.UseSerilog(); | |
| string firebasePath = Path.GetFullPath( | |
| Path.Combine( | |
| builder.Environment.ContentRootPath, | |
| "..", | |
| "Soccer.Infrastructure", | |
| "firebase.json")); | |
| builder.Services.AddInfrastructure(firebasePath); | |
| builder.Services.AddApplication(); | |
| builder.Services.AddControllers(); | |
| var app = builder.Build(); | |
| // Serilog: компактне HTTP-логування запитів (метод, path, status, duration) | |
| app.UseSerilogRequestLogging(); | |
| app.UseMiddleware(); | |
| using (var scope = app.Services.CreateScope()) | |
| { | |
| var seeder = scope.ServiceProvider.GetRequiredService(); | |
| await seeder.SeedAsync(); | |
| } | |
| app.MapControllers(); | |
| app.Run(); | |
| } | |
| catch (Exception ex) | |
| { | |
| // Serilog: логуємо критичну помилку старту | |
| Log.Fatal(ex, "Application terminated unexpectedly"); | |
| } | |
| finally | |
| { | |
| // Serilog: коректно закриваємо логер (скидаємо буфери на диск) | |
| Log.CloseAndFlush(); | |
| } |
参与讨论