Asp.Net Core Logging Fundamentals

Spread the love

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

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 PackageOutput Target
Microsoft.Extensions.Logging.ConsoleConsole
Microsoft.Extensions.Logging.AzureAppServicesAzure App Services ‘Diagnostics logs’ and ‘Log stream’ features
Microsoft.Extensions.Logging.DebugDebugger Monitor
Microsoft.Extensions.Logging.EventLogWindows Event Log
Microsoft.Extensions.Logging.EventSourceEventSource/EventListener
Microsoft.Extensions.Logging.TraceSourceTrace 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 ProviderDescription
elmah.ioProvider for the Elmah.Io service
LoggrProvider for the Logger service
NLogProvider for the NLog library
SerilogProvider 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 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

 Copy

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 LevelSeverityExtension MethodDescription
Trace0LogTrace()Logs messages only for tracing purposes for the developers.
Debug1LogDebug()Logs messages for short-term debugging purposes.
Information2LogInformation()Logs messages for the flow of the application.
Warning3LogWarning()Logs messages for abnormal or unexpected events in the application flow.
Error4LogError()Logs error messages.
Critical5LogCritical()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:

Logging in ASP.NET Core

ASP.NET Core uses the same logging mechanism as .NET Core logging. So, it is highly recommended to go through the previous chapter Logging in .NET Core before reading this.

Here, we will implement logging in the ASP.NET Core 2.x MVC application.

As explained in the previous chapter, the logging API in Microsoft.Extensions.Logging namespace works with one or more built-in or third party logging providers. So, in an ASP.NET Core MVC application, we will also have to install the NuGet package Microsoft.Extensions.Logging and one or more logging providers of our choice.

Create an ASP.NET Core MVC application in Visual Studio 2017 (or later). When you create the ASP.NET Core MVC web application in Visual Studio 2017 (or later), it automatically includes the NuGet package for Microsoft.Extensions.Logging and the following logging providers under the Microsoft.AspNetCore.App NuGet package. So, we don’t have to install it manually.

  1. Microsoft.Extensions.Logging.Console
  2. Microsoft.Extensions.Logging.Debug
  3. Microsoft.Extensions.Logging.EventSource
  4. Microsoft.Extensions.Logging.TraceSource

Add Logging Providers

As mentioned in the previous chapter, we need to add providers in LoggerFactory. In the ASP.NET Core MVC application, the call to the WebHost.CreateDefaultBuilder(args) method in the Program.cs internally adds the Console, Debug, and EventSource logging providers.

Example: Program.cs

 Copy

public class Program

{

    public static void Main(string[] args)

    {

        CreateWebHostBuilder(args).Build().Run();

    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>

        WebHost.CreateDefaultBuilder(args)

               .UseStartup<Startup>();

}

Look at the source code of the WebHost.CreateDefaultBuilder() method on GitHub and you will find the following code:

.ConfigureLogging((hostingContext, logging) =>

    {

        logging.AddConfiguration(hostingContext.Configuration.GetSection(“Logging”));

        logging.AddConsole();

        logging.AddDebug();

        logging.AddEventSourceLogger();

    }).

Thus, if you want to use these providers, no need to add them manually. If you want to use other providers or any default provider, then you need to remove all the existing providers and add the provider of your choice. To configure logging providers, call the ConfigureLogging() extension method of IWebHostBuilder, as shown below.

Example: Program.cs

 Copy

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>

    WebHost.CreateDefaultBuilder(args)

    .ConfigureLogging(logBuilder =>

    {

        logBuilder.ClearProviders(); // removes all providers from LoggerFactory

        logBuilder.AddConsole(); 

        logBuilder.AddTraceSource(“Information, ActivityTracing”); // Add Trace listener provider

    })

    .UseStartup<Startup>();

In the above example, the ConfigureLogging() method takes action to delegate Action<ILogBuilder> to configure logging providers. To add logging providers of your choice, remove all the default providers using ClearProviers() and then call the extension method of a provider to add it, such as AddTraceSource() which will add the trace listener provider, and the AddConsole() method which will add the Console logging provider.

You can also configure the logging provider using ILoggerFactory in the Configure() method of the Startup class. Let’s see an example on how to store logs in a text file.

Store Logs in a Text File

To store logs in a file, install the NuGet package Serilog.Extensions.Logging.File. Serillog includes an extension method for ILoggerFactory but not for ILogBuilder (in v 1.1.0). So, go to the Startup.cs file and add the ILoggerFactory parameter in the Configure() method. Then, call the AddFile() extension method to add Serillog file provider, as shown below. ASP.NET Core dependency injection will automatically pass an instance of the LoggerFactory for this parameter.

Example: Startup.cs

 Copy

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

{

    // other code remove for clarity

    loggerFactory.AddFile(“Logs/mylog-{Date}.txt”);

}

This will store all the logs in the mylog-<date>.txt file, under the Logs folder in your application.

Create Logs in the Controller

We can use ILogger or ILoggerFactory anywhere in an application using ASP.NET Core DI (Dependency Injection). Consider the following example of HomeController:

Example: Logging in MVC Controller

