Over 10 years we help companies reach their financial and branding goals. Engitech is a values-driven technology agency dedicated.

Gallery

Contacts

411 University St, Seattle, USA

+1 -800-456-478-23

Development

How to create a Serilog enricher that adds HTTP information to your logs

What is a Serilog enricher and what is it used for?

A Serilog enricher gives us the ability to dynamically add useful, contextual properties to our logs. It is one of those things that makes Serilog more than just a logging API.

A number of pre-built enrichers can be found on the Github page of Serilog. However, today, we’re going to write our own. Ours will enrich our logs with properties from the HttpContext.

After getting familiar with what an enricher is, let’s get into writing one of our own…

The setup

For the purpose of being IDE-agnostic, we’re going to use the .NET CLI to create our project and add the necessary NuGet packages. For the purpose of demonstrating how to create the enricher, we are going to create a Web API project using ASP.NET Core 6 and we’ll target C# 10.

The first command we are going to execute is the one that’ll create our project:

dotnet new webapi --name HttpEnricher

Having our project created and ready to go, next, we’ll have to install the necessary NuGet packages to make it all work.

First things first, we’ll need to add the Serilog package itself. We can do that by executing the following command:

dotnet add package Serilog

After having Serilog installed, we’ll essentially need to log somewhere. In order to not complicate things more than necessary, we’ll log into the console. For the purpose of logging into the console, we’ll use one of the available Serilog sinks. We can install the Serilog.Sinks.Console using the following command:

dotnet add package Serilog.Sinks.Console

That puts us in a good place, where we have the Serilog itself and a place where we can see our logs. In order for everything to come together, we’ll need to install one last package, which will integrate Serilog with ASP.NET Core itself. The package is called Serilog.AspNetCore and we can install it using the following command:

dotnet add package Serilog.AspNetCore

Now that we have our project created, and all the necessary NuGet packages installed, we can start digging into the code…

Creating the enricher

A Serilog enricher is a class that implements the ILogEventEnricher. The ILogEventEnricher interface has a single method called Enrich, that we’re going to go ahead and implement. Here’s what the implementation looks like:

public class HttpContextEnricher : ILogEventEnricher
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public HttpContextEnricher(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }
    
    public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
    {
        var httpContext = _httpContextAccessor.HttpContext;

        if (httpContext is null)
        {
            return;
        }

        var httpContextModel = new HttpContextModel
        {
            Method = httpContext.Request.Method
        };

        logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("HttpContext", httpContextModel, true));
    }
}
public class HttpContextModel
{
    public string Method { get; init; }
}

The HttpContextModel is a class that contains the properties we’re interested in. For the sake of keeping things simple, we’re going to use only the Method property. You are free to add as many properties as you’d like to that class.

Having our enricher class implemented, the next is to add it to the DI container alongside the IHttpContextAccessor.

Setting up the logger

The first thing we’re going to add is the HttpContextAccessor in order for us to be able to inject it into the constructor of our enricher. We can do that with the following line of code:

builder.Services.AddHttpContextAccessor();

Next, we’ll need to register the enricher class itself into the DI container. We can do that with the following line of code:

builder.Services.AddSingleton<HttpContextEnricher>();

Now that we have the necessary dependencies registered, we can go ahead and set up the logger itself.

Serilog provides a very convenient overload of the UseSerilog extension method that allows us to use the IServiceProvider. Remember that we’ve registered our enricher class into the DI, so we’re going to need the IServiceProvider to get a hold of an instance of the class itself and tell Serilog to enrich the logs with it. Here’s how we are going to use the UseSerilog extension method:

builder.Host.UseSerilog((_, serviceProvider, loggerConfiguration) =>
{
    var enricher = serviceProvider.GetRequiredService<HttpContextEnricher>();
    
    loggerConfiguration
        .Enrich.FromLogContext()
        .Enrich.With(enricher)
        .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {HttpContext} {Message:lj}{NewLine}{Exception}");
});

And with that, we have our logger fully set up. An important thing to notice in the configuration is that we’ve changed the output template. The reason being is that if are to see the HttpContext property our enricher added in our logs, we have to add it to the output template as Serilog doesn’t take care of that for us.

Let’s go ahead and try logging something…

We’ll add the following line of code to the Get method of the WeatherForecastController:

_logger.LogInformation("Getting the forecast");

After sending a request to the endpoint we see the following log:

[08:35:19 INF] HttpContextModel { Method: "GET" } Getting the forecast

It looks like we’ve successfully enriched our logs with the HTTP method.

Conclusion

The technique demonstrated is not specific to the HttpContext. The ability to register the enricher class into the DI means that we’re free to inject anything we’d like into the enricher.

Author

Kerim Emurla

Leave a comment

Your email address will not be published. Required fields are marked *