10 Dec

Building Supportable Systems (Logging)

If there was going to be a “silver bullet” that will make your applications more supportable I think I would suggest that appropriate logging would be it. There are obviously a lot of other things you can do to make applications easier to support, monitor, debug and develop – but without logging you’re shooting yourself in the foot before you even start.

Luckily there are plenty of great options for logging in .NET. Console.WriteLine() isn’t one of them, and neither is anything in the System.IO.* namespaces. I mean there are plenty of useful functions throughout these namespaces, but you really don’t want to write your own logging framework when there are so many open source solutions. Libraries like log4net, nlog, SLAB and Serilog are all dedicated logging libraries and they will abstract all of the tricky bits away from you so you don’t need to think too hard and can concentrate on adding business value to your applications.

Serilog

Most logging frameworks are kind of like string.Format(“…”) that goes somewhere useful. Most logging frameworks offer a variety of output targets (Sinks to Serilog) ranging from simple flat files through to databases and cloud-hosted log aggregation services.

The following is an example of a log4net formatted logging command:

    Log.Info("{0}, {1} bytes @ {2}", ...)

It’s not bad, but we can do better… we can make it more readable. This is where Serilog comes in and as with everything in this series it’s installed via NuGet So our previous log line now becomes this:

    Log.Information("{User}, {Bytes} bytes @ {Time}", ...) 

“So what?” you say. That’s exactly the response I got when I was demoing this to some workmates last week. Well this is where the power of Serilog becomes apparent. Unlike other logging frameworks, Serilog can actually serialise your logged objects into rich objects rather than just the “ToString()” representation. So rather then getting an anaemic “Processed Order 123” or something similar from the following line:

    Log.Information("Processed order {@order}", order);

We will get something rich and infinitely more useful:

    2014-12-07 18:47:43 [Information] Processed order Order { Id: 123, Customer: Customer { Name: "Shaw", Address: "123 Some Street" } }

There is one thing to watch for (as I discovered the naive and hard way). Beware of very deep object graphs, or even worse, circular references. These will the kiss of death to your rich logging story.

Summary

With these logging frameworks it’s so easy to get rich logging into your applications so do it early and make use of it for easier access to usage and debugging information. Mature logging frameworks like log4net and Serilog have integrated log file retention management, so you can set reasonable limits on the size and number of logs to keep without having to worry about your disks filling up.