joydip_kanjilal
Contributor

How to use advanced Serilog features in ASP.NET Core MVC

how-to
Jul 13, 20218 mins
C#Microsoft .NETSoftware Development

Take advantage of filters and request logging middleware in Serilog to reduce log verbosity and generate useful log summaries in your ASP.NET Core MVC applications.

blog 6 image
Credit: Broadcom

One of the great features of ASP.NET Core is its built-in support for logging. This means that you can take advantage of your logging framework to get infrastructure logs from your logging infrastructure. While this can help you gain deeper insights into your application metrics, this does have its downsides as well. For example, you would often get too many logs, i.e., too many messages in your logs that might not be meaningful.

Serilog is a third-party, open-source library that integrates nicely with ASP.NET Core and allows developers to easily log-structured event data to the console, to files, and various kinds of log targets. I’ve discussed on the basic features of Serilog in a previous article here. This article talks about a few advanced capabilities in Serilog such as reducing log verbosity and log message summary and how you can implement them in ASP.NET Core MVC 5.

To work with the code examples provided in this article, you should have Visual Studio 2019 installed in your system. If you don’t already have a copy, you can download Visual Studio 2019 here.

Create an ASP.NET Core MVC project in Visual Studio 2019

First off, let’s create an ASP.NET Core project in Visual Studio 2019. Following these steps will create a new ASP.NET Core MVC 5 project in Visual Studio 2019.

  1. Launch the Visual Studio IDE.
  2. Click on “Create new project.”
  3. In the “Create new project” window, select “ASP.NET Core Web App (Model-View-Controller)” from the list of templates displayed.
  4. Click Next.
  5. In the “Configure your new project” window, specify the name and location for the new project.
  6. Optionally check the “Place solution and project in the same directory” check box, depending on your preferences.
  7. Click Next.
  8. In the “Additional Information” window shown next, select .NET 5.0 as the target framework from the drop-down list at the top. Leave the “Authentication Type” as “None” (default).
  9. Ensure that the check boxes “Enable Docker,” “Configure for HTTPS,” and “Enable Razor runtime compilation” are unchecked as we won’t be using any of those features here.
  10. Click Create.

A new ASP.NET Core MVC 5 project will be created together with the default HomeController class. We’ll use this project to work with Serilog in the subsequent sections of this article.

Install the Serilog NuGet packages

If you have successfully created an ASP.NET Core project, the next thing you should do is add the necessary NuGet packages to your project. To do this, select the project in the Solution Explorer window and right-click and select “Manage NuGet Packages…” In the NuGet Package Manager window, search for the following packages and install them.

Serilog.AspNetCore Serilog.Sinks.File

Alternatively, you can install the two packages via the NuGet Package Manager console by entering the lines shown below.

PM> Install-Package Serilog.AspNetCore
PM> Install-Package Serilog.Sinks.File

Register Serilog in ASP.NET Core MVC

To start using Serilog in ASP.NET Core applications, you should register Serilog on the WebHostBuilder in the Program.cs file using the UseSerilog extension method as shown below.

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder => {
        webBuilder.UseStartup < Startup > ();
    }).UseSerilog();

Here is the complete source code of the Program class for your reference:

public class Program
    {
        public static void Main(string[] args)
        {
            try
            {
                string outputTemplate = "{Timestamp:yyyy-MM-dd
                    HH:mm:ss.fff} [{Level}] {Message}{NewLine}{Exception}";
                Log.Logger = new
                    LoggerConfiguration().WriteTo.File("C:LogsDemo.txt",
                    rollingInterval: RollingInterval.Day, outputTemplate:
                    outputTemplate).CreateLogger();
                CreateHostBuilder(args).Build().Run();               
            }
            catch
            {
                throw;
            }
            finally
            {
                Log.CloseAndFlush();
            }
        }
        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                }).UseSerilog();
    }

Configure Serilog in ASP.NET Core MVC

Serilog takes advantage of sinks to send logs to different log targets such as a text file or a database. You should write the following code in the Main method to configure the log target and specify the rolling interval and file size limit.

Log.Logger = new LoggerConfiguration()
    .WriteTo.File(Path.Combine("C:Logs", "Test-Log-{Date}.txt"),
    rollingInterval: RollingInterval.Day, fileSizeLimitBytes: 100000)
    .CreateLogger();

Understand Serilog event severity levels

Now that you’ve configured Serilog in your application, you can take advantage of the built-in interface ILogger to log data in action methods of your controller as shown below.

public IActionResult Index()
{
  _logger.LogInformation("Log message generated with INFORMATION severity level.");
  _logger.LogWarning("Log message generated with WARNING severity level.");
  _logger.LogError("Log message generated with ERROR severity level.");
  _logger.LogCritical("Log message log generated with CRITICAL severity level.");
  return View();
}

