Update July 2016: RTM is here! The instructions below are now current with .NET Core 1.0.

If you’re writing ASP.NET apps with the latest tooling, you will inevitably encounter the Microsoft.Extensions.Logging package. It’s a dependency of ASP.NET MVC, WebForms and much of the related infrastructure. “What is this thing?” you ask. Great question!

The Framework writes log events

When an MVC controller is selected, when a static file is served, when an error is caught… ASP.NET and other framework libraries helpfully log this information.

In past .NET versions, System.Diagnostics.Trace was the output of choice, but the world has moved on and the newer package is an alternative with a more modern-feeling API.

What does it look like?

Like ASP.NET 5, your applications and libraries can write events to the framework’s logging pipeline:

var loggerFactory = new LoggerFactory().AddConsole();
var logger = loggerFactory.CreateLogger(typeof(Program).FullName);

logger.LogInformation("Handled in {ExecutionTime} ms", executionTime);

An ILoggerFactory creates ILoggers, and these provide the typical methods you’d expect for logging errors, warnings, debug events and so-on.

You might be surprised (or, you might not!) that just like Serilog, Microsoft.Extensions.Logging supports {Named} holes in its format strings, in addition to the typical {0} and {1}. This technique enables structured loggers to provide first-class search operations on not just the raw text of the log message, but the individual property values as well:

Execution Time gt 300 ms

The great thing is that if you’re not using a structured approach, messages will just come through the pipeline as strings - everyone’s looked after.

Microsoft.Extensions.Logging vs. Serilog, NLog, SLAB, log4net…

The designers of ASP.NET Core faced the same dilemma as other library authors in .NET: which logging library should they use to write events? The choice of logger is typically one the application author will make, so frameworks and libraries need a way to support more than one option.

Over time we’ve had a few solutions to this – Common.Logging has been popular, and more recently LibLog does a good of providing a dependency-free API on top of several loggers.

Microsoft.Extensions.Logging today is another of these, though it’s somewhat more capable (and in many ways it’s a very nice one).

Although out-of-the-box implementations are provided for basic console logging and a few other targets, you’ll need a logging back-end like Serilog or NLog to gain the kind of functionality expected by non-trivial apps.

So, how does that work?

Getting started

We’ll assume you want to use Serilog. (Instructions for NLog are pretty similar, and an example that uses it can be found here.) The ASP.NET Team wrote the original Serilog back-end for Microsoft.Extensions.Logging, and transferred it to the Serilog project where it’s currently supported and maintained.

First, install the Serilog.Extensions.Logging NuGet package into your web or console app, plus whichever sinks you need for log events.

Install-Package Serilog.Extensions.Logging -DependencyVersion Highest
Install-Package Serilog.Sinks.LiterateConsole

(This example uses the literate console sink, which works if you’re hosting in Kestrel or running from the console; if you’re using IIS to host the app, check out something like the Seq sink to collect and view logs out-of-process.)

Next, in your application’s Startup() method, configure Serilog first:

using Serilog;

public class Startup
  public Startup(IHostingEnvironment env)
    Log.Logger = new LoggerConfiguration()
    // Other startup code

Finally, in your Startup class’s Configure() method, remove the defaults and call AddSerilog() on the provided loggerFactory.

  public void Configure(IApplicationBuilder app, IHostingEnvironment env,
                        ILoggerFactory loggerFactory)

That’s it! When you run you’ll see log output like:

[12:30:27 INF] Request starting HTTP/1.1 GET http://localhost:5000/
[12:30:27 INF] Executing action method WebApplication1.Controllers.HomeController.Index
 with arguments (null) - ModelState is Valid'
[12:30:30 INF] Executing ViewResult, running view at path /Views/Home/Index.cshtml.
[12:30:31 INF] Executed action WebApplication1.Controllers.HomeController.Index in 0.3641ms
[12:30:31 INF] Request finished in 0.3922ms 200 text/html; charset=utf-8

Which API should my application use?

Personally, I’m content to let ASP.NET write events with the Microsoft.Extensions.Logging API, and to use Serilog’s native API in my application code. The designers of the framework API have gone out of their way to support a wide range of logging styles, so using either is reasonable. I’m obviously somewhat biased, but I prefer the more focused API of Serilog to the more general one from the framework. Your preferences might differ :-).

The important thing is - don’t miss the opportunity posed by ASP.NET Core to take your logging to the next level and get some structured events through your logging pipeline.

Getting help

If you have questions or comments please feel free to raise an issue on the tracker. We’re also frequently in the Serilog Gitter chat and happy to help if you get stuck!