Contextual logger injection for Autofac
TL;DR: install package AutofacSerilogIntegration, call
builder.RegisterLogger()
, and use constructor injection ofILogger
to get source type tagging.
When I use Serilog, I more often than not embrace the static Log
class and use a pattern like:
class Example
{
readonly ILogger _log = Log.ForContext();
public void Show()
{
_log.Information("Hello!");
}
}
Notice in this example the ForContext()
call. This creates a contextual logger that will tag all of the events created through it with the name of the specified class, in this case Example
. Serilog does this by attaching a property called SourceContext
.
SourceContext
can be very useful for filtering. Here, using the Seq sink, we can see all events raised by PreadmissionController
:
Logger Injection
When using an IoC container like Autofac, it’s quite common to inject a logger into the class using it. In this case our example would follow a slightly different pattern:
class Example
{
readonly ILogger _log;
public Example(ILogger log)
{
_log = log;
}
public void Show()
{
_log.Information("Hello!");
}
}
Here, instead of calling ForContext()
, the expectation is that the appropriate logger will be passed into the constructor by the caller.
Though I’ve tended to move away from this pattern in recent years (if for nothing else, just to cut down the number of parameters on constructors!) I’ve encountered lots of codebases that use this tactic and find it works well.
Unfortunately, despite founding both the Autofac and Serilog projects, when asked how to set this up I’ve had to point people to Google and newsgroup posts, and don’t think there’s been a comprehensive example online showing how it can work efficiently and reliably. So, finally, I’ve posted a working integration on GitHub and published it as the AutofacSerilogIntegration NuGet package. Here’s how it’s used.
Setting up the Autofac/Serilog Integration
As with all good stories, this one begins at the NuGet package manager command-line:
Install-Package AutofacSerilogIntegration
(This assumes you’ve installed both the Autofac and Serilog packages already.)
The first thing you should do in your application is configure a logger. I recommend assigning this to Log.Logger
even if you don’t intend to use the static Log
class, just in case any calls to the static logger slip in accidentally.
Log.Logger = new LoggerConfiguration()
.WriteTo.ColoredConsole()
.CreateLogger();
Next up, where your Autofac ContainerBuilder
is configured, call RegisterLogger()
. This is an extension method in the AutofacSerilogIntegration
namespace..
var builder = new ContainerBuilder();
builder.RegisterLogger();
And, that’s everything. For components created by the container, parameters of type ILogger
will now be fulfilled using a logger instance tagged with the correct type.
The RegisterLogger()
method accepts a couple of parameters - an ILogger
can be specified if you want to use a root logger separate from the static one, and property injection can be optionally enabled.
Closing thoughts…
This is a shiny new slice of code and there may still be scenarios it doesn’t handle so well. The beauty of getting it to GitHub is that over time it can be improved through use - pull requests appreciated! I hope it saves you some searching next time you hit File > New Project.