📝 Key Takeaways: Replace plain text logs with structured, queryable JSON logs. Leverage Elasticsearch, Kibana, or Seq for powerful log analysis.
Traditional text logs are impossible to search efficiently. Serilog brings structured logging to .NET.
🚀 Quick Setup
dotnet add package Serilog dotnet add package Serilog.Sinks.Console dotnet add package Serilog.Sinks.File dotnet add package Serilog.Sinks.ElasticSearch
// Program.cs
using Serilog;
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.WriteTo.Console()
.WriteTo.File("logs/myapp-.txt", rollingInterval: RollingInterval.Day)
.WriteTo.Elasticsearch(new ElasticsearchSinkOptions(new Uri("http://localhost:9200"))
{
IndexFormat = "myapp-logs-{0:yyyy.MM.dd}",
AutoRegisterTemplate = true
})
.CreateLogger();
var builder = WebApplication.CreateBuilder(args);
builder.Logging.ClearProviders();
builder.Logging.AddSerilog();
// Structured logging in action
app.MapGet("/api/orders/{id}", async (int id, ILogger<Program> logger) =>
{
logger.LogInformation("Fetching order {OrderId} for {User}", id, "john");
// Logs: {"OrderId": 123, "User": "john", "Message": "Fetching order 123 for john"}
});
💡 Advanced: Enrichers
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.Enrich.WithThreadId()
.Enrich.WithMachineName()
.Enrich.WithEnvironmentName()
.Enrich.WithProperty("Application", "MyAPI")
.CreateLogger();
// Usage:
using (LogContext.PushProperty("OrderId", orderId))
using (LogContext.PushProperty("UserId", userId))
{
logger.LogInformation("Processing order");
// All logs include OrderId and UserId!
}
📊 Querying with Kibana
# Find all errors with specific OrderId error AND OrderId:12345 # Find slow requests (duration > 1000ms) duration:>1000 # Find exceptions by type ExceptionType:"NullReferenceException" # Group by UserId and count errors SELECT UserId, COUNT(*) FROM myapp-logs-* WHERE Level=''Error'' GROUP BY UserId
