Logging in distributed system Part 2 — Action filters

This is the second part of the Logging series. For your convenience you can find other parts in the table of contents in Part 1 – Correlations

We have our loggers and correlators, now we need to use them. Since we want to create them with each request, we can use action filters to automate the job. Let’s start with WebAPI2.

Important

Before we start: it is crucial to register loggers and correlators properly in DI container. They need to be registered in request lifetime scope so all services injected to the controllers get the same instance of the correlator and logger. If we mess this thing our logs will be useless.

REST API

Let’s see the code:

This is pretty obvious. On entering action I generate the activity and log parameters. When action is finished I log this fact and add correlation headers to the response.

One thing related to the DI. I am using Autofac and I could register this action filter in DI and filter provider. However, it is easier to just create action filter as an attribute, register it globally, and get dependencies from WebAPI’s services resolver. Of course this is up to you.

Web job

WebAPI was easy, web job is even easier. I am using Autofac as well in this part of the system but I have no web request here. This is why I create dependent scope and register logger and correlator as instances:

Next, all my actions need to extract dependencies from the scope:

This way all your services should get correct instance of logger and correlator, and logs should go to the TextWriter given by the Azure.

Of course you could use Azure’s JobHost services resolver.

Sitefinity

Now the case of Sitefinity. Actually, there are four cases to consider.

WebForms

First case is WebForms part of the CMS. When you open the page with widgets, you actually start with the WebForms infrastructure which then internally creates another requests to your Feather widgets written as MVC. This WebForms path needs to be handled but I don’t use DI for this. I simply create logger manually and run the code since I don’t have much of my code handled in WebForms:

On start I create the logger and store it globally in request items so I can extract it when the request is finished. Other stuff should be obvious.

I need to run these methods on each request but this is easy, simply handle events in Global.asax.cs.

Sitefinity’s loggers

We already know how to override Sitefinity’s loggers. Since they are not tied to the request (Sitefinity runs internal jobs), they should have separate logger with different name, so we can distinguish them. But this is easy, simply create a logger when overriding trace listeners.

MVC widgets

Last piece of Sitefinity is MVC path for running widgets. We know how to inject services using DI container so now we only need to create an action filter:

We need to register this filter so we need a filter provider:

And now we need to register the filter in DI container and we are done:

We need one more thing: scope for MVC request:

Unity

There is another place where you should consider registering your logger and correlator: Unity in Sitefinity. For instance, you could log stuff in users provider.

Summary

Great! We have our loggers and correlators injected in all places. In the next part we will handle exceptions and errors using another filters.