v5.0 — Now with ILogger<T> support

Route Serilog sinks
by level, with zero code

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
9
Built-in Sinks
5
Lines to Setup
4
TFMs (net6–net10)
<2%
Routing Overhead

Everything you need to orchestrate logs

Built on Serilog, designed for real-world .NET applications. No boilerplate, no complexity.

🎯

Per-Level Sink Routing

Send Error to Email, Warning to Telegram, Information to Console — all declaratively. No custom code needed.

5-Line Fluent API

Full IntelliSense, compile-time safety. Or use JSON config — your choice. Switch between them or combine both.

🔌

ILogger<T> Native

Drop-in replacement for Microsoft.Extensions.Logging. Your existing ILogger<T> code works instantly — no refactoring.

🚀

9 Sinks, 1 NuGet Each

Console, File, Email, Telegram, Elasticsearch, SQL Server, PostgreSQL, Seq, Hangfire Console. Install only what you need.

📈

Request/Response Logging

One-line middleware captures every HTTP request and response with correlation IDs, timing, and structured data.

🔭

OpenTelemetry Ready

Built-in Activity correlation. Logs automatically carry trace IDs and span IDs for distributed tracing.

Up and running in 30 seconds

Three steps. No configuration files, no XML, no boilerplate.

1

Install the packages

Core + the sinks you need. Each sink is a separate NuGet package.

Terminal
# 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
2

Configure in Program.cs

Fluent API with full IntelliSense. Define which levels go to which sinks.

Program.cs
builder.Services.AddLoggerHelper(b => b
    .WithApplicationName("MyApp")
    .AddRoute("Console", LogEventLevel.Information, LogEventLevel.Warning)
    .AddRoute("Email", LogEventLevel.Error, LogEventLevel.Fatal)
    .EnableRequestResponseLogging()
);
appsettings.LoggerHelper.json
{
  "LoggerHelper": {
    "ApplicationName": "MyApp",
    "Routes": [
      { "Sink": "Console", "Levels": ["Information", "Warning"] },
      { "Sink": "Email",   "Levels": ["Error", "Fatal"] }
    ]
  }
}
3

Use it — or don't change anything

If you already use ILogger<T>, your logs are automatically routed. Zero code changes.

YourController.cs
// 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
    }
}

9 sinks, copy-paste ready

Each sink is a separate NuGet package. Install only what you need. Click a sink to see its 5-line setup.

🖥 Console

Colored output, per-level colors

📄 File

Rolling JSON files, auto-cleanup

✉ Email

SMTP with HTML templates, throttling

💬 Telegram

Bot notifications with Markdown

🔎 Elasticsearch

Full-text search, auto-indexing

🗃 SQL Server

Structured storage, auto-create table

🐘 PostgreSQL

JSONB columns, typed schema

📈 Seq

Structured log server, API key auth

⚙ Hangfire Console

Logs on Hangfire Dashboard during jobs

Console Sink — 3 lines
// dotnet add package CSharpEssentials.LoggerHelper.Sink.Console
builder.Services.AddLoggerHelper(b => b
    .WithApplicationName("MyApp")
    .AddRoute("Console", LogEventLevel.Information, LogEventLevel.Warning, LogEventLevel.Error)
);
File Sink — 5 lines
// 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")
);
Email Sink — 5 lines
// 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";
    })
);
Telegram Sink — 5 lines
// 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";
    })
);
Elasticsearch Sink — 5 lines
// 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")
);
SQL Server Sink — 5 lines
// 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";
    })
);
PostgreSQL Sink — 5 lines
// 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";
    })
);
Seq Sink — 4 lines
// 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"; })
);
Hangfire Console Sink — 5 lines
// 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();
    }
}

Modular packages — install only what you need

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.

Interactive Playground

Edit the JSON config and see how logs are routed in real-time. Press Ctrl+Enter or click Run.

Configuration (JSON)
Simulated Output

            

Works everywhere .NET runs

Step-by-step guides for the most common scenarios. Copy-paste and go.

Program.cs — Minimal API
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();
Program.cs — Blazor Server
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");
Program.cs — Azure App Service
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 + Program.cs
# 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")
);
Program.cs + Job — Hangfire with Dashboard logs
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
    }
}

Minimal overhead, maximum flexibility

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

What makes it different

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

Start routing your logs in 30 seconds

Install the package, add 5 lines of code, and you're done. No configuration files, no XML, no complexity.

$ dotnet add package CSharpEssentials.LoggerHelper
View on NuGet Star on GitHub