A more flexible and enhanced way of logging in .NET 8

11/15/2023
2 minute read

The latest version of the .NET (version 8) has introduced a "better" way of logging. This new way of logging is more flexible and enhanced than the previous versions. It is about the LoggerMessageAttribute.

In the old way, you would write code like this:

public sealed class Repository<TEntity> : IRepository<TEntity>
    where TEntity : Entity
{
    public async ValueTask DeleteBulkAsync(IEnumerable<string> ids)
    {
        ...
        for (var batch = 0; batch < totalBatches; batch++)
        {
            logger.LogDebug("Deleted Batch {BatchNumber}. In total {TotalDeleted} elements deleted", batch + 1, (batch + 1) * batchSize);
        }
    }
}

With .NET 8, the LoggerMessageAttribute got some extensions, that halp you to define exactly that with source generators:

public sealed partial class Repository<TEntity> : IRepository<TEntity>
    where TEntity : Entity
{
    public async ValueTask DeleteBulkAsync(IEnumerable<string> ids)
    {
        ...
        for (var batch = 0; batch < totalBatches; batch++)
        {
            LogDeleteBatch(batch + 1, (batch + 1) * batchSize);
        }
    }

    [LoggerMessage(LogLevel.Debug, "Deleted Batch {BatchNumber}. In total {TotalDeleted} elements deleted")]
    private partial void LogDeleteBatch(int batchNumber, int totalDeleted);
}

To make source generators work, we have to define the class as a partial class. The source generator will then generate the missing part of the class. Personally, it is nicer to read with less1 code. You can also save some precious allocations and a bit of performance, even though in 99% of cases, that shouldn't matter. But it is nice if it comes "free" with it.

1 "Less" in the sense of less complexity and mental capacity needed to process. LogDeleteBatch(batch + 1, (batch + 1) * batchSize); is way easier to process than logger.LogDebug("Deleted Batch {BatchNumber}. In total {TotalDeleted} elements deleted", batch + 1, (batch + 1) * batchSize); }. It isn't necessary less code.

Resources

If you want to know more about the LoggerMessageAttribute, you can the "update" on the official announcement of .NET 8 Preview 6.

A new way of doing reflection with .NET 8

.NET 8 introduced a new way of doing reflection. Why did they introduce this, and what are some benefits - this blog post will give you some insights.

An asynchronous lock free ring buffer for logging

In this blog post, I showcase a very simple lock-free ring buffer for logging. I'll show why it's useful and how it works.

Logging Source Code Generators

Since .NET6 we have the possibility to define an easy way of logging common statements:

Meet Compile-time logging source generators. This article will show why we have them and how to use them. Of course a smaller benchmark will also follow.

An error has occurred. This application may no longer respond until reloaded. Reload x