By default Serilog will log events of Information severity level and above. Two levels below Information level are also available — Debug and Verbose.

Create a Serilog logger instance in ASP.NET Core MVC

The following code snippet illustrates how the _logger instance has been created using dependency injection in the constructor of the HomeController class.

private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
   _logger = logger;
}

Here is the complete source code of the HomeController class for your reference:

public class HomeController : Controller
    {
        private readonly ILogger<HomeController> _logger;
        readonly IDiagnosticContext _diagnosticContext;
        public HomeController(ILogger<HomeController> logger)
        {
            _logger = logger;
        }
        [CustomSerilogLogging]
        public IActionResult Index()
        {
            _logger.LogInformation("Log message generated with
                INFORMATION severity level.");
            _logger.LogWarning("Log message generated with
                 WARNING severity level.");
            _logger.LogError("Log message generated with
                ERROR severity level.");
            _logger.LogCritical("Log message log generated with
                CRITICAL severity level.");
            return View();
        }
        public IActionResult Privacy()
        {
            return View();
        }
        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None,
            NoStore = true)]
        public IActionResult Error()
        {
            return View(new ErrorViewModel { RequestId =
                Activity.Current?.Id ?? HttpContext.TraceIdentifier });
        }
    }

If you run the application, the application will automatically navigate to the Home page by default. You’ll observe that a log file has been generated inside the C:Logs folder in your computer with the following content:

serilog aspnet core mvc 01 IDG

Figure 1: By default, Serilog logs events of Information severity level and above.

Note the highlighted text in Figure 1. Those are the lines that we’ve written to the log in the Index action method of the HomeController class. Note too that logging the events associated with Serilog’s default severity levels — Information, Warning, Error, and Fatal — can create very verbose logs. Fortunately we can reduce the verbosity of the log by turning off event levels we don’t care about.

Turn off unnecessary events in Serilog

Update the Serilog configuration you’ve specified in the Program class using filters as shown in the following code snippet.

Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
.WriteTo.File("C:LogsDemo.txt",
rollingInterval: RollingInterval.Day,
outputTemplate: outputTemplate).CreateLogger();

Note that, while we’ve changed the minimum event severity level to Debug, we have restricted logging to Information level and higher for system (“Microsoft”) events and Warning level and higher for ASP.NET Core. When you run the application again, here’s how the log file would look like this time:

serilog aspnet core mvc 02 IDG

Figure 2: Filtering log messages in Serilog.

The log messages have been reduced and the log looks much cleaner now, doesn’t it?

Use Serilog’s request logging middleware in ASP.NET Core MVC

Available as part of the Serilog.AspNetCore package, Serilog’s request logging middleware (i.e., the RequestLoggingMiddleware class) is used to add one summary log message per request in your application. In other words, you can take advantage of the request logging middleware to get a summary of all of the log messages for each request in your application.

To add RequestLoggingMiddleware to the pipeline, you need to call the UseSerilogRequestLogging() method. This method condenses the vital information of each request into a clean and concise completion event. Then to use RequestLoggingMiddleware all you have to do is specify the following line in the Configure method of the Startup class:

app.UseSerilogRequestLogging();

Now, if you run our application again, you’ll see the same log messages but with an additional summary log message from Serilog that lets you know the time taken to execute the request, as shown in Figure 3 below.

serilog aspnet core mvc 03 IDG

Figure 3: Serilog’s RequestLoggingMiddleware in action!

As logging is integral to every application, simplicity and flexibility are essential attributes for a logging framework. Serilog offers a logging framework that is simple to set up and can be used to log structured event data to a variety of logging destinations. Serilog’s request logging middleware may be used to filter out the vast majority of the infrastructure logs that are produced by default, allowing you to save time and resources. I’ll discuss more of Serilog’s advanced features in future articles here.

joydip_kanjilal
Contributor

Joydip Kanjilal is a Microsoft Most Valuable Professional (MVP) in ASP.NET, as well as a speaker and the author of several books and articles. He received the prestigious MVP award for 2007, 2008, 2009, 2010, 2011, and 2012.

He has more than 20 years of experience in IT, with more than 16 years in Microsoft .Net and related technologies. He has been selected as MSDN Featured Developer of the Fortnight (MSDN) and as Community Credit Winner several times.

He is the author of eight books and more than 500 articles. Many of his articles have been featured at Microsoft’s Official Site on ASP.Net.

He was a speaker at the Spark IT 2010 event and at the Dr. Dobb’s Conference 2014 in Bangalore. He has also worked as a judge for the Jolt Awards at Dr. Dobb's Journal. He is a regular speaker at the SSWUG Virtual Conference, which is held twice each year.

More from this author