Data Logging In ASP.NET Core Using Serilog

Introduction

Logging is a very critical and essential part of any software. It helps us in the investigation of the essence of problems. ASP.NET Core has built-in support for logging API's, which is able to work with various logging providers. Using these built-in providers, we can send application logs to one or more destinations and also, we can plug in third party logging frameworks such as Serilog, Nlog, etc.

Serilog is a good logging framework and it is built with the structured log data in mind. It is a kind of serializer. Serilog determines the right representation when the properties are specified in log events.

Feature of Serilog

  • Simple and extendable API
  • Support structured data
  • Log to variety of targets such as file, database, event log, etc.

To use Serilog logging feature with ASP.NET core, we need to add the dependency of "Serilog.Extensions.Logging". As we are aware that Serilog has a variety of providers like file provider, SQL provider etc., using file provider, we can write the log data in to the file in text format. Serilog does not support .NET Framework Core for SQL Server provider, so if we want to do SQL logging with Serilog, we need to use .NET Framework 4.5.

Log Data into File using Serilog

To write log data in to the file, we can use "Serilog.Extensions.Logging.File" extension dependency. This extension has a method known as "AddFile" on the LoggerFactory. It accepts the file path as a parameter.

Project.json

  1. {  
  2.     "version""1.0.0-*",  
  3.     "buildOptions": {  
  4.         "preserveCompilationContext"true,  
  5.         "debugType""portable",  
  6.         "emitEntryPoint"true  
  7.     },  
  8.     "dependencies": {},  
  9.     "frameworks": {  
  10.         "netcoreapp1.0": {  
  11.             "dependencies": {  
  12.                 "Microsoft.NETCore.App": {  
  13.                     "type""platform",  
  14.                     "version""1.0.1"  
  15.                 },  
  16.                 "Microsoft.AspNetCore.Server.Kestrel""1.0.0",  
  17.                 "Microsoft.AspNetCore.Mvc""1.0.0",  
  18.                 "Serilog.Extensions.Logging.File""1.0.0"  
  19.             },  
  20.             "imports""dnxcore50"  
  21.         }  
  22.     }  
  23. }   

Startup.cs

  1. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) {  
  2.     loggerFactory.AddFile("Logs/Example-{Date}.txt");…….…….  
  3. }  

Here, the file name includes {Date} to specify the date portion in the file name. We may use any environment variable as a part of the file name.

By Default, Serilog writes the file in plain text and the log file contains the fields given below.

Field

Description

Timestamp

Event time

Request id

Uniquely identifies for all the messages raised during a single Web request.

Level

Event log level (Three character code in square brackets).

Message

Log message.

Event id

Identifies the messages generated from the same format string/message template.

Exception

Exception if any.



As we know, ASP.NET Core has a built-in support for DI (Dependency Injection). Therefore, we can get the instance of ILogger object to controller or Middleware. Here, we need to store the instance of ILogger object to the local variable, so that we can use this instance anywhere in Controller, as we need.

HomeController.cs

  1. public class HomeController: Controller {  
  2.     ILogger _logger;  
  3.     public HomeController(ILogger < HomeController > logger) {  
  4.         _logger = logger;  
  5.     }  
  6. }  

In the example given below, I have logged the some text, using LogInformation and LogWarning method.

  1. [Route("home/LogData")]  
  2. public IActionResult LogData() {  
  3.     _logger.LogInformation("Log Information to Debug Window!");  
  4.     _logger.LogWarning("Log Warning to Debug Window!");  
  5.     return View();  
  6. }  

Output


Serilog has a capability to serialize a log event property as a structured object. Serilog provides the “@” de-structuring operator and by this operator, it pulls the value from the structured data. For example, I have a user class object and I want to store the property values into the log file. In this case, Serilog will help us. In the example given below, I have passed the user object and Serilog will store the user class properties in form of JSON.

Action method in Controller class

  1. [Route("home/LogDataFormated")]  
  2. public IActionResult LogDataFormated() {  
  3.     User user = new User();  
  4.     user.ID = 1;  
  5.     user.Name = "Jignesh";  
  6.     _logger.LogInformation("Log Information {@User}", user);  
  7.     _logger.LogWarning("Log Warning to Debug Window!");  
  8.     return View("LogData");  
  9. }   

Output in text File


It is also able to handle the collection type object.

Example

  1. var intValue = new[] { 1, 2, 3, 4 };  
  2.   
  3. _logger.LogWarning("Log Warning: {IntValue}", intValue);  

Output


Serilog is able to recognize the list given below of basic scalar types.

  • Booleans
  • Numeric byte, short, ushort, int, uint, long, ulong, float, double, decimal
  • Strings string, byte[]
  • Temporal DateTime, DateTimeOffset, TimeSpan
  • Others Guid, Uri
  • Nullables nullable versions of any of the above define type

Serilog also supports Stringification. The Stringification is the process of taking the value of ToString() method for the supplied .NET property. Some .NET types do not support serialization or support it very poorly and it is also handled by Serilog, using Stringification.

For example, when we pass SqlConnection object for the formatted string, Serilog doesn't recognize the type, then Serilog renders an object, using ToString() method.

Example

  1. SqlConnection connection = new SqlConnection();  
  2. _logger.LogWarning("Log Warning: Connection object - {connection}"connection);  

Output


Summary

Using the method described above, we can create log file, using Serilog with ASP.NET Core. It is very simple to use and maintain. We can create different log files or break up our log file logically, as per our need. As described above, I have breakup log file, which is based on the current date.