Fundamentals of Logging in .NET Core

.NET Core SDK is a light weight SDK which includes a bare minimum set of features required to build an application. We can install NuGet packages for other features we require for our application. For this, Microsoft provides .NET APIs as .NET Extensions.

.NET Extensions is an open-source, cross-platform set of APIs for commonly used programming patterns and utilities, such as dependency injection, logging, and app configuration. Most APIs in this project are meant to work on many .NET platforms, such as .NET Core, .NET Framework, Xamarin, and other. While commonly used in ASP.NET Core applications, these APIs are not coupled to the ASP.NET Core application model. They can be used in console apps, WinForms and WPF, etc. You can find the documentation and the source code of extensions at https://github.com/aspnet/Extensions.

All the extensions are included under the Microsoft.Extensions namespace. You can find all built-in and third party extensions at nuget.org/packages.

The Logging API is included in the Microsoft.Extensions.Logging package. The Logging API does not work as standalone. It works with one or more logging providers that store or display logs to a particular medium such as Console, Debug, TraceListeners etc.

So, there are two important building blocks for implementing logging in a .NET Core based application:

  1. Logging API
  2. Logging Providers

The following figure illustrates logging in .NET Core:

.NET Frameworks

As you can see in the above figure, the logging API in Microsoft.Extensions.Logging works on the .NET Core based applications whether it is ASP.NET Core or EF Core. You just need to use the logging API with one or more logging providers to implement logging in any .NET Core based application.

Logging API

As mentioned before, Microsoft provides logging API as an extension in the wrapper Microsoft.Extensions.Logging which comes as a NuGet package.

Microsoft.Extensions.Logging includes the necessary classes and interfaces for logging. The most important are the ILogger, ILoggerFactory, ILoggerProvider interfaces and the LoggerFactory class.

The following figure shows the relationship between logging classes.

Logging API .NET Core
Logging API

Let's have an overview of each of the above class.

ILoggerFactory

The ILoggerFactory is the factory interface for creating an appropriate ILogger type instance and also for adding the ILoggerProvider instance.

public interface ILoggerFactory : IDisposable
{
    ILogger CreateLogger(string categoryName);
    void AddProvider(ILoggerProvider provider);
}

The Logging API includes the built-in LoggerFactory class that implements the ILoggerFactory interface. We can use it to add an instance of type ILoggerProvider and to retrieve the ILogger instance for the specified category. Visit ILoggerFactory and LoggerFactory for more information.

ILoggerProvider

The ILoggerProvider manages and creates an appropriate logger, specified by the logging category.

public interface ILoggerProvider : IDisposable
{
    ILogger CreateLogger(string categoryName);
}

We can create our own logging provider by implementing the ILoggerProvider interface. Visit ILoggerProvider for more information.

ILogger

The ILogger interface includes methods for logging to the underlying storage. There are many extension methods which make logging easy. Visit ILogger for more information.

public interface ILogger
{
    void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter);
    bool IsEnabled(LogLevel logLevel);
    IDisposable BeginScope<TState>(TState state);
} 

Logging Providers

A logging provider displays or stores logs to a particular medium such as a console, a debugging event, an event log, a trace listener, and others. Microsoft provides various logging providers as NuGet packages.

The following table lists important logging providers.

Logging Provider's NuGet Package Output Target
Microsoft.Extensions.Logging.Console Console
Microsoft.Extensions.Logging.AzureAppServices Azure App Services 'Diagnostics logs' and 'Log stream' features
Microsoft.Extensions.Logging.Debug Debugger Monitor
Microsoft.Extensions.Logging.EventLog Windows Event Log
Microsoft.Extensions.Logging.EventSource EventSource/EventListener
Microsoft.Extensions.Logging.TraceSource Trace Listener

Microsoft has also collaborated with various logging framework teams (including third parties like NLog, Serilog, Loggr, Log4Net, and others) to extend the list of providers compatible with Microsoft.Extensions.Logging. The following are some thrid-party logging providers:

Logging Provider Description
elmah.io Provider for the Elmah.Io service
Loggr Provider for the Logger service
NLog Provider for the NLog library
Serilog Provider for the Serilog library

Let's take an example using the Microsoft.Extensions.Logging.Console package which displays logs on the Console.

Console Logging Provider

Let's see how to display logs on the console using the NuGet package for a console provider.

The Microsoft.Extensions.Logging.Console package includes logging classes which send log output to the console.

