CSharpEssentials.LoggerHelper is a modular, centralized hub for Serilog sinks that delivers comprehensive observability . Its flexible JSON‑based configuration lets you decide which log levels go to which sink—for example, routing only Error messages to email while sending all logs to ElasticSearch—without touching your code . The package unifies logs, metrics and traces via OpenTelemetry; every log entry carries a trace_id to correlate distributed requests, and an interactive dashboard lets you visualize traces, sink failures and telemetry, and configure alerts . Standard structured fields (e.g., IdTransaction, ApplicationName, MachineName, Action) are included by default, and you can enrich logs with custom properties that propagate across all sinks . Each sink—Console, File, MSSQL, PostgreSQL, ElasticSearch, Email, Telegram, xUnit, Telemetry, Dashboard and AI—is delivered as a separate NuGet package, so you install only what you need; the core loads them dynamically and exposes CurrentError and an in‑memory Errors queue to simplify debugging . The latest AI integration enables natural‑language queries against logs, trace correlation for root‑cause analysis, anomaly detection and automatic incident summaries , while the new xUnit sink captures full traces of failed tests directly in your test output—ideal for debugging flaky tests or disconnected environments
$ dotnet add package CSharpEssentials.LoggerHelperTraceAsync on finally block of RequestResponseLoggingMiddlewareProperties handling and Email sinkIRequest interfaceLoggerHelper is a flexible and modular structured logging library for .NET (6.0/8.0) applications based on Serilog. It enables structured, multi-sink logging through a plug-and-play approach.
Action, IdTransaction, ApplicationName, MachineName{} mismatch errorsappsettings.LoggerHelper.jsonLoggerBuilder⚠️ Important for developers: In development mode, LoggerHelper automatically uses
appsettings.LoggerHelper.debug.json. This allows safe testing without affecting production settings.
#if DEBUG
.AddJsonFile("appsettings.LoggerHelper.debug.json")
#else
.AddJsonFile("appsettings.LoggerHelper.json")
#endif
dotnet add package CSharpEssentials.LoggerHelper
The full configuration JSON can be found in the original README. Important:
SerilogCondition for each sink with the desired LevelLevel is empty, the sink is ignoredTo activate LoggerHelper and enable request/response logging, configure your application in Program.cs as follows:
#if NET6_0
builder.AddLoggerConfiguration();
#else
builder.Services.AddLoggerConfiguration(builder);
#endif
Enable HTTP middleware logging:
app.UseMiddleware<RequestResponseLoggingMiddleware>();
Example appsettings.LoggerHelper.json configuration (⚠️ or appsettings.LoggerHelper.debug.json during development):
{
"Serilog": {
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Debug",
"System": "Debug"
}
},
"SerilogConfiguration": {
"ApplicationName": "TestApp",
"SerilogCondition": [
{"Sink": "ElasticSearch","Level": []},
{"Sink": "MSSqlServer","Level": []},
{"Sink": "Email","Level": []},
{"Sink": "PostgreSQL","Level": ["Information","Warning","Error","Fatal"]},
{"Sink": "Telegram","Level": ["Fatal"]},
{"Sink": "Console","Level": [ "Information" ]},
{"Sink": "File","Level": ["Information","Warning","Error","Fatal"]}
],
"SerilogOption": {
"File": {
"Path": "D:\Logs\ServerDemo",
"RollingInterval": "Day",
"RetainedFileCountLimit": 7,
"Shared": true
},
"TelegramOption": {
"chatId": "xxxxx",
"Api_Key": "sssss:ttttttttt"
},
"PostgreSQL": {
"connectionString": "<YOUR CONNECTIONSTRING>",
"tableName": "public",
"schemaName": "dbo",
"needAutoCreateTable": true,
"addAutoIncrementColumn": true,
"ColumnsPostGreSQL": [
{"Name": "Message","Writer": "Rendered","Type": "text"},
{"Name": "MessageTemplate","Writer": "Template","Type": "text"},
{"Name": "Level","Writer": "Level","Type": "varchar"},
{"Name": "TimeStamp","Writer": "timestamp","Type": "timestamp"},
{"Name": "Exception","Writer": "Exception","Type": "text"},
{"Name": "Properties","Writer": "Properties","Type": "jsonb"},
{"Name": "LogEvent","Writer": "Serialized","Type": "jsonb"},
{"Name": "IdTransaction","Writer": "Single","Property": "IdTransaction","Type": "varchar"},
{"Name": "MachineName","Writer": "Single","Property": "MachineName","Type": "varchar"},
{"Name": "Action","Writer": "Single","Property": "Action","Type": "varchar"},
{"Name": "ApplicationName","Writer": "Single","Property": "ApplicationName","Type": "varchar"}
]
},
"ElasticSearch": {
"nodeUris": "http://10.0.1.100:9200",
"indexFormat": "<YOUR INDEX FORMAT>"
},
"Email": {
"From": "<Email Alert>",
"Port": 587,
"Host": "<Host EMail>",
"To": [ "recipient#1", "recipient#2" ],
"username": "<UserName SMTP>",
"password": "<Password SMTP>"
},
"MSSqlServer": {
"connectionString": "<YOUR CONNECTIONSTRING>",
"sinkOptionsSection": {
"tableName": "logs",
"schemaName": "dbo",
"autoCreateSqlTable": true,
"batchPostingLimit": 100,
"period": "0.00:00:10"
},
"columnOptionsSection": {
"addStandardColumns": ["LogEvent"],
"removeStandardColumns": ["Properties"]
}
},
"GeneralConfig": {
"EnableSelfLogging": false
}
}
}
}
}
LoggerHelper supports logging to PostgreSQL with optional custom schema definition.
If ColumnsPostGreSQL is not set, the following default columns will be created and used:
message, message_template, level, raise_date, exception, properties, props_test, machine_nameIf ColumnsPostGreSQL is defined, LoggerHelper will use the exact fields provided.
Setting addAutoIncrementColumn: true will add an id SERIAL PRIMARY KEY automatically.
Example configuration:
"PostgreSQL": {
"connectionString": "...",
"tableName": "Logs",
"schemaName": "public",
"addAutoIncrementColumn": true,
"ColumnsPostGreSQL": [
{ "Name": "Message", "Writer": "Rendered", "Type": "text" },
{ "Name": "Level", "Writer": "Level", "Type": "varchar" }
]
}
If custom ColumnsPostGreSQL is defined, logs will include all specified fields.
🧩 Tip: PostgreSQL sink is ideal for deep analytics and long-term log storage. ⚠️ Note: When using
ColumnsPostGreSQL, always enableSelfLogduring development to detect unsupported or misconfigured column definitions. Invalid types or property names will be silently ignored unless explicitly logged via Serilog’s internal diagnostics.
LoggerHelper supports Telegram notifications to alert on critical events.
⚠️ Recommended Levels: Use only
ErrororFatalto avoid exceeding Telegram rate limits.
"TelegramOption": {
"chatId": "<YOUR_CHAT_ID>",
"Api_Key": "<YOUR_BOT_API_KEY>"
}
To configure a Telegram Bot:
📸 Example of a formatted Telegram message:
_logger.TraceSync(
new Request {
IdTransaction = Guid.NewGuid().ToString(),
Action = "SampleAction",
ApplicationName = "MyApp"
},
LogEventLevel.Information,
null,
"Sample log message: {Parameter}",
123
);
Or async:
await _logger.TraceAsync(
request,
LogEventLevel.Error,
ex,
"Something failed: {ErrorMessage}",
ex.Message
);
Starting from version 2.0.0, the
If you are upgrading from
1.x.x, you MUST update yourappsettings.LoggerHelper.json.
Old (before 2.0.0):
"Email": {
"From": "...",
"Host": "...",
"Port": 587,
"To": ["..."],
"CredentialHost": "...",
"CredentialPassword": "..."
}
New (since 2.0.0):
"Email": {
"From": "...",
"Host": "...",
"Port": 587,
"To": "...",
"username": "...",
"password": "...",
"EnableSsl": true
}
Starting from version 2.0.0, LoggerHelper no longer uses the standard Serilog.Sinks.Email for sending emails.
Reason:
The official Serilog Email Sink does not support custom body formatting (HTML templates, structured logs, color coding, etc).
It only supports plain text messages generated via RenderMessage(), without the ability to control the message content.
🔎 See discussion: GitHub Issue - serilog/serilog-sinks-email
What changed:
LoggerHelperEmailSink.✅ No third-party dependencies added. ✅ Full control over email appearance and content.
Since v2.0.0, LoggerHelper no longer uses Serilog.Sinks.Email. It ships with LoggerHelperEmailSink, allowing:
Example HTML placeholders:
{{Timestamp}}, {{Level}}, {{Message}}, {{Action}}, {{IdTransaction}}, {{MachineName}}, {{ApplicationName}}, {{LevelClass}}
LoggerHelper allows you to customize the HTML structure and appearance of the email body.
You can provide an external .html file with placeholders like:
{{Timestamp}}, {{Level}}, {{Message}}, {{Action}}, {{IdTransaction}}, {{MachineName}}, {{ApplicationName}}, {{LevelClass}}
Then, in the appsettings.LoggerHelper.json configuration file, set:
"LoggerHelper": {
"SerilogOption": {
"Email": {
...
"TemplatePath": "Templates/email-template-default.html"
}
}
}
This sink writes logs to a Microsoft SQL Server table and supports additional context properties out of the box.
"MSSqlServer": {
"connectionString": "<YOUR CONNECTIONSTRING>",
"sinkOptionsSection": {
"tableName": "logs",
"schemaName": "dbo",
"autoCreateSqlTable": true,
"batchPostingLimit": 100,
"period": "0.00:00:10"
},
"columnOptionsSection": {
"addStandardColumns": [
"LogEvent"
],
"removeStandardColumns": [
"Properties"
]
}
}
connectionString: Full connection string to the SQL Server instance.tableName: Name of the table that will receive log entries.schemaName: Schema to use for the log table (default is dbo).autoCreateSqlTable: If true, the log table will be created automatically if it does not exist.batchPostingLimit: Number of log events to post in each batch.period: Interval for batching log posts.addStandardColumns: Additional default Serilog columns to include (e.g., LogEvent).removeStandardColumns: Columns to exclude from the standard set.This sink automatically adds the following custom fields to each log:
IdTransaction: a unique identifier for tracking a transaction.MachineName: name of the server or machine.Action: custom action tag if set via Request.Action.ApplicationName: name of the application logging the message.ElasticSearch is ideal for indexing and searching logs at scale. When integrated with Kibana, it enables advanced analytics and visualization of log data.
"ElasticSearch": {
"nodeUris": "http://<YOUR_IP>:9200",
"indexFormat": "<YOUR_INDEX>"
}
nodeUris: The ElasticSearch node endpoint.indexFormat: The format or name of the index that will store log entries.Try live with full logging and structured output:
📁 [Demo Project]
✅ Now available for both .NET 6.0 and .NET 8.0:
Enable Serilog internal diagnostics:
SelfLog.Enable(msg => File.AppendAllText("serilog-selflog.txt", msg));
Alessandro Chiodo 📦 NuGet Package 🔗 GitHub