|Date Modified||April 25, 2022|
This article has been updated to briefly discuss other frameworks, such as Nlog and Log4Net as well.
I have been pretty upfront about my appreciation for Microsoft Extensions Logging and Serilog. I use both very often and recommended them frequently for various projects. But which one is better?
Well, it’s messier than that - It doesn’t have to be a question of “Microsoft Extensions Logging or Serilog” but instead a question of “Microsoft Extensions Logging and Serilog?”
I won’t totally throw out the premise of this being a “vs.” article: I’ll take some time to compare the two head to head. But then, I want to discuss the typical setup we recommend for our users interested in logging for their .NET 6 & .NET Core apps, which is to use both.
Serilog vs. Microsoft Extensions Logging: Abridged
Both are competent as loggers for any .NET project. If you already use one or the other for an application, there is no real reason to rush and switch to the other team. If you are building an application from scratch or migrating an application from .NET Framework to .NET Core though, it’s worth learning about both options.
Microsoft Extensions Logging (MEL) is a clean logging mechanism that’s considered the default for .NET Core. That doesn’t mean you can’t make .NET Core projects without it, but doing so requires a conscious effort. The truth is though, there are not many projects in which you would use MEL alone. It’s designed to work well with others.
Serilog is the reference example of a Structured Logging system - one that doesn’t just create messages, it easily captures key attributes and data about the context the message happened in. While this is possible with MEL via Logging Scopes (and desirable!), Serilog does it automatically as a natural outcome of composing log messages from format strings, a neat trick!
Both options have been very carefully designed, but were designed at different times. Serilog was made for .NET Framework, when structured logging wasn’t really a thing. It provided a full-fat framework better than anything Microsoft offered. It quickly became one of the most popular logging frameworks for .NET, and remains so to this day.
MEL was made after third-party logging systems had pretty much become an accepted part of .NET. Instead of building a fancy framework that matched every capability of third-party options like Serilog, they focused on making “an extensible logging mechanism with plug-in providers for many common logging systems.” With that said, it becomes very silly to pit the two against each other because MEL is not selling itself as an alternative to Serilog, it’s a way to implement systems like Serilog.
So, the question becomes whether you would want to use Serilog directly, or with MEL? To make things easy, I’ll start by listing the scenarios in which you may want/need to use Serilog directly:
- If you’re writing in .NET Framework and can’t use .NET Standard. While MEL is a .NET Core exclusive technology, Serilog has packages for both branches of .NET.
- You have to add logging to the entire startup process. MEL is initiated during the startup, and therefore not available for the whole process. Serilog can be initiated beforehand and log the whole thing (although, the rest of the application can be written to MEL, and maybe should be).
- If you need to use an intricate feature of Serilog that MEL doesn’t support, go ahead and write that part directly to Serilog (but consider writing the rest to MEL).
Otherwise, we recommend using MEL, then adding Serilog on top of it. Let’s discuss what that setup would look like.
Logging Framework vs. Logging API: How We Use Both
When someone asks, “What Logger should I use for my application?” they are asking two questions:
- What is the logging API you want your code to utilize to capture log data?
- What is the logging framework you want to have implement that API to construct the formatted output various logs you want to record?
The API is what your code actually calls. You write log statements in your application using the API. The framework is what creates the structured log messages with the data passed through the API. Finally, the log messages are pushed to a sink, the mechanism used to store (and sometimes transport) the log data to where you can view it.
In the past, the distinction wasn’t so important because in order to use a logging framework, you would need to use the matching API as well. But on .NET Core, MEL can act as the API for whatever logging framework you would realistically use, so the distinction matters. In many cases, organizations will write to the MEL API and process it through a separate framework.
Still though, Serilog has it’s own API. So let’s look at an application structure that uses the Serilog API and Framework exclusively:
Using Serilog Exclusively
Below is an example logging flow using Serilog as the API and Framework exclusively.
This flow is capable of making excellent structured logs for pretty much any .NET application. But there are downsides to this setup when we consider the dependencies your application takes on.
Everything in your codebase takes a dependency on Serilog. If you want to update to the newest release of Serilog, you have to update every single part of the project, including libraries you may not want to touch. Or maybe you want to add a new library to use in a simple utility? You’re setting up Serilog too. Or, if you’re going to move away from Serilog, you’ll need to update every logging statement in the project.
This setup forces the entire organization to be all in on Serilog. Every team, every piece of the application. This is not necessarily a bad thing, but we can create a more flexible system.
Microsoft Extensions Logging as API, Serilog as Framework
This functionally works the same as the Serilog example. We can use the Serilog formatting to make structured logs and access the same sinks. So, what’s the difference?
The key distinction is not visible in the chart. These charts only account for the main process for your application. Consider any libraries you have. I mentioned earlier that if you use Serilog as the API, you will have to add Serilog as a dependency for each of those libraries. In this case, you do not. Other parts of the application are not required to use Serilog as a MEL provider.
This setup allows for greater flexibility across the board. That means you can use Serilog for where it makes sense, like the application executable, and avoid using it for items like individual libraries where it may be best to leave the output in debug, a console, or use the NullLogger to not capture anything at all. Ultimately, using MEL as the API allows you to use the best framework for your main process, while letting MEL take care of logging for the other parts you may want to keep simple.
What About Using Microsoft Extensions Logging with Other Frameworks?
Other logging frameworks can work the same way, such as Log4Net or NLog. Set them as a MEL provider, and you’re good to go. I personally like Serilog the best, but it’s easy to switch frameworks in and out (I do just that in this article on file logging with MEL). You can even set multiple frameworks as MEL providers, and use them simultaneously.
For example, let’s say you are currently using Log4Net on top of MEL to log to text files. You want to start using a centralized logging system like Loupe instead, but it’s not supported. If you directly replaced the framework with Serilog, you could set both a file and Loupe as log sinks. But other teams in your organization may have processes built around the log files created by Log4Net, and a sudden switch would prove very disruptive. So instead of forcing a transition on the team, you could use both frameworks like this:
This setup allows both parties to use their preferred logging system without rewriting any logs. Over time, you may want to phase Log4Net out though, as this setup has some minor performance and code complexity costs. For that reason, I used Serilog as the new framework instead of using Loupe directly. Over time, Serilog could replace the file logging and Loupe can’t. But in the short term, using multiple frameworks on top of MEL allows everyone to use the tools they need with the least disruptions.
So What Should I Use?
For almost every current .NET project, we recommend using MEL as the logging API and letting preference guide which frameworks to use behind it. That way, you’re only taking on one global dependency as an organization, and you are free to use whichever logging framework makes sense for other parts of the project. If you want one of those frameworks to be Serilog, that’ll work just fine. It can create some great looking, data rich logs.
There’s one more piece to the logging pipeline that I haven’t covered in depth here: the sink. You may be using the console, a text file, or even something like the EventViewer if you are on windows. But it’s worth giving Loupe Desktop a try.
Loupe Desktop is a free log viewer for .NET Framework, .NET Core, and .NET 6. The above screenshot shows me running Serilog into Loupe in an ASP.NET application. Along with an advanced log viewer, Loupe Desktop can also provide performance information on your application, including memory usage, average time per unique query, and much more. You can get it for yourself using the link below.