The easiest way to orchestrate Serilog. Send errors to Email, warnings to Telegram, info to Console — all from a simple JSON config or 5 lines of fluent C#.
dotnet add package CSharpEssentials.LoggerHelper
Built on Serilog, designed for real-world .NET applications. No boilerplate, no complexity.
Send Error to Email, Warning to Telegram, Information to Console — all declaratively. No custom code needed.
Full IntelliSense, compile-time safety. Or use JSON config — your choice. Switch between them or combine both.
Drop-in replacement for Microsoft.Extensions.Logging. Your existing ILogger<T> code works instantly — no refactoring.
Console, File, Email, Telegram, Elasticsearch, SQL Server, PostgreSQL, Seq, Hangfire Console. Install only what you need.
One-line middleware captures every HTTP request and response with correlation IDs, timing, and structured data.
Built-in Activity correlation. Logs automatically carry trace IDs and span IDs for distributed tracing.
Three steps. No configuration files, no XML, no boilerplate.
Core + the sinks you need. Each sink is a separate NuGet package.
# Core + Console sink dotnet add package CSharpEssentials.LoggerHelper dotnet add package CSharpEssentials.LoggerHelper.Sink.Console # Add more sinks as needed dotnet add package CSharpEssentials.LoggerHelper.Sink.File dotnet add package CSharpEssentials.LoggerHelper.Sink.Email
Fluent API with full IntelliSense. Define which levels go to which sinks.
builder.Services.AddLoggerHelper(b => b .WithApplicationName("MyApp") .AddRoute("Console", LogEventLevel.Information, LogEventLevel.Warning) .AddRoute("Email", LogEventLevel.Error, LogEventLevel.Fatal) .EnableRequestResponseLogging() );
{
"LoggerHelper": {
"ApplicationName": "MyApp",
"Routes": [
{ "Sink": "Console", "Levels": ["Information", "Warning"] },
{ "Sink": "Email", "Levels": ["Error", "Fatal"] }
]
}
}
If you already use ILogger<T>, your logs are automatically routed. Zero code changes.
// Your existing code works as-is. No changes needed! public class OrdersController(ILogger<OrdersController> logger) { public IActionResult Create(Order order) { logger.LogInformation("Order {Id} created", order.Id); // → Console logger.LogError("Payment failed for {Id}", order.Id); // → Email } }
Each sink is a separate NuGet package. Install only what you need. Click a sink to see its 5-line setup.
Colored output, per-level colors
Rolling JSON files, auto-cleanup
SMTP with HTML templates, throttling
Bot notifications with Markdown
Full-text search, auto-indexing
Structured storage, auto-create table
JSONB columns, typed schema
Structured log server, API key auth
Logs on Hangfire Dashboard during jobs
// dotnet add package CSharpEssentials.LoggerHelper.Sink.Console builder.Services.AddLoggerHelper(b => b .WithApplicationName("MyApp") .AddRoute("Console", LogEventLevel.Information, LogEventLevel.Warning, LogEventLevel.Error) );
// dotnet add package CSharpEssentials.LoggerHelper.Sink.File builder.Services.AddLoggerHelper(b => b .WithApplicationName("MyApp") .AddRoute("File", LogEventLevel.Warning, LogEventLevel.Error, LogEventLevel.Fatal) .ConfigureFile(f => f.Path = "logs/app-.json") );
// dotnet add package CSharpEssentials.LoggerHelper.Sink.Email builder.Services.AddLoggerHelper(b => b .WithApplicationName("MyApp") .AddRoute("Email", LogEventLevel.Error, LogEventLevel.Fatal) .ConfigureEmail(e => { e.SmtpServer = "smtp.gmail.com"; e.SmtpPort = 587; e.From = "alerts@myapp.com"; e.To = "team@myapp.com"; e.Username = "alerts@myapp.com"; e.Password = "app-password"; }) );
// dotnet add package CSharpEssentials.LoggerHelper.Sink.Telegram builder.Services.AddLoggerHelper(b => b .WithApplicationName("MyApp") .AddRoute("Telegram", LogEventLevel.Error, LogEventLevel.Fatal) .ConfigureTelegram(t => { t.BotToken = "123456:ABC-..."; t.ChatId = "-100123456"; }) );
// dotnet add package CSharpEssentials.LoggerHelper.Sink.Elasticsearch builder.Services.AddLoggerHelper(b => b .WithApplicationName("MyApp") .AddRoute("Elasticsearch", LogEventLevel.Information, LogEventLevel.Warning, LogEventLevel.Error) .ConfigureElasticsearch(e => e.NodeUri = "http://localhost:9200") );
// dotnet add package CSharpEssentials.LoggerHelper.Sink.MSSqlServer builder.Services.AddLoggerHelper(b => b .WithApplicationName("MyApp") .AddRoute("MSSqlServer", LogEventLevel.Warning, LogEventLevel.Error, LogEventLevel.Fatal) .ConfigureMSSqlServer(s => { s.ConnectionString = "Server=.;Database=Logs;Trusted_Connection=true"; s.TableName = "AppLogs"; }) );
// dotnet add package CSharpEssentials.LoggerHelper.Sink.Postgresql builder.Services.AddLoggerHelper(b => b .WithApplicationName("MyApp") .AddRoute("Postgresql", LogEventLevel.Warning, LogEventLevel.Error, LogEventLevel.Fatal) .ConfigurePostgreSql(p => { p.ConnectionString = "Host=localhost;Database=logs;Username=app;Password=secret"; p.TableName = "app_logs"; }) );
// dotnet add package CSharpEssentials.LoggerHelper.Sink.Seq builder.Services.AddLoggerHelper(b => b .WithApplicationName("MyApp") .AddRoute("Seq", LogEventLevel.Information, LogEventLevel.Warning, LogEventLevel.Error) .ConfigureSeq(s => { s.ServerUrl = "http://localhost:5341"; s.ApiKey = "your-api-key"; }) );
// dotnet add package CSharpEssentials.LoggerHelper.Sink.HangfireConsole // 1. Register the PerformContext accessor in DI builder.Services.AddHangfireConsoleSink(); // 2. Route logs to Hangfire Dashboard builder.Services.AddLoggerHelper(b => b .WithApplicationName("MyApp") .AddRoute("HangfireConsole", LogEventLevel.Information, LogEventLevel.Warning, LogEventLevel.Error) ); // 3. In your Hangfire job, set the PerformContext public class MyJob(IPerformContextAccessor accessor) { public void Execute(PerformContext context) { accessor.Set(context); // All ILogger calls now appear on the Hangfire Dashboard! accessor.Clear(); } }
The core package orchestrates routing; each sink is a separate NuGet.
Use the Sink name in routes (JSON or fluent). All packages target net6.0, net8.0, net9.0, and net10.0.
| Package | Route key | Purpose | |
|---|---|---|---|
CSharpEssentials.LoggerHelper |
— | Core routing, ILogger<T> bridge, JSON/fluent config, legacy Serilog JSON adapter |
NuGet |
CSharpEssentials.LoggerHelper.Sink.Console |
Console |
Colored console output, per-level themes | NuGet |
CSharpEssentials.LoggerHelper.Sink.File |
File |
Rolling JSON/text files, retention | NuGet |
CSharpEssentials.LoggerHelper.Sink.Email |
Email |
SMTP alerts, HTML templates, throttling | NuGet |
CSharpEssentials.LoggerHelper.Sink.Telegram |
Telegram |
Bot notifications, Markdown, throttling | NuGet |
CSharpEssentials.LoggerHelper.Sink.Elasticsearch |
Elasticsearch |
Elasticsearch / OpenSearch indexing | NuGet |
CSharpEssentials.LoggerHelper.Sink.MSSqlServer |
MSSqlServer |
SQL Server table sink, extra columns | NuGet |
CSharpEssentials.LoggerHelper.Sink.Postgresql |
PostgreSQL / Postgresql |
PostgreSQL structured logs, JSONB columns | NuGet |
CSharpEssentials.LoggerHelper.Sink.Seq |
Seq |
Seq centralized log server | NuGet |
CSharpEssentials.LoggerHelper.Sink.HangfireConsole |
HangfireConsole |
Hangfire Dashboard console output with colored log levels | NuGet |
CSharpEssentials.HttpHelper |
optional | HTTP client helpers with structured logging (companion to LoggerHelper) | NuGet |
v2–v4 migration: existing Serilog:SerilogConfiguration in appsettings.json is auto-mapped when LoggerHelper:Routes is empty — no rewrite required.
Template: dotnet new loggerhelper-api -n MyApi scaffolds an API with LoggerHelper pre-wired.
Edit the JSON config and see how logs are routed in real-time. Press Ctrl+Enter or click Run.
Step-by-step guides for the most common scenarios. Copy-paste and go.
using CSharpEssentials.LoggerHelper; using Serilog.Events; var builder = WebApplication.CreateBuilder(args); // Add LoggerHelper — 5 lines, done builder.Services.AddLoggerHelper(b => b .WithApplicationName("MyMinimalApi") .AddRoute("Console", LogEventLevel.Information, LogEventLevel.Warning) .AddRoute("File", LogEventLevel.Error, LogEventLevel.Fatal) .EnableRequestResponseLogging() ); var app = builder.Build(); app.UseLoggerHelper(); // Enables request/response middleware app.MapGet("/", (ILogger<Program> logger) => { logger.LogInformation("Hello from LoggerHelper!"); return "It works!"; }); app.Run();
using CSharpEssentials.LoggerHelper; using Serilog.Events; var builder = WebApplication.CreateBuilder(args); builder.Services.AddRazorComponents().AddInteractiveServerComponents(); // LoggerHelper works with Blazor Server out of the box builder.Services.AddLoggerHelper(b => b .WithApplicationName("MyBlazorApp") .AddRoute("Console", LogEventLevel.Information, LogEventLevel.Warning) .AddRoute("File", LogEventLevel.Error, LogEventLevel.Fatal) ); var app = builder.Build(); app.UseLoggerHelper(); app.MapRazorComponents<App>().AddInteractiveServerRenderMode(); app.Run(); // In any component or service, just inject ILogger<T> // @inject ILogger<MyComponent> Logger // Logger.LogInformation("Component rendered");
using CSharpEssentials.LoggerHelper; using Serilog.Events; var builder = WebApplication.CreateBuilder(args); // Azure: use File sink for App Service logs + Seq/Elasticsearch for centralized builder.Services.AddLoggerHelper(b => b .WithApplicationName("MyAzureApp") .AddRoute("Console", LogEventLevel.Information) // Azure log stream .AddRoute("File", LogEventLevel.Warning, LogEventLevel.Error, LogEventLevel.Fatal) .ConfigureFile(f => f.Path = "/home/LogFiles/app-.json") // Azure persistent storage .AddRoute("Email", LogEventLevel.Fatal) // Critical alerts only .ConfigureEmail(e => { e.SmtpServer = "smtp.sendgrid.net"; e.SmtpPort = 587; e.From = "alerts@myapp.com"; e.To = "ops@myapp.com"; }) .EnableRequestResponseLogging() ); var app = builder.Build(); app.UseLoggerHelper(); // ... your routes ... app.Run();
# docker-compose.yml — Seq for centralized log viewing services: app: build: . depends_on: [seq] seq: image: datalust/seq:latest environment: - ACCEPT_EULA=Y ports: ["5341:5341", "8081:80"] // Program.cs — route errors to Seq, info to console builder.Services.AddLoggerHelper(b => b .WithApplicationName("MyDockerApp") .AddRoute("Console", LogEventLevel.Information, LogEventLevel.Warning) .AddRoute("Seq", LogEventLevel.Information, LogEventLevel.Warning, LogEventLevel.Error, LogEventLevel.Fatal) .ConfigureSeq(s => s.ServerUrl = "http://seq:5341") );
using CSharpEssentials.LoggerHelper; using CSharpEssentials.LoggerHelper.Sink.HangfireConsole; using Serilog.Events; var builder = WebApplication.CreateBuilder(args); // 1. Register the PerformContext accessor builder.Services.AddHangfireConsoleSink(); // 2. Configure LoggerHelper with HangfireConsole route builder.Services.AddLoggerHelper(b => b .WithApplicationName("MyHangfireApp") .AddRoute("Console", LogEventLevel.Information, LogEventLevel.Warning) .AddRoute("HangfireConsole", LogEventLevel.Information, LogEventLevel.Warning, LogEventLevel.Error) ); // 3. In your Hangfire job class public class ProcessOrderJob( ILogger<ProcessOrderJob> logger, IPerformContextAccessor contextAccessor) { public void Execute(PerformContext context, int orderId) { contextAccessor.Set(context); // Activate dashboard logging logger.LogInformation("Processing order {OrderId}", orderId); // ... your job logic — all logs appear on Hangfire Dashboard ... logger.LogInformation("Order {OrderId} completed", orderId); contextAccessor.Clear(); // Cleanup } }
LoggerHelper adds a thin routing layer on top of Serilog. The overhead is negligible compared to the I/O cost of any real sink.
| Scenario | Raw Serilog | LoggerHelper v5 | Overhead |
|---|---|---|---|
| Single message (NullSink) | ~120 ns | ~135 ns | ~12% |
| 100 messages batch | ~11 μs | ~12 μs | ~9% |
| Structured payload (3 props) | ~180 ns | ~200 ns | ~11% |
| Below-min-level (filtered) | ~5 ns | ~15 ns | +10 ns |
| Multi-route (2 sinks) | n/a | ~140 ns | unique feature |
| Startup (full pipeline) | ~2 ms | ~8 ms | one-time cost |
* Measured with BenchmarkDotNet on .NET 10, NullSink (no I/O). Real sinks dominate the total time — routing overhead is invisible in practice. View benchmark source
| Feature | Raw Serilog | NLog | LoggerHelper v5 |
|---|---|---|---|
| Per-level sink routing (declarative) | Manual filter | XML rules | 1 line of JSON |
| ILogger<T> support | Via Serilog.Extensions.Logging | Via NLog.Extensions.Logging | Built-in, automatic |
| Fluent Builder API | WriteTo.X() | No | Full IntelliSense |
| Request/Response logging | Serilog.AspNetCore | Manual | 1 line middleware |
| Email/Telegram alerts | 3rd-party sinks | NLog.MailKit | Built-in + throttling |
| Setup complexity | 15-30 lines | XML + code | 5 lines |
Install the package, add 5 lines of code, and you're done. No configuration files, no XML, no complexity.
dotnet add package CSharpEssentials.LoggerHelper