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.
Redact emails, credit cards, JWT/Bearer tokens, connection-string passwords and custom regex patterns from every sink at once — one JSON block, zero code changes.
Two lines of setup expose sink health, errors, and config to Claude, Cursor, or any MCP client. The only .NET logging library with native AI tooling — no Seq, no Kibana, no extra infrastructure.
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 // v5.0.1: FileNameProperty routes to subdirectories per tenant/module builder.Services.AddLoggerHelper(b => b .WithApplicationName("MyApp") .AddRoute("File", LogEventLevel.Warning, LogEventLevel.Error, LogEventLevel.Fatal) .ConfigureFile(f => { f.Path = "Logs"; f.FileNameProperty = "TenantId"; }) );
// 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.MCP NEW v5.1 |
— | MCP server: let Claude, Cursor, or any AI assistant query sink health, errors & config via POST /mcp (JSON-RPC 2.0, zero dependencies) |
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 } }
// 1. Install the MCP package // dotnet add package CSharpEssentials.LoggerHelper.MCP using CSharpEssentials.LoggerHelper.MCP; var builder = WebApplication.CreateBuilder(args); // 2. Register LoggerHelper + MCP (just 2 extra lines) builder.Services.AddLoggerHelper(b => b .WithApplicationName("MyApp") .AddRoute("Console", LogEventLevel.Information, LogEventLevel.Warning) ); builder.Services.AddLoggerHelperMcp(); // ← line 1 var app = builder.Build(); app.UseLoggerHelper(); app.MapLoggerHelperMcp("/mcp"); // ← line 2: POST /mcp is now live app.Run(); // 3. Connect Claude Desktop — add to claude_desktop_config.json: // { // "mcpServers": { // "loggerhelper": { // "url": "http://localhost:5000/mcp", // "transport": "streamable-http" // } // } // } // 4. Now ask your AI assistant: // "Are there any sink errors?" → loggerhelper_get_errors // "What sinks are active?" → loggerhelper_get_sinks // "What's the health status?" → loggerhelper_get_health // "Show me the current log config" → loggerhelper_get_config
The only .NET logging library with native AI tooling. Give Claude, Cursor, or any MCP-compatible client eyes into your logs — no Seq, no Kibana, no extra infrastructure.
Overall status: OK / WARNING / CRITICAL — active sink count and recent error count at a glance.
Recent sink errors (failed writes, SMTP issues, network timeouts). Accepts optional count parameter.
All configured sinks with ACTIVE / FAILED status and their assigned log levels.
Application name, routing rules, and sensitive data masking settings — the full running config.
# List available tools curl -X POST http://localhost:5000/mcp \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' # Check health curl -X POST http://localhost:5000/mcp \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"loggerhelper_get_health","arguments":{}}}' # Get last 5 sink errors curl -X POST http://localhost:5000/mcp \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"loggerhelper_get_errors","arguments":{"count":5}}}'
Zero dependencies: implemented with System.Text.Json + Microsoft.AspNetCore.App only. No external NuGet packages added to your project.
Protocol: JSON-RPC 2.0 over HTTP POST (MCP Streamable HTTP transport, spec 2024-11-05). Compatible with Claude Desktop, Cursor, GitHub Copilot, and any MCP HTTP client.
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 |
| Sensitive data masking (PII/secrets) | Manual IDestructuringPolicy | 3rd-party | JSON-driven, all sinks at once |
| AI assistant integration (MCP) NEW v5.1 | Requires separate Seq / Grafana | Not supported | Built-in, 2 lines — POST /mcp |
Install the package, add 5 lines of code, and you're done. No configuration files, no XML, no complexity.
dotnet add package CSharpEssentials.LoggerHelper