The following figure illustrates how the logging API works with the console logging provider.

Logging in ASP.NET Core
Logging API with Console Logging Provider

As you can see in the above figure, the ConsoleLogger implements ILogger, while the ConsoleLoggingProvider implements ILoggingProvider. The ConsoleLoggerExtensions class includes extension method AddConsole(), which adds a console logger to the LoggerFactory.

Now, let's see how to display logs on the Console in the .NET Core console application.

First of all, create a new console application using the Console App (.NET Core) template in Visual Studio 2017 (or later).

Now, you need to install a NuGet package of Microsoft.Extensions.Logging. You can install it either using the NuGet Package Manager or executing the following command in the Package Manager Console.

PM> Install-Package Microsoft.Extensions.Logging

Now, you need to install a logging provider of your choice. Here, we will send logs on the Console, so, install the Microsoft.Extensions.Logging.Console package either using NPM or execute the following command in the Package Manager Console in Visual Studio.

PM> Install-Package Microsoft.Extensions.Logging.Console

After successfully installing the above two packages, you can now implement logging in your .NET Core console application, as shown below.

Example: Logging in .NET Core Console App
namespace DotnetCoreConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            ILoggerFactory loggerFactory = new LoggerFactory(
                            new[] { new ConsoleLoggerProvider((_, __) => true, true) }
                        );
            //or
            //ILoggerFactory loggerFactory = new LoggerFactory().AddConsole();
            
            ILogger logger = loggerFactory.CreateLogger<Program>();
            logger.LogInformation("This is log message.");
        }
    }
}
Output:
info: DotnetCoreConsoleApp.Program[0]
      This is log message.

In the above example, we created an object of the LoggerFactory class and assigned it to the ILoggerFactory type variable, as shown below.

ILoggerFactory loggerFactory = new LoggerFactory(
    new[] { new ConsoleLoggerProvider ((_, __) => true, true) }
);

The LoggerFactory can contain one or more logging providers, which can be used to log to multiple mediums concurrently. The constructor of the LoggerFactory accepts an array of different logger provider objects as new[] { }. We want to display logs on the console, so we need to create an object of the console logger provider ConsoleLoggerProvider.

There are four constructors of the ConsoleLoggerProvider. Use the one that allows lambda expression (Func<>) for log filtration and includeScope Boolean. Here, we don't want to filter any information so the lambda expression would always return true (_, __) => true, as shown below.

new ConsoleLoggerProvider((_, __) => true, true)

Then, we can use this object of the LoggerFactory to create a logger using which we can actually log information, errors, warnings, traces, debugs etc. loggerFactory.CreateLogger<Program>() creates a logger specific to the Program class so that the logger will display a message with context info, e.g. DotnetCoreConsoleApp.Program[0].

Most logging providers include an extension method of ILoggerFactory, which is a shortcut to add a provider to the logger factory. For example, to add a console logger provider to the LoggerFactory, just call the LoggerFactory.AddConsole() extension method with the same parameters as ConsoleLoggerProvider, as shown below.

public ILoggerFactory loggerFactory = new LoggerFactory().AddConsole();

This is more readable and maintainable than creating a logger provider manually. The above logger factory will display the same output as above.

Log Levels

Log levels indicate the importance or severity of log messages. Built-in log providers include extension methods to indicate log levels.

The following table lists log levels in .NET Core.

Log Level Severity Extension Method Description
Trace 0 LogTrace() Logs messages only for tracing purposes for the developers.
Debug 1 LogDebug() Logs messages for short-term debugging purposes.
Information 2 LogInformation() Logs messages for the flow of the application.
Warning 3 LogWarning() Logs messages for abnormal or unexpected events in the application flow.
Error 4 LogError() Logs error messages.
Critical 5 LogCritical() Logs failures messages that require immediate attention.

We can use extension methods to indicate the level of the log messages as shown below.

namespace DotnetCoreConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            ILoggerFactory loggerFactory = new LoggerFactory().AddConsole((_, __) => true);
            ILogger logger = loggerFactory.CreateLogger<Program>();
    
            logger.LogInformation("Logging information.");
            logger.LogCritical("Logging critical information.");
            logger.LogDebug("Logging debug information.");
            logger.LogError("Logging error information.");
            logger.LogTrace("Logging trace");
            logger.LogWarning("Logging warning.");
        }
    }
}

The above example will display the following output:

Visit Logging in .NET Core for more detailed information.

Want to check how much you know ASP.NET Core?