কেন Serilog?
Built-in ILogger থাকলেও Serilog structured log লেখে — JSON, Elasticsearch, Seq-এ analyze সহজ।
Setup
dotnet add package Serilog.AspNetCore
dotnet add package Serilog.Sinks.File
dotnet add package Serilog.Sinks.Seq
dotnet add package Serilog.Enrichers.Environment
// Program.cs
using Serilog;
builder.Host.UseSerilog((ctx, lc) => lc
.ReadFrom.Configuration(ctx.Configuration)
.Enrich.FromLogContext()
.Enrich.WithMachineName()
.Enrich.WithEnvironmentName()
.WriteTo.Console()
.WriteTo.File("logs/log-.txt", rollingInterval: RollingInterval.Day)
.WriteTo.Seq("http://localhost:5341"));
var app = builder.Build();
app.UseSerilogRequestLogging(); // HTTP request log automatic
appsettings.json Configuration
{
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"Microsoft.EntityFrameworkCore": "Information",
"System": "Warning"
}
},
"WriteTo": [
{ "Name": "Console" },
{
"Name": "File",
"Args": {
"path": "logs/log-.txt",
"rollingInterval": "Day",
"retainedFileCountLimit": 30
}
}
]
}
}
Structured Logging ⭐
public class ProductService {
private readonly ILogger<ProductService> _logger;
public ProductService(ILogger<ProductService> l) => _logger = l;
public async Task<Product?> GetAsync(int id) {
// ❌ Bad — string interpolation
_logger.LogInformation($"Fetching product {id}");
// ✅ Good — structured
_logger.LogInformation("Fetching product {ProductId}", id);
try {
var p = await _ctx.Products.FindAsync(id);
_logger.LogInformation("Found product {ProductId} {Name}", id, p?.Name);
return p;
}
catch (Exception ex) {
_logger.LogError(ex, "Failed to fetch product {ProductId}", id);
throw;
}
}
}
Log Levels
LogTrace— খুব detailedLogDebug— debugging infoLogInformation— normal flowLogWarning— unexpected but not errorLogError— error হয়েছে কিন্তু app চলছেLogCritical— app crash সম্ভাবনা
Scope (Correlation)
using (_logger.BeginScope("Order {OrderId}", orderId)) {
_logger.LogInformation("Processing");
_logger.LogInformation("Charging card");
// সব log-এ OrderId যুক্ত হবে
}
Seq — Log Server
// Docker docker run -d -p 5341:80 -e ACCEPT_EULA=Y datalust/seq // Browser: http://localhost:5341 // Filter: ProductId = 42, Level = Error
Elasticsearch + Kibana
dotnet add package Serilog.Sinks.Elasticsearch
.WriteTo.Elasticsearch(new ElasticsearchSinkOptions(new Uri("http://localhost:9200")) {
IndexFormat = "myapp-logs-{0:yyyy.MM}",
AutoRegisterTemplate = true
})
Application Insights (Azure)
builder.Services.AddApplicationInsightsTelemetry(
builder.Configuration["ApplicationInsights:ConnectionString"]);