Microsoft Extensions Logging and Flexibility on .NET 6

Last year, I wrote this article explaining why Microsoft.Extensions.Logging(MEL) is a clean logging architecture for .NET 5 applications. Well, .NET 6 is out now, the first version of the new .NET with long-term support (3 years). That means for many developers, this version of .NET may be the first they encounter that uses MEL, largely organizations considering migrating to .NET 6 from .NET Framework.

So I think it’s worth broadly discussing MEL again, even if our stance on it hasn’t really changed.
We still believe MEL is the best logging architecture for most .NET projects, including those created and migrated to .NET 6. Its flexibility for plugging into other logging frameworks and sinks makes it hard to beat.

What is Microsoft.Extensions.Logging?

It’s the default logging API for .NET Core, including .NET 6. When you make a new solution in Visual Studio, it uses MEL unless you specify a change. If you make no changes, MEL will log to your debug console (for non-console apps).

Let’s look at a quick example: I’ve inserted a log in the privacy page of the ASP.NET template app.

    //...      
    public PrivacyModel(ILogger<PrivacyModel> logger)
    {
        logger.LogWarning("Logger added to privacy page");
    }
    //...

Making my first log is easy as adding the ILogger interface and writing a warning. Without the need to do anything else, the log will appear in the debug console once I enter the privacy page in the app.

The output for the privacy page log example

In .NET 6, I don’t even need to add a using statement if I’m making an ASP.NET application from the new template. There’s a global using statement generated for MEL automatically.

Adding the above log is easy to do, but it’s not super impressive. The debug console is frankly outclassed by most other available log sinks and unreliable for logging once my app is in production. But the strength of MEL is found beyond the base settings.

The Strength of Flexibility

The best way to understand MEL’s value as a logging API is to discuss other logging APIs first.

For example, let’s say you like the Serilog framework, so you decided to use it and the Serilog API for your .NET 6 solution. It will work well. Serilog is a great framework that provides everything I need for effective structured logging. But, by also using it as the API, I am adding it as a dependency for my entire solution. My executable requires Serilog as the framework and API, my libraries, and everything else.

Let’s compare that scenario to an example logging flow with MEL:

Flow chart showing two errors, one going to the debug console, another to debug and Loupe server

This chart shows two different possible flows for an error in our application.

  • Error A represents an error in the executable. We use MEL as the API to direct the error log to the debug console. We also use MEL to connect to the Serilog logging framework and push a structured error log to Loupe Server as the Serilog sink.

  • Error B occurs for one of our libraries. Instead of adding Serilog and Loupe Server, we just push the log to debug so we don’t need any additional dependencies.

With MEL, I have a lot of flexibility when choosing a framework and can limit what portions of my program have it as a dependency. I can use Serilog with my executable, but skip it for my library. So you can reliably have MEL as the only logging dependency throughout your whole solution.

Overall, this makes it much easier to manage for the whole application. Those responsible for the executable get the logging they need, while a hefty framework does not mire down those responsible for the library. Instead, they can just use MEL as the framework and keep things lightweight. And anyone outside your organization that uses the library can also determine what logging framework will work best for them.

What are the Downsides?

There are a few downsides to MEL as the API, one being you can’t use it throughout every part of the application, specifically the startup process (as it’s responsible for initiating MEL).

The main downside of MEL is not the API, but the default sinks. It supports the debug console, the developer’s console, or Windows Event Viewer out-of-the-box, but none of these options are robust enough long-term sinks for most devs. Eventually, you will want to save a log to a file, a dedicated log viewer, and possibly centralized logging (especially when in production).

Luckily, MEL is pretty easy to get working with most sinks you would want to use. While it would be nice for MEL to have the option to log to a file out of the box, it’s not completely necessary.

What Log Sinks Can I Use With MEL?

If you want to just log to a file, you can do that pretty easily with Serilog and the Serilog.extensions.logging package.

If you’re looking for something that can be used from early development through production, with full-text log searching and contextual details in every log, take a look at Loupe. You can get started with Loupe Desktop as a free local logger, but Loupe Server is our centralized logging platform that is the best long-term solution. If you are interested in getting started with Loupe Server, you can learn more about the trial in the link below.

See The Trial

Rock solid centralized logging

Unlimited applications, unlimited errors, scalable from solo startup to enterprise.