Does Log4Net Work With .NET 6?

The short answer is… yes. Log4Net targets .NET Standard, which gives it a level of compatibility across the entirety of .NET core, including .NET 6.

But it’s worth asking another question: do you want to use Log4Net on .NET 6? Here, we will review two ways to get Log4Net running on .NET 6 using the new hosting model, then discuss whether Log4Net is the correct logging framework for most developers.

But First, What is Log4Net?

Log4Net is a .NET logging framework maintained by Apache, based on their popular JAVA logging framework Log4j.

Traditionally, Log4Net was one of the easiest ways to start logging to a file, database, or even an email on .NET Framework. Over time, it has fallen out of favor compared to logging frameworks like Serilog and NLog, which have more advanced features like structured logging.

If you’re not familiar with Log4Net, understand it’s a bit of a legacy choice. Even so, it still has a decent number of users and was one of the better logging frameworks around for a long time. It’s worth at least a discussion.

Using Log4Net on .NET 6

If you like Log4Net as a way to output log statements to text files, databases, and more, it can still do this on .NET 6. You just need to make sure to use a version of Log4Net that targets .NET Standard (2.0.7 and beyond). In fact, I can use Log4Net alongside the default logging API for .NET Core: Microsoft.Extensions.Logging.

Log4Net as a MEL provider

On ASP.NET Core, I can use Log4Net as a Microsoft.Extensions.Logging (MEL) provider, which then writes logs to the desired appender (i.e., log sink, Log4Net refers to them as appenders). In general, we recommend using MEL as the logging API for most .NET Core projects. It’s extremely flexible and allows for a very clean logging architecture.

The Microsoft.Extensions.Logging.Log4Net.AspNetCore package is written and maintained by Ángel García Santos (huorswords) and possibly the easiest log-to-file provider for MEL to set up. Just create a log4net.config file with a log file as an appender, then add two using statements and a single line of code to the new .NET 6 hosting model:

//Program.cs
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Log4Net.AspNetCore;

var builder = WebApplication.CreateBuilder(args);

builder.Logging.AddLog4Net(); //creating the provider
//...

So I added a simple test log to the privacy page:

//Privacy.cshtml.cs
//...
public PrivacyModel(ILogger<PrivacyModel> logger)
{
    _logger = logger;
    logger.LogWarning("This is a MEL warning on the privacy page");
}
//...

And ran the application to create the following log file:

Log file output showing some info logs showing the hosting process for the application

Recently, I wrote an article with two file logging examples using Serilog and NLog as the providers. While I really like those options (and ultimately think they’re better for .NET Core projects), the Log4Net package was slightly faster to set up. Not bad!

But I don’t think this technique is the answer everyone is looking for. I’d imagine a more common scenario is trying to migrate an existing .NET Framework application that uses Log4Net to .NET Core/.NET 6 while trying to avoid major changes to your logging. Using Log4Net as the provider really only solves half of the problem. Sure, it will allow for you to use Log4Net pointing to the same appender (text file, console, etc.), but it may require a significant amount of editing to get working right (i.e., a lot of dependency injection).

Using Log4Net without MEL

Log4Net can work on .NET 6 without using MEL. This means, in theory, you can migrate.NET Framework applications and keep the same Log4Net logging statements. Whether it’s advisable is a separate question. For now, let’s just go over a proof-of-concept example that shows Log4Net operating on its own on .NET 6.

For the template ASP.NET application using the new hosting model, all I had to do was add one line to grab the config file (located in the root directory):

//Program.cs
using log4net.Config;

var builder = WebApplication.CreateBuilder(args);

XmlConfigurator.Configure(new FileInfo("log4net.config")); 
//...

Then I could log throughout the application using the ILog interface as you would with Log4Net on .NET Framework. Let’s look at the equivalent privacy page log I wrote to MEL, but writing to Log4Net directly instead:

//Privacy.cshtml.cs
//...
public void OnGet()
{
    ILog log = LogManager.GetLogger(typeof(Program));
    log.Warn("This is a Log4Net warning on the privacy page");
}
//..

The resulting log file was almost identical to the MEL Provider example, minus the additional host logs captured by MEL:

Log file output showing three privacy page logs

