Exploring Serilog Enrichers in .NET 8

Chaitanya (Chey) Penmetsa
CodeNx
Published in
4 min readApr 12, 2024

In this blog let us see how we can use Serilog Enrichers for dynamically add useful and contextual properties to logs. We have already seen how Serilog helps in structured logging as well as how we can log to different destinations using Serilog Sinks, you can read those blogs using below links:

Image taken from Serilog github

What is Serilog Enricher?

A Serilog enricher is a feature that empowers us to dynamically include valuable contextual properties in our log entries. Essentially, it extends the capabilities of Serilog beyond a basic logging library, enabling us to augment our log messages with additional information based on the context in which they are generated.

When we talk about “enriching” logs, we mean enhancing them with details that provide a richer understanding of what happened during a particular event or action in our application. This extra information can be immensely helpful for debugging, monitoring, and auditing purposes. Serilog provides a variety of pre-built enrichers available on its GitHub page, offering functionalities such as adding timestamps, machine details, or user-specific data to logs. However, in some cases, we might need custom enrichers tailored to our specific application requirements.

Pros of Serilog Enrichers

  • Enhanced Log Context — Enrichers allow you to add contextual information to your log events, such as request details, user information, application state, or any custom data that can aid in debugging and analysis.
  • Centralized Logic — By encapsulating the logic for enriching log events in enricher classes, you centralize the code responsible for adding context. This makes your logging configuration cleaner and more maintainable. In general companies build there own logging NuGet packages which included all the enrichers along with logging middle ware.
  • Reusable and Configurable — Enrichers can be reused across multiple loggers or applications, promoting code reuse. You can configure enrichers to include specific properties or behaviors based on your application’s needs.

Cons of Serilog Enrichers

  • Performance Overhead — Adding too many enrichers or enriching log events with complex data can introduce performance overhead, especially in high-throughput applications. Care should be taken to avoid excessive enrichment.
  • Potential for Memory Leaks — Incorrectly implemented enrichers, especially those that store state, can lead to memory leaks if not managed properly. Ensure proper disposal of resources and avoid unnecessary data retention.
  • Debugging Challenges — Debugging issues related to enrichers, such as incorrect property values or missing context, might require additional effort due to the separation of the enrichment logic from the logging statements.

Now let us look how we can leverage existing Enricher and even add a custom enricher to our web api sample project which we have been using for demonstrating Serilog functionality. Since we already mentioned there are many built-in enrichers let us see different ways, we can add them. First let us look at how we can add them via configuration as shown below:

{
"Serilog": {
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File", "Serilog.Sinks.MSSqlServer" ],
"MinimumLevel": "Debug",
"WriteTo": [
{ "Name": "Console" },
{
"Name": "File",
"Args": { "path": "Logs/log.txt" }
},
{
"Name": "MSSqlServer",
"Args": {
"connectionString": "Server=Yourserver;Database=SerilogSample;Trusted_Connection=True;TrustServerCertificate=True;",
"tableName": "Logs",
"autoCreateSqlTable": true
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId", "WithExceptionDetails" ]
},
"AllowedHosts": "*"
}

Now let us look at how we can add enricher using code by adding a custom enricher to the code. First let’s add a custom enricher which will add http request related properties to log context while loading the logs. Below is the code for custom enricher:

 using Serilog.Core;
using Serilog.Events;

namespace ResidentAPI.CustomEnrichers
{
public class HttpRequestAndCorrelationContextEnricher : ILogEventEnricher
{
private readonly IHttpContextAccessor _httpContextAccessor;

public HttpRequestAndCorrelationContextEnricher(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}

public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
// Get HttpContext properties here
var httpContext = _httpContextAccessor.HttpContext;

if (httpContext != null)
{
// Add properties to the log event based on HttpContext
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("RequestMethod", httpContext.Request.Method));
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("RequestPath", httpContext.Request.Path));
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("UserAgent", httpContext.Request.Headers["User-Agent"]));

//Let us say we get correlationid passed in via request header, let us see how we can pull and populate that
if(httpContext.Request.Headers.TryGetValue("App-Correlation-Id", out var appCorrelationId))
{
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("CorrelationId", appCorrelationId));
}
}

}
}
}

Now let us see how we can configure this custom enricher with Serilog in program.cs.

//Add singleton
builder.Services.AddSingleton<HttpRequestAndCorrelationContextEnricher>();

///Register remaining services

//Sample for enriching using custom enricher
builder.Host.UseSerilog((_, serviceProvider, loggerConfiguration) =>
{
var enricher = serviceProvider.GetRequiredService<HttpRequestAndCorrelationContextEnricher>();
loggerConfiguration
.Enrich.FromLogContext()
.Enrich.With(enricher) // Register custom enricher
.WriteTo.Console();
});

Now when you run the program and see you will see all the new properties appearing in the logs. Serilog enrichers provides a powerful way for enriching logging which will help with troubleshooting issues in higher environments. Just like any tool, it’s important to use Serilog enrichers thoughtfully to prevent them from slowing down your application or making it harder to manage. When set up correctly, these enrichers can really boost your ability to understand and fix issues, keep an eye on your app’s health, and dig into what’s happening behind the scenes.

Source code for this blog can be found in below link:

🙏Thanks for taking the time to read the article. If you found it helpful and would like to show support, please consider:

  1. 👏👏👏👏👏👏Clap for the story and bookmark for future reference
  2. Follow me on Chaitanya (Chey) Penmetsa for more content
  3. Stay connected on LinkedIn.

Wishing you a happy learning journey 📈, and I look forward to sharing new articles with you soon.

--

--

Chaitanya (Chey) Penmetsa
CodeNx
Editor for

👨🏽‍💻Experienced and passionate software enterprise architect helping solve real-life business problems with innovative, futuristic, and economical solutions.