Serilog vs log4net
Serilog and log4net are two very popular choices for logging messages from .NET applications. In this post, I'll show you how to configure and use each framework as well as list the advantages and disadvantages of each framework. I even dare to recommend you use one of the frameworks :)
Let's start with a bit of information about each framework.
Serilog
Launched in 2013, Serilog is one of the newest logging frameworks. This definitely isn't a bad thing, since the framework uses some of the newer and more advanced features of .NET. Structured logging probably being the most noticeable, but also the concept of enrichment is what makes Serilog unique compared to a lot of other logging frameworks.
Serilog is constantly growing and new log targets are being launched every month. There is a large community around Serilog. Compared to other frameworks, the people involved are genuinely nice and want to help out.
log4net
log4net is the old boy on the team of .NET logging frameworks. Originally launched as a port of log4j, it has evolved into a unique product run by the Apache Foundation. You will find a lot of existing projects out there that use log4net for their logging needs. With the latest release back in 2017, development of the main framework pretty much stood still during the last years. New appenders are being developed though, and log4net actually has pretty decent support for modern NoSQL databases as well.
Configuration
Both log4net and Serilog need configuration to start logging. Let's dive into each framework to see how easy the configuration is.
Serilog
Serilog supports both XML and C# based configuration. I've never actually heard of anyone using the XML approach, so that's why the rest of this section will show configuration code written in C#. Being able to configure Serilog in a strongly typed language is a great benefit.
To configure simple logging to a file we write configuration code like this:
Log.Logger = new LoggerConfiguration()
.WriteTo.File("log-.txt", rollingInterval: RollingInterval.Day)
.CreateLogger();
The LoggerConfiguration
class is the key part of configuring and creating the Serilog ILogger
object. In Serilog, log destinations are called Sinks and are added using extension methods on the WriteTo
property. In the example above, I tell Serilog to log messages to a rolling file. Finally, I call the CreateLogger
method and set the output on the static Logger
property on the Log
class. This ensures easy access to the ILogger
object from your program.
log4net
Like Serilog, log4net can be configured in both XML and C#. The C# approach is clearly something that was added later and is not really intuitive (IMO). Since most of the examples you will find online are in XML, I will use that for the rest of the examples in this post.
log4net configuration is added through either app.config
or a dedicated log4net.config
file:
<log4net>
<appender name="FileAppender" type="log4net.Appender.FileAppender">
<file value="log-file.txt" />
<appendToFile value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %level %message%newline" />
</layout>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="FileAppender" />
</root>
</log4net>
Notice how the file appender has its own named appender
element, which is then referenced inside the root
element in the appender-ref
sub-element.
To make the configuration visible for the rest of your program, add a bit of code somewhere (like in AssemblyInfo.cs
):
[assembly: log4net.Config.XmlConfigurator(Watch=false)]
As mentioned earlier, configuration isn't really log4net's strong side. Luckily, there is some pretty good documentation and because of its long history, a lot of examples and blog posts online.
Sinks and Appenders
Unless you want to store everything in /dev/zero, you need some way of storing your log messages. Both examples above, showed how to store log messages to a file. Serilog has the concept of Sinks and log4net has appenders. They both cover the same need, just with different naming.
Sinks and appenders are available for a lot of different destinations like files, databases, and remote services. As an example, elmah.io provides both a sink for Serilog and an appender for log4net. They both do the same, store all messages logged through each framework to elmah.io. Both logging frameworks have sinks and appenders for the most common storage options. The quality of each implementation highly varies, which is why I would recommend you try out each sink/appender and see if it covers your needs.
Logging Messages
Why configure a logging framework if you don't want to log any messages? Let's do something about that.
Serilog
Logging in Serilog is dead simple:
Log.Information("Hello World");
Remember how we initialized the Log
class in a previous section? Well, here we really see the benefit. The Log
class has overloads for all available log levels through Serilog. In this example, I log an information message.
A great benefit of Serilog is the feature of structured logging:
Log.Information("Hello World from {FirstName}", "Thomas");
Rather than using normal string concatenation, I tell Serilog to replace {FirstName}
with Thomas
. This produces a nice log message, as well as tells Serilog to remember the FirstName
key and its value. This can be used to log structured data in a service like elmah.io or in NoSQL databases like MongoDB or Elasticsearch.
This isn't a guide to structured logging with Serilog. If you don't know the concept, check out Structured Data on the Serilog wiki. You are in for a treat!
log4net
Logging through log4net is a bit more complex than Serilog, but it still does the job:
var log = LogManager.GetLogger(typeof(Bar));
log.Info("Hello World");
The main difference is the need for the LogManager
. You typically get a reference to the logger one time per class and re-use the same log instance.
log4net doesn't support the concept of structured logging. Like shown in the conversionPattern
element in the XML configuration, you have some variables to play with when writing to the storage. But including properties like FirstName
in the Serilog example isn't available.
Conclusion
I don't really like to pick on log4net since it has served as a great (and default) logging choice for me for the past decade. But in the end, Serilog is superior in most ways. Structured logging, enrichments (I didn't even show you those, but check out the Serilog documentation for examples) and C# based configuration are all winners.
In most cases, I wouldn't recommend you to replace the logging framework on legacy systems, but in this case, I definitely see some benefits of jumping from log4net to Serilog.
Serilog
Advantages
- Structured logging and enrichment
- Great documentation and community
- C# based configuration
Disadvantages
- More features to learn
log4net
Advantages
- A lot of documentation and blog posts
- Easy to understand when coming from logging frameworks from other languages
Disadvantages
- No structured logging
- Hard to configure
- Project seems dead