Some issues hang on! Serilog’s #3 — XML configuration support — was still grimacing at us from the backlog alongside issues with three digits, until it was unceremoniously closed a few minutes ago.
If you’ve spent any time with Serilog you’ll have noticed the absence of built-in XML configuration support. Something about the project just wanted – and wants – to be a code-centric thing. I guess it is part of lifting the status of logging a bit – ORMs for example moved on from XML configuration to code-first/fluent configuration many moons ago. Instrumenting your app with an event stream is an important thing that deserves a modern configuration API.
XML’s not at all bad though. File paths change, servers have different addresses in different environments, logging levels go up and down. XML’s a great fit for this and we’ve known that all along with Serilog; we’ve just chosen to keep it in its place and write code like:
var logger = new LoggerConfiguration()
Over time this gets boring and repetitive I admit. Thats why we’ve now got the Serilog.Extras.AppSettings package.
XML configuration with a twist
As I said – we like XML configuration in its place, but that’s a pretty small place. When I open up
Web.config in a modern .NET project the amount of gunk in there can be pretty confronting.
Most XML config implementations provide their own
<configurationSection>s, and those need to be declared, and then the XML syntax used within them generally gets copied from a long list of arcana like the one in the log4net documentation that I’ve visited for years on end.
Serilog’s “app settings” support is different; we use a technique I first saw suggested for Autofac module configuration several years ago.
This revolves around the
<appSettings> collection, an element that’s present in almost every .NET configuration file. Here’s an example to illustrate what we’re doing:
<add key="serilog:minimum-level" value="Verbose" />
Instead of our own custom
<serilog> element, we cheat a bit and just look for
<appSettings> elements that match a certain pattern (their names start with
serilog:). Simple idea, but effective: I’m going to write this whole article without checking the documentation or sample code even once! Remembering a setting name or pattern is much easier for me than remembering a whole pile of custom XML syntax.
Going a bit further, here’s the configuation for two sinks, the console and a log file:
<add key="serilog:write-to:File.path" value="C:\Logs\myapp.txt" />
(Notice you don’t actually have to provide a value for an app setting? I didn’t until recently, but works nicely!)
Where do the magic names
File.path come from? They’re just encodings of the following method calls:
The name of the
path parameter obviously wouldn’t be specified in normal usage, but you can see how the XML and code-based configuration match up 1:1.
The extension methods are looked up dynamically using reflection, so you can configure your own sinks this way. You can include multiple parameters for the same sink using multiple keys – for both features check out the wiki page linked below.
Enabling the package
Two steps: 1. Install the Serilog.Extas.AppSettings package from NuGet; 2. add a call to
ReadAppSettings() when you’re configuring your logger:
... // Other configuration here, then
You can mix and match app settings with code-driven config, but for each sink you need to use one or the other.
There’s much more detailed documentation here, on the wiki.
But isn’t this super-limited?
I’m happy to trade configuation power for something I can actually remember how to use. Someday we might have a more sophisiticated XML configuration option than this, but unless you can write the PR – I’m served pretty well by this one and not in a hurry.
But this is totally not my style!
That’s fine; it’s an ‘extra’, meaning we ship it separately from Serilog’s core and you’re free to install it if you like it and ignore it otherwise.
Still, I’ll be happy to hear if you do find it useful!