All this to say, this isn’t an example of ideal logging for a .NET 6/.NET Core application, just a demonstration that Log4Net actually works on the platform. But let’s discuss whether you should use Log4Net.

Is Log4Net a Good Choice for .NET Core/.NET 6?

If you are making an application from scratch, I would not recommend using Log4Net. While it’s quick to set up, there are many aspects of Log4Net that are less than ideal:

  • It’s challenging to find .NET Core documentation. Most of the official documentation is written for .NET Framework. This is not necessarily a bad thing, as most Log4Net applications are built with .NET Framework. But for Serilog, NLog, Loupe, etc., it’s pretty easy to find official .NET Core documentation.

  • Many Log4Net features are missing for the .NET Core implementations. Appenders (sinks) such as the colored console don’t work. Stack trace patterns are unsupported, and more features are missing. The .NET Core offering is just simply worse.

  • Log4Net simply doesn’t have the capabilities of modern frameworks. It doesn’t support structured logging well, it focuses on XML configuration (technically, there are other config options, but they are not well documented), and the current development is focused on exclusively life support. Stock Log4Net lacks features like structured logging or client-side logging for ASP.NET applications.

Instead, start with MEL and try out different providers like Serilog for logging to a file or Loupe for detailed centralized logging (highly recommended ). Using MEL saves you time in the future, as it is compatible with pretty much any logging framework or sink you would want to use. Changing from one logging platform to another is as simple as configuring a new provider; no rewriting is required for the log statements.

What About for Applications Migrating from .NET Framework to .NET 6?

This is frankly a topic that deserves its own article, but it would be a disservice not to discuss it in any capacity. A large portion of Log4Net users are in this exact scenario.

In short, everything that makes Log4Net unappealing for new applications is true for migrating applications. But it’s more difficult to justify a new logging framework when you already have one in place. Log4Net still works, so you’re not required to switch.

That being said, migration is often the right time to change your logging. Here are a few things to consider when deciding whether to move on from Log4Net or not:

  • Migration can change what’s needed from your logs. New features and possibilities can lead to further data requirements that your current logging system does not meet. For example, .NET Core/.NET 6 offers cross-platform support, cluster-based application deployment, improved performance, and more compared to .NET Framework. If you’re planning on extending platform support or using a more complex linux cluster deployment, a logging system built for a single Windows server would require significant changes anyway.

  • Log4Net isn’t going to get much better for .NET Core/.NET 6. Just because it works well enough now doesn’t mean it will work well enough in the future, when documentation is harder to find and your average developer is less familiar with it. The longer you stick to any legacy technology, the greater the price is in the future to maintain or move on from that technology. Switching the logging framework now can save time and money later.

  • The amount of labor required to switch will vary from project to project. Not every application has a giant codebase with thousands of unique logging statements. If your application has ten unique logging statements, rewriting to another logging framework may not take too much time or effort (especially if you can just copy over a few log classes to MEL and leave logging statements largely untouched). Another factor on the required labor is the number of 3rd party libraries/plugins used with Log4Net. Some of those may work with .NET Core, and some may not. Fixing or replacing those will need labor as well.

But it’s much easier for me to say “don’t use Log4Net” than for someone to rewrite every logging statement in their application. The realities of software development often result in not using the best technologies all the time.

If you can’t move away from Log4Net before migrating, it’s not the end of the world. It still works in a decent number of scenarios, even if not optimal.

Log4Net Still Works on .NET 6, But It’s Not the Best Option

Log4Net has been a stable option for logging on .NET, and still is. It was super easy to get working as a MEL provider and on its own. Ease of use will always have appeal. But other frameworks like Serilog, Nlog, and the Loupe framework are easy to set up as well, with better documentation, feature sets, and more active development. So we recommend switching to a different framework if at all feasible.

If you want to change your logging for .NET 6, consider trying Loupe!

Loupe can be used as a MEL provider, on its own, or as a log sink for other .NET Core frameworks like Serilog. You can get started with Loupe in any of these capacities using our free local log viewer in the link below.

Loupe Desktop - A Local .NET and Java Log Viewer

Completely free local log viewer
Works with the technologies you use
Adds additional metrics and supplemental data