Enriching Serilog log entries

serilog

Introduction to Serilog Logger

Serilog is a powerful and flexible logging library for .NET applications. It allows developers to easily capture log data and send it to various destinations, such as files, databases, and cloud services. One of the key features of Serilog is its ability to enrich log data with contextual information, such as properties and structured data. In this blog we focus on a Serilog library that I recently published and what features it could add to your logs.

Introducing Biplov.Serilog

Biplov.Serilog is a library based on Serilog logger. You can install the library in your project by running the following command in your project folder or, you can install it by using nuget package manager for your project.

dotnet add package Biplov.Serilog

You can find the project in Github. Feel free to start or clone or open a PR of possible improvement.

The library provides following feature:

CorrelationId Middleware

Enriching logs with CorrelationId can help to filter all your logs for given CorrelationId. This CorrelationId could be passed around multiple APIs if you work in Microservice architecture. Filtering logs accordingly can help you debug any issues in less time when you have end to end logs.

Here is the CorrelationId middleware from the library:

public class CorrelationIdMiddleware
{
    private readonly RequestDelegate _next;
    private readonly string _correlationId;

    public CorrelationIdMiddleware(RequestDelegate next, string? correlationId = null)
    {
        _next = next ?? throw new ArgumentException(nameof(next));
        _correlationId = correlationId ?? "CorrelationId";
    }

    public async Task Invoke(HttpContext httpContext)
    {
        if (httpContext is null)
            throw new ArgumentException(nameof(httpContext));

        using (LogContext.PushProperty(_correlationId, httpContext.CorrelationHeader()))
            await _next(httpContext);
    }
}

You can then use this ServiceColletion extension to register the middleware.

public static class CorrelationIdMiddlewareExtensions
{
    /// <summary>
    /// Registers CorrelationId Middleware via
    /// <see cref="https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.iapplicationbuilder?view=aspnetcore-7.0">IApplicationBuilder</see>
    /// </summary>
    /// <param name="builder"></param>
    /// <param name="correlationId">Custom value for CorrelationId name can be passed here. Default is null</param>
    /// <returns>IApplicationBuilder</returns>
    public static IApplicationBuilder UseCorrelationIdMiddleware(
        this IApplicationBuilder builder, string? correlationId = null)
    {
        return builder.UseMiddleware<CorrelationIdMiddleware>(correlationId);
    }
}

This will enrich each log entry with the CorrelationId property (or any name you provide)

Here is an example for the test endpoint we have in the example project:

image
Each log entry is enhanced with TestCorrelationId

HttpContext Enrichment

You can also opt in to enrich your request log with HttpContext which can be invoked using following example:

app.UseSerilogRequestLogging(options => options.EnrichDiagnosticContext = HttpContextEnricher.HttpRequestEnricher);

This will enrich your request log with HttpContext object containing following property:

  • IpAddress – This is request IP
  • Host – This is application host
  • Protocol – Request protocol
  • Scheme – Request Scheme
  • User – User info if logged in
  • Route – Request route

Here is example screenshot:

image 1

Extra Enrichments

The request log is also enriched with LogContext, AssemblyName, EnvironmentName, SpanId, Version if not null or empty

var logger = loggerConfig
      .Enrich.FromLogContext()
      .Enrich.WithAssemblyName()
      .Enrich.WithEnvironmentName()
      .Enrich.WithSpan();
            
if (!string.IsNullOrWhiteSpace(version))
{
    logger.Enrich.WithProperty("Version", version);
}

Excluding Request Path

You can opt in to not log certain routes. For example if you do not want /api/ignore path to be logged and you do not want any path that contains _system and the log level is info you could add this

services.RegisterSerilogLogger(
    Configuration,
    "0.1",
    "RequestPath like '/api/ignore%'",
    "@l in ['Information'] and RequestPath like '%/_system/%'");

Furthermore, you can try running the test project by running :

docker-compose up --build

This will spin up the API and Seq inside docker container. You can find api in localhost:5000 and seq in localhost:5341

Happy Coding!

Leave a Comment

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.