This application contains absolutely no logging. In many legacy enterprise application, there usually is some logging, but it’s often not very useful. In some cases, there is no logging at all. This makes it hard to troubleshoot when things go wrong.

In .NET, the first logging frameworks that come to many developer’s minds is log4net or NLog. I’d recommend NLog over log4net because the documentation seems better to me. In my position as consultant, I often encounter custom logging frameworks. I’ve already explained why company frameworks are a bad idea. I’ve also touched on why you shouldn’t fork an open source project and never give back to the community.

For this application, I will be using Serilog which was the first .NET library I encountered that supports structured logging. Structured logging allows you to search your logs more easily and is the recommended way of logging.

By the way, NLog supports structured logging as well, since version 4.5. But I didn’t realize this at the time of my refactoring.

After installing the Serilog and Serilog.Sinks.Console NuGet packages, I can add an ILogger to my Autofac container:

var log = new LoggerConfiguration()
          .WriteTo.Console()
          .CreateLogger();
builder.RegisterInstance(log).As<ILogger>();

We can now use this logger instance in any place where we want, thanks to Autofac.

Exceptions

For general exceptions, I had to go back to the Autofac documentation and add some bits.

For the MVC part of my application:

  • Add “builder.RegisterFilterProvider();” in our Autofac setup
  • Create a class that implements System.Web.Mvc.IExceptionFilter, add a public ILogger property and use it to log the exception in the OnException method
  • Add an instance of this filter to the System.Web.Mvc.GlobalFilters.Filters collection

For the WebAPI part:

  • Create a class that implements Autofac’s IAutofacExceptionFilter interface, receives an ILogger in the constructor and uses that to log the exception
  • Register this class as an exception filter for all my ApiController instances
  • Tell Autofac to use the WebAPI Filter Provider

These last two steps are done like this at startup:

builder.RegisterFilterProvider();
var config = GlobalConfiguration.Configuration;
builder.RegisterWebApiFilterProvider(config);

Other Messages

Logging is a excercise of balance. Log too much, and your log becomes too verbose. Log too little, and you don’t have enough information to troubleshoot issues.

For my application, the general exception logging is fine for now. But if I encounter issues in the future where extra logging would have been useful, I can now easily add it. Thanks to Autofac and the dependency injection we set up earlier, all I have to do is inject an ILogger into the constructor of a controller (or other component), and log what I want to log.

Log Destinations

Serilog has a concept of Sinks. These are destinations to where the log is written. In our example above, I wrote to the console. This is useful when running locally, but not so much when running online. In my case, Azure.

Luckily, there is an Application Insights package for Serilog. There are many other sinks you can use. But Application Insights will do for this application, as it will also provide some extra basic benefits, like monitoring, telemetry, etc.

So I added this to my Startup clas:

private static TelemetryClient _telemetryClient;

public static TelemetryClient TelemetryClient => _telemetryClient ?? (_telemetryClient = new TelemetryClient
{
    InstrumentationKey = ConfigurationManager.AppSettings["APPINSIGHTS_INSTRUMENTATIONKEY"]
});

As you can see, I’ve made it static, because I’ll need to flush the client when my application ends. Otherwise, I could lose some events.

Next, I changed the creation of my logger to this:

var log = new LoggerConfiguration()
#if DEBUG
          .WriteTo.Console()
#else 
          .WriteTo.ApplicationInsightsEvents(TelemetryClient)
#endif
          .CreateLogger();

This way, I’m not using Application Insights locally, but will be when it’s running on Azure.

You can see the commit that added logging here.

3 thoughts on “Fixing My Legacy Application: Adding Logging

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

This site uses Akismet to reduce spam. Learn how your comment data is processed.