CSharpEssentials.LoggerHelper
5.0.3
dotnet add package CSharpEssentials.LoggerHelper --version 5.0.3
NuGet\Install-Package CSharpEssentials.LoggerHelper -Version 5.0.3
<PackageReference Include="CSharpEssentials.LoggerHelper" Version="5.0.3" />
<PackageVersion Include="CSharpEssentials.LoggerHelper" Version="5.0.3" />
<PackageReference Include="CSharpEssentials.LoggerHelper" />
paket add CSharpEssentials.LoggerHelper --version 5.0.3
#r "nuget: CSharpEssentials.LoggerHelper, 5.0.3"
#:package CSharpEssentials.LoggerHelper@5.0.3
#addin nuget:?package=CSharpEssentials.LoggerHelper&version=5.0.3
#tool nuget:?package=CSharpEssentials.LoggerHelper&version=5.0.3
CSharpEssentials.LoggerHelper
Route Serilog sinks by log level — zero boilerplate, native
ILogger<T>support.
Install the NuGet, add 5 lines of JSON, and every ILogger<T> in your app automatically routes logs to Console, File, Email, Telegram, PostgreSQL, SQL Server, Elasticsearch, and Seq — each sink receiving only the levels you want.
dotnet add package CSharpEssentials.LoggerHelper
dotnet add package CSharpEssentials.LoggerHelper.Sink.Console
dotnet add package CSharpEssentials.LoggerHelper.Sink.File
dotnet add package CSharpEssentials.LoggerHelper.Sink.Email # add only what you need
Why LoggerHelper?
| Serilog alone | NLog | LoggerHelper v5 | |
|---|---|---|---|
| Per-level sink routing | Manual per sink | Via targets | JSON / fluent — built-in |
ILogger<T> compatible |
Via bridge pkg | Native | Native — zero code change |
| Install only needed sinks | No | No | Yes — modular NuGet |
| Named params preserved | Yes | Yes | Yes — through the bridge |
BeginScope structured |
Yes | Yes | Yes — propagates to Serilog |
| Scope nesting | Yes | Yes | Yes — accumulates properties |
| OpenTelemetry trace ID | Manual | Manual | Built-in, auto-correlated |
| Internal error diagnostics | No | No | Yes — injectable ILogErrorStore |
| Fluent OR JSON OR both | No | No | All three, mergeable |
Quick Start — 30 seconds
Option A — JSON config (recommended)
Program.cs
builder.Services.AddLoggerHelper(builder.Configuration);
app.UseLoggerHelper();
appsettings.LoggerHelper.json
{
"LoggerHelper": {
"ApplicationName": "MyApp",
"Routes": [
{ "Sink": "Console", "Levels": ["Information", "Warning"] },
{ "Sink": "File", "Levels": ["Information", "Warning", "Error", "Fatal"] },
{ "Sink": "Email", "Levels": ["Error", "Fatal"] }
],
"Sinks": {
"File": { "Path": "C:\\Logs\\MyApp", "RollingInterval": "Day" },
"Email": { "To": "ops@example.com", "Host": "smtp.example.com", "Port": 587 }
},
"General": { "EnableRequestResponseLogging": true }
}
}
That's it. Every ILogger<T> in your app now routes through LoggerHelper.
Option B — Fluent API
builder.Services.AddLoggerHelper(b => b
.WithApplicationName("MyApp")
.AddRoute("Console", LogEventLevel.Information, LogEventLevel.Warning)
.AddRoute("File", LogEventLevel.Information, LogEventLevel.Warning, LogEventLevel.Error, LogEventLevel.Fatal)
.AddRoute("Email", LogEventLevel.Error, LogEventLevel.Fatal)
.ConfigureFile(f => { f.Path = "C:\\Logs\\MyApp"; f.RollingInterval = "Day"; })
.EnableRequestResponseLogging()
);
Option C — JSON base + fluent overrides (merge)
// JSON defines shared config across environments.
// Fluent adds Development-only extras without touching JSON.
builder.Services.AddLoggerHelper(builder.Configuration, b => b
.AddRoute("Console", LogEventLevel.Debug) // extra sink only in code
);
Option D — Via ILoggingBuilder (respects Logging:LogLevel filters)
builder.Logging.ClearProviders();
builder.Logging.AddLoggerHelper(builder.Configuration);
Zero code changes for existing apps
If your app already uses ILogger<T>, you change nothing. LoggerHelper plugs in as a standard ILoggerProvider:
// Your existing service — not a single line changes
public class OrderService(ILogger<OrderService> logger) {
public void Process(int orderId) {
logger.LogInformation("Processing order {OrderId}", orderId); // → Console + File
logger.LogError("Payment failed for {OrderId}", orderId); // → File + Email
}
}
Named parameters like {OrderId} are preserved as structured Serilog properties — not flattened into strings.
BeginScope — context that travels with your logs
Add business properties once. Every log in that block carries them automatically, including logs inside methods you call:
using (_logger.BeginScope(new Dictionary<string, object?> {
["OrderId"] = orderId,
["UserId"] = userId
}))
{
_logger.LogInformation("Validation started"); // OrderId + UserId are here
await ValidateStock(); // logs inside also carry them
_logger.LogInformation("Order confirmed"); // OrderId + UserId are here
}
// Outside the using: properties removed automatically
Scope nesting — properties accumulate layer by layer:
using (_logger.BeginScope(new Dictionary<string, object?> { ["OrderId"] = 123 }))
{
using (_logger.BeginScope(new Dictionary<string, object?> { ["Provider"] = "Stripe" }))
{
_logger.LogInformation("Charging card");
// OrderId=123, Provider="Stripe"
}
_logger.LogInformation("Order complete");
// OrderId=123 (Provider removed)
}
Automatic enrichment on every log
Without any extra code, every log event carries:
| Property | Value |
|---|---|
ApplicationName |
Set via config or WithApplicationName() |
MachineName |
Environment.MachineName |
SourceContext |
Class name from ILogger<T> |
RenderedMessage |
Pre-rendered message string |
TraceId / SpanId |
From System.Diagnostics.Activity (OpenTelemetry) |
RequestPath / RequestId |
Added by ASP.NET Core middleware |
Available sinks
Each sink is a separate NuGet — install only what you need:
| Package | Target |
|---|---|
CSharpEssentials.LoggerHelper.Sink.Console |
Colored console output |
CSharpEssentials.LoggerHelper.Sink.File |
JSON rolling files |
CSharpEssentials.LoggerHelper.Sink.Email |
SMTP alerts with throttling |
CSharpEssentials.LoggerHelper.Sink.Telegram |
Bot notifications with throttling |
CSharpEssentials.LoggerHelper.Sink.Postgresql |
PostgreSQL structured logs |
CSharpEssentials.LoggerHelper.Sink.MSSqlServer |
SQL Server structured logs |
CSharpEssentials.LoggerHelper.Sink.Elasticsearch |
Elasticsearch + Kibana |
CSharpEssentials.LoggerHelper.Sink.Seq |
Seq centralized log server |
CSharpEssentials.LoggerHelper.Sink.HangfireConsole |
Hangfire Dashboard console logs |
Sinks self-register via a plugin mechanism — the core package has zero dependency on them.
Per-level routing — real-world example
"Routes": [
{ "Sink": "Console", "Levels": ["Debug", "Information", "Warning"] },
{ "Sink": "File", "Levels": ["Information", "Warning", "Error", "Fatal"] },
{ "Sink": "Telegram", "Levels": ["Error", "Fatal"] },
{ "Sink": "Email", "Levels": ["Fatal"] },
{ "Sink": "Elasticsearch", "Levels": ["Information", "Warning", "Error", "Fatal"] }
]
- Developers see everything on Console during development
- File captures all non-debug logs for auditing
- Telegram pings the team on every error
- Email sends a full report only for fatal crashes
- Elasticsearch indexes everything for Kibana dashboards
Migrating from v2/v4 (legacy JSON)
Legacy (Serilog:SerilogConfiguration) |
v5 (LoggerHelper) |
|---|---|
SerilogCondition |
Routes |
Level |
Levels |
SerilogOption |
Sinks |
See gap analysis for feature parity details.
Benchmarks
See docs/benchmarks.md for LoggerHelper v5 vs Serilog vs NLog comparisons.
Environment-aware configuration
LoggerHelper automatically picks the right file based on the current environment:
| Environment | File loaded |
|---|---|
Development |
appsettings.LoggerHelper.debug.json |
| Everything else | appsettings.LoggerHelper.json |
Internal diagnostics
If a sink fails to configure (wrong connection string, unreachable SMTP server), LoggerHelper captures the error silently and exposes it — your app keeps running:
app.MapGet("/health/logging", (ILogErrorStore errors) =>
errors.Count == 0
? Results.Ok("All sinks healthy")
: Results.Problem(string.Join("\n", errors.GetAll().Select(e => $"{e.SinkName}: {e.ErrorMessage}")))
);
Request / Response logging middleware
Enable HTTP request/response logging with a single setting:
"General": { "EnableRequestResponseLogging": true }
Then activate in the pipeline:
app.UseLoggerHelper();
Building a custom sink
- Create a project
CSharpEssentials.LoggerHelper.Sink.MyTarget - Implement
ISinkPlugin:
internal sealed class MyTargetSinkPlugin : ISinkPlugin {
public bool CanHandle(string sinkName) =>
sinkName.Equals("MyTarget", StringComparison.OrdinalIgnoreCase);
public void Configure(LoggerConfiguration loggerConfig, SinkRouting routing, LoggerHelperOptions options) {
var opts = options.GetSinkConfig<MyTargetOptions>("MyTarget")
?? options.BindSinkSection<MyTargetOptions>("MyTarget")
?? new MyTargetOptions();
loggerConfig.WriteTo.Conditional(
evt => routing.Matches(evt.Level),
wt => wt.MySink(opts.ConnectionString)
);
}
}
public static class PluginInitializer {
[ModuleInitializer]
public static void Init() => SinkPluginRegistry.Register(new MyTargetSinkPlugin());
}
- Reference
CSharpEssentials.LoggerHelperas a NuGet — not a project reference. - The sink auto-registers at startup with no changes to the core.
Performance
LoggerHelper v5 is built on Serilog, adding a thin MEL-compatible routing layer. Overhead vs raw Serilog is kept minimal — no reflection at log time, level checks short-circuit before routing evaluation.
Full benchmark results (auto-updated on each release) → docs/benchmarks.md
Benchmarks run with BenchmarkDotNet on .NET 9, comparing LoggerHelper v5 against Serilog (baseline) and NLog using no-op sinks to measure framework overhead independently of I/O.
Target frameworks
| Package | Targets |
|---|---|
| LoggerHelper core | net8.0 · net9.0 · net10.0 |
| Sink plugins | net8.0 · net9.0 · net10.0 |
TODO
Planned for upcoming releases — contributions welcome.
- Source Generator — replace runtime reflection for sink loading with a compile-time source generator: faster startup, AOT-compatible, trimming-safe
- BenchmarkDotNet suite — published performance comparisons vs Serilog pure, NLog, and Microsoft.Extensions.Logging default provider
-
dotnet newtemplate —dotnet new loggerhelper-apiscaffolds a pre-configured project with zero friction - Dashboard sink — embedded real-time UI showing active sinks, routing rules, and recent sink errors
- xUnit sink — forwards log output to xUnit test runner for integration test visibility
- AI extension — natural language log queries, anomaly detection, and incident summarization via LLM
- Telemetry extension — OpenTelemetry metrics export (log counters per sink, error rates, latency)
- Interactive playground — browser-based editor to test JSON routing config and see live output
License
MIT — © Alessandro Chiodo
Documentation · GitHub · NuGet
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Serilog (>= 4.2.0)
- Serilog.Settings.Configuration (>= 9.0.0)
-
net6.0
- Serilog (>= 4.2.0)
- Serilog.Settings.Configuration (>= 3.4.0)
-
net8.0
- Microsoft.Extensions.Configuration (>= 9.0.1)
- Microsoft.Extensions.Configuration.Binder (>= 9.0.1)
- Microsoft.Extensions.Configuration.Json (>= 9.0.1)
- Microsoft.Extensions.Logging (>= 9.0.1)
- Serilog (>= 4.2.0)
- Serilog.Settings.Configuration (>= 9.0.0)
-
net9.0
- Serilog (>= 4.2.0)
- Serilog.Settings.Configuration (>= 9.0.0)
NuGet packages (14)
Showing the top 5 NuGet packages that depend on CSharpEssentials.LoggerHelper:
| Package | Downloads |
|---|---|
|
CSharpEssentials.HttpHelper
Make every HTTP call resilient in one line. Built-in retry, rate limiting, and automatic logging — so your app keeps working when APIs don't. New in 5.0.1: File sink now supports dynamic subdirectories per tenant or module. |
|
|
CSharpEssentials.LoggerHelper.Sink.Console
See your logs in color, instantly. Add Console to your LoggerHelper routes and get beautiful, readable output — only the levels you care about. New in 5.0.1: File sink now supports dynamic subdirectories per tenant or module. |
|
|
CSharpEssentials.LoggerHelper.Sink.MSSqlServer
Query your logs with SQL. Auto-creates the table, batches the writes, and lets you JOIN logs with your business data — because sometimes grep isn't enough. New in 5.0.1: File sink now supports dynamic subdirectories per tenant or module. |
|
|
CSharpEssentials.LoggerHelper.Sink.Postgresql
Logs meet PostgreSQL. JSONB fields you can query, auto-created tables, and the full power of SQL — perfect for teams already running Postgres. New in 5.0.1: File sink now supports dynamic subdirectories per tenant or module. |
|
|
CSharpEssentials.LoggerHelper.Sink.Elasticsearch
Search millions of logs in milliseconds. Ship structured logs straight to Elasticsearch and build Kibana dashboards that actually tell you what's happening. New in 5.0.1: File sink now supports dynamic subdirectories per tenant or module. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 5.0.3 | 178 | 6/2/2026 |
| 5.0.2 | 286 | 6/1/2026 |
| 5.0.1 | 325 | 5/31/2026 |
| 5.0.0 | 298 | 5/31/2026 |
| 4.1.0 | 167 | 3/27/2026 |
| 4.0.13 | 171 | 2/28/2026 |
| 4.0.12 | 816 | 11/19/2025 |
| 4.0.11-beta | 175 | 11/15/2025 |
| 4.0.10.1 | 244 | 10/12/2025 |
| 4.0.10 | 569 | 10/12/2025 |
| 4.0.9.1 | 178 | 10/10/2025 |
| 4.0.9 | 144 | 10/10/2025 |
| 4.0.8 | 167 | 10/10/2025 |
| 4.0.7 | 215 | 10/8/2025 |
| 4.0.6 | 214 | 10/8/2025 |
| 4.0.5 | 798 | 9/27/2025 |
| 4.0.4 | 175 | 9/27/2025 |
| 4.0.3 | 296 | 9/14/2025 |
| 4.0.2 | 654 | 9/11/2025 |
| 4.0.1.1 | 209 | 9/11/2025 |