How To Implement Logging in ASP.NET Core

In this post, I will discuss how to implement logging in ASP.NET core. A similar logging mechanism is used by ASP.NET Core and .NET Core. The chapter Logging in .NET Core is highly recommended before reading this one.

ASP.NET Core MVC application logging will be implemented here.

These APIs support both built-in and external log providers and can be used both internally and externally. The Microsoft.Extensions.Logging NuGet package along with our choice of logging providers must also be installed in an ASP.NET Core MVC application.

The first step is to create a Visual Studio 2017 (or later) ASP.NET Core MVC application. Under the Microsoft.AspNetCore.App NuGet package, ASP.NET Core MVC web applications are automatically packaged with the NuGet package for Microsoft.Extensions.Logging. As a result, we do not need to manually install it.

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

Providers for logging should be added

We need to add providers to LoggerFactory, as discussed in the previous chapter. WebHost.CreateDefaultBuilder(args) in Program.cs automatically adds the Console, Debug, and EventSource logging providers to programs that use ASP.NET Core MVC.

Example: Program.cs

public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
               .UseStartup<Startup>();
}

In the WebHost.CreateDefaultBuilder() method’s source code on GitHub, you’ll find the following code:

.ConfigureLogging((hostingContext, logging) =>
    {
        logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
        logging.AddConsole();
        logging.AddDebug();
        logging.AddEventSourceLogger();
    }).

In this case, there is no need to manually add these providers if you wish to use them. By removing all existing providers and adding your choice, you can add another provider or any default provider. IWebHostBuilder offers an extension method called ConfigureLogging() for configuring logging providers.

Example: Program.cs

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>();

A logging provider can be configured when you invoke the ConfigureLogging() method. When you call the extension methods AddTraceSource() and AddConsole(), for example, you can add type of logging provider of your choice. You can also remove the default logging providers using ClearProviers(), which allows you to add logging providers of your choice.

The Startup class also has a Configure() method that allows you to configure the logging provider using ILoggerFactory. A text file is used in this example to store logs.

Store Logs in a Text File

Using Serilog.Extensions.Logging.File, logs can be stored in a file. For ILogBuilder (in version 1.1.0), Serillog does not have an extension method. The Configure() method in Startup.cs needs to be changed to include the ILoggerFactory parameter. After adding the Serillog file provider, call AddFile() in the extension method. ASP.NET Core dependency injection will automatically pass an instance of the LoggerFactory to this parameter.

Example: Startup.cs

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 
{
    // other code remove for clarity 
    loggerFactory.AddFile("Logs/mylog-{Date}.txt");
}

In your application, this will create a file named mylog-date.txt under the Logs folder.

The controller should be configured to create logs

As long as we use ASP.NET Core DI (Dependency Injection), we can use ILogger or ILoggerFactory anywhere in the application. HomeController can be illustrated as follows:

Example: Logging in MVC Controller

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();
        }
    }
}

As seen above, the ILogger<HomeController> parameter is included in the constructor. The Index() and About() action methods in ASP.NET Core DI have access to the ILogger instance, which can be used to log events.

ILogger*HomeController> will be used as a category by passing HomeController as its generic type. Logs will display the fully qualified name AspDotNetCoreMvcApp.Controllers.HomeController, for example.

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

Taking a look at the above log message, let’s understand what it means. AspDoteNetCoreMvcApp.Controllers.HomeController[0] is the class where information is logged with the LogInformation() method: AspDoteNetCoreMvcApp.Controllers.HomeController[0]. An event id is given by [0]. A record’s event id, for example, a log’s Id, page number, or another important identifier can be used to identify the record. No event id was specified, so 0 will be used. In the Index() method, a log message appears: “Log message”.

ILoggerFactory can be passed in the constructor to achieve the same result.

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();
    }
}

The application can then be run from the 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. Logs will appear on the Console in the same way as before.

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

ASP.NET Core MVC applications can therefore log events.

Leave a Comment