Migrating from log4net to Serilog

I recently got excited about structured logging and decided to migrate from old log4net to Serilog. Adding more classification data to log events is something that will definitely benefit many applications. I tried to search for pros and cons, but it’s difficult to find a real world comparison for a large, complicated web application. Here are my experiences and opinions.

Good about Serilog

  • Easy to create logger configurations in code in just a few lines.
  • Everything is instance-based and mostly immutable. No need to use globals unless you want to.
  • Easy to extend, for example new sinks or enrichers.
  • Clean APIs, less clutter from over the years. Log4net and NLog have features that nobody should really use anymore.

Bad about Serilog

  • Configuration file support is lacking compared to log4net/NLog. Configuration is verbose and complicated. Live reload support is lacking.
  • Community seems small compared to NLog. Possible issues with support. For example, Gitter was very quiet.
  • Certain features are lacking, such as extracting properties from structured objects.

Our requirements

Our software had some specific requirements.

  • Logging to flat text files is still needed.
  • Everything needs to be configurable in configuration files, with live reload (no restarting application).

Main issues identified

Configuration file support

The main issue I identified was support for configuration files, especially live reload.

Serilog is clearly optimized for code-based configuration. Creating additional loggers, with new properties and sinks (targets) is very simple and straightforward. However, configuration by files is not as well supported. There are limitations with what you can do with config files.

The most critical limitations for us were related to live reloading of the logging configuration, so that configuration can be updated without restarting the application. For example, making a specific class/source log on debug level instead of error level. In log4net and NLog, it’s possible to replace the whole configuration file and it will take effect on the fly, without application restart. Serilog only supports changing log levels for existing class names, that are already specified in the log file when the application starts. Fortunately it was easy to write a replacement for live overrides using filters. Adding and removing sinks runtime is still a problem, and a lot harder to solve.

The configuration file format is more verbose compared to NLog and log4net, so complicated configuration should be done in code, if possible. I decided to solve this by putting the default configuration in code, then using .ReadFrom.Configuration to apply overrides from config file. This allows the configuration to be very clean by default, with the option to apply run-time overrides when needed, without recomplication.

Missing features

There are also some missing features. Most importantly, we need to be able to pick certain properties from structured objects, for flat-file logging. This is possible in NLog (using objectpath), but I couldn’t find a way to do it in Serilog. I was able to implement it myself with a few lines of code. Other minor features I would have used, but were missing: turning off loggers via configuration and setting log levels per sink/logger.

Community activity

The lack of community activity was a bit troubling. I checked the Gitter chat, and there was people asking questions, but no response from community members for several weeks. Most of the development is concentrated on one or two people (including the original developer), which is always a bit risky. Serilog repository on GitHub is getting only a small number of commits. These are mostly theoretical risks for future-proofness of the library. NLog seems very active, although it’s hard to compare development activity, because Serilog is broken into smaller pieces than NLog, which is a good thing of course. Log4net on the other hand has been dead for many years, and I wouldn’t recommend it for anyone.

Conclusions

I mostly talked about issues with Serilog. I do really like the API design. It’s clean, and very easy to extend. Structured logging is definitely the future. There are shortcomings, but because the API is so simple, it should be easy to fill most of those gaps. You need to be prepared to do some extension work yourself, though, that would be available with NLog out of the box.

I should note that Serilog, NLog and Microsoft.Extensions.Logging all support the same message templates syntax, so any of those will work, and it should be relatively easy to switch between frameworks. Log4net does not support message templates (it has its own syntax for structured logging). I found a library for message template -> format string conversion, written by the Serilog author, but it’s marked as prerelease, and not maintained for years.

Would I recommend Serilog? Depends on how much you need configuration files, I guess. If you’re happy doing most of the configuration in code (like I imagine most would be?), then Serilog is definitely fine. It’s simple and clean. If your configuration relies heavily on configuration files, and you need to customize those live, then you should be aware of the issues I faced.

I haven’t still made the final decision. If the configuration issues are too large, I might switch to NLog instead, or at least use it together with Serilog.

Leave a Reply