 Copy

namespace AspDotNetCoreMvcApp.Controllers

{

    public class HomeController : Controller

    {

        private readonly ILogger _logger;

        public HomeController(ILogger<HomeController> logger){

            _logger = logger;

        }

        public IActionResult Index()

        {

            _logger.LogInformation(“Log message in the Index() method”);

            return View();

        }

        public IActionResult About()

        {

            _logger.LogInformation(“Log message in the About() method”);

            return View();

        }

    }

}

In the above example, the ILogger<HomeController> parameter is included in the constructor. ASP.NET Core DI will pass the ILogger instance, which can be used to log in the Index() and About() action methods.

Passing HomeController as generic type for the ILogger<HomeController>, will be used as a category. For example, specifying ILogger<HomeController< will display a fully qualified name AspDotNetCoreMvcApp.Controllers.HomeController in the logs, as shown below.

info: AspDoteNetCoreMvcApp.Controllers.HomeController[0]
       Log message in the Index() method

Let’s understand the above log message. Here, we logged information using the LogInformation() method, so it starts with “info:” followed by the fully qualified name of the class where a log is created: AspDoteNetCoreMvcApp.Controllers.HomeController[0]. [0] is the event id. You can specify this event id to identify a record, e.g. Id, page number or other important information which uniquely identifies a log. We didn’t specify any event id, so it will be 0. The next line is an actual log message: “Log message in the Index() method”.

The same can be achieved by passing ILoggerFactory in the constructor.

public class HomeController : Controller

{

    private readonly ILogger _logger;

    public HomeController(ILoggerFactory logFactory)

    {

        _logger = logFactory.CreateLogger<HomeController>();

    }

    public IActionResult Index()

    {

        _logger.LogInformation(“Log message in the Index() method”);

        return View();

    }

    public IActionResult About()

    {

        _logger.LogInformation(“Log message in the About() method”);

        return View();

    }

}

Now, run the above application from command prompt by navigating to /<app root folder>/bin/debug/netcoreapp2.1/, run the dotnet <app name>.dll command and then open http://localhost:5000 in the browser. It will display the same logs on the Console as above.

Logs:

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]

      Request starting HTTP/1.1 GET http://localhost:5000/

info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]

      Route matched with {action = “Index”, controller = “Home”}. Executing acti

on AspDoteNetCoreMvcApp.Controllers.HomeController.Index (AspDotNetCoreMvcApp)

info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]

      Executing action method AspDoteNetCoreMvcApp.Controllers.HomeController.In

dex (AspDotNetCoreMvcApp) – Validation state: Valid

info: AspDoteNetCoreMvcApp.Controllers.HomeController[0]

      Log message in the Index() method

info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]

      Executed action method AspDoteNetCoreMvcApp.Controllers.HomeController.Ind

ex (AspDotNetCoreMvcApp), returned result Microsoft.AspNetCore.Mvc.ViewResult in

 0.8505ms.

info: Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor[1]

      Executing ViewResult, running view Index.

info: Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor[4]

      Executed ViewResult – view Index executed in 231.2839ms.

info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]

      Executed action AspDoteNetCoreMvcApp.Controllers.HomeController.Index (Asp

DotNetCoreMvcApp) in 288.6931ms

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]

      Request finished in 946.274ms 200 text/html; charset=utf-8

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]

      Request starting HTTP/1.1 GET http://localhost:5000/images/banner1.svg

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]

      Request starting HTTP/1.1 GET http://localhost:5000/images/banner2.svg

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]

      Request finished in 5.6471ms 404

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]

      Request finished in 6.5811ms 404

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]

      Request starting HTTP/1.1 GET http://localhost:5000/css/site.min.css

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]

      Request finished in 0.2811ms 404

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]

      Request starting HTTP/1.1 GET http://localhost:5000/js/site.min.js

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]

      Request starting HTTP/1.1 GET http://localhost:5000/images/banner3.svg

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]

      Request finished in 0.178ms 404

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]

      Request finished in 0.2342ms 404

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]

      Request starting HTTP/1.1 GET http://localhost:5000/css/site.min.css

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]

      Request finished in 0.1173ms 404

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]

      Request starting HTTP/1.1 GET http://localhost:5000/js/site.min.js

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]

      Request finished in 0.2539ms 404

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]

      Request starting HTTP/1.1 GET http://localhost:5000/favicon.ico

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]

      Request finished in 0.3253ms 404

Thus, we can implement logging in ASP.NET Core MVC application.

Leave a Comment

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

https://www.cooljerseyedge.com, https://www.collegeshopfan.com, https://www.kcchiefsgearusa.com, https://www.dlionsgearusa.com, https://www.bravensgearusa.com, https://www.cbengalsgearusa.com, https://www.gbpackersgearusa.com, https://www.htexansgearusa.com, https://www.laramsgearusa.com, Josh Allen Wyoming Jersey, https://www.dcowboysgearusa.com, https://www.mdolphinsgearusa.com, https://www.aliexfanshop.com, https://www.bestplayershop.com, https://www.collegeedgeshop.com, https://www.giantsonlinefans.com