Logging with Serilog
Tags: serilog, structuredlogging, aspnetcore
Published: 2020-04-20 09:41:00

This blog post illustrates structured logging and the goal of using such an approach compared to the traditional way of logging (`log4net, NLog`),
Another follow-up article demonstrating the use of `Serilog` with `Elasticsearch` acting as a log repository and running `Docker` [is here](https://dev.to/hasdrubal/structure-logging-with-serilog-and-seq-and-elasticsearch-under-docker-16dk), if you are a `Serilog` novice, this blog article is for you.

## Why Serilog and structured logging?
Structured logging and `Serilog` are different. We can store the object as it is or finely-tuned to record just the right information for optimal diagnostics depending in our use case and what we need to log, then deconstructing the object using the `Serilog` framework on your behalf does not need to record all of the object’s fields of interest, get them into desired string format, and then store them in log instructions.

`Serilog` includes many integrations that cover many cases such as:

* Logging to console
* Logging to file
* Logging to data base
* Logging  to Message queues
* Logging to logstash and elasticsearch
* Serilog also controls the way events are captured and enriched

The use of structured logging also has other advantages:

* We can store our logs in databases like `ElasticSearch` which offer quite impressive search functions on this type of data.
* We can build KPIs around stored logs using `ElasticSearch`
* We can create a dashboards with nice widgets, pie, graphics.
* We can store our logs directly in `Seq`, then we can benefit from the ability to search and filter the logs using `SQL` like language
* Great documentation and community
* `C#` based configuration

## How it works ?
Install the core Serilog package and the File sinks
In Visual Studio, open the Package Manager Console and type:

Install-Package Autofac
Install-Package Autofac.Extensions.DependencyInjection
Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson
Install-Package Microsoft.Extensions.DependencyInjection
Install-Package Microsoft.Extensions.Hosting
Install-Package Microsoft.Extensions.Logging
Install-Package Microsoft.Extensions.Options
Install-Package Newtonsoft.Json
Install-Package Serilog
Install-Package Serilog.AspNetCore
Install-Package Serilog.Extensions.Hosting
Install-Package Serilog.Extensions.Logging
Install-Package Serilog.Settings.AppSettings
Install-Package Serilog.Settings.Configuration
Install-Package Serilog.Sinks.File

In the Main method we need to initialize `Serilog` and for this purpose we need to grab the configuration and configure `Serilog` inside the `CreateSerilogLogger`.

```csharp
var configuration = GetConfiguration();
Log.Logger = CreateSerilogLogger(configuration);
```
Grab the the configuration from `appsettings.json` and build the Configuration object:
```csharp
private static IConfiguration GetConfiguration()
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
        .AddJsonFile($"appsettings.Development.json", optional: true)
        .AddEnvironmentVariables();
   return builder.Build();
        }
```
Configure `Serilog` like below:
```csharp
private static ILogger CreateSerilogLogger(IConfiguration configuration)
{
     return new LoggerConfiguration()
          .MinimumLevel.Verbose()
          .Enrich.WithProperty("ApplicationContext", AppName)
          .Enrich.FromLogContext()
          .WriteTo.File("log.txt", rollingInterval: RollingInterval.Day)
          .CreateLogger();
}
```
Add some configuration in the `appsettings.json`:
```json
{
  "Serilog": {
    "MinimumLevel": {
      "Default": "Debug",
      "Override": {
        "Microsoft": "Debug",
        "CatalogAPI": "Debug",
        "MYSHOP": "Debug",
        "System": "Warning"
      }
    }
  }
}
```
And finally the body of the Main method should look like this:
```csharp
public static int Main(string[] args)
{
    var configuration = GetConfiguration();

    Log.Logger = CreateSerilogLogger(configuration);

    try
    {
       Log.Information("Configuring web host ({ApplicationContext})", AppName);
       var host = CreateHostBuilder(configuration, args);

       Log.Information("Starting web host ({ApplicationContext})", AppName);
       host.Run();

       return 0;
    }
    catch (Exception ex)
    {
       Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName);
       return 1;
    }
    finally
    {
       Log.CloseAndFlush();
    }
}
```
## Structured logging
The main benefit from `Serilog` is the structured logging feature:

The traditionnal way of logging messages into any support (file, database) was always in a unstructured way

But with `Serilog` we can store my information in a structured way.

In the below example we tell `Serilog` to replace `{FirstName}` with `Ali` and `{LastName}` with `MSELMI`, this produces not only a nice log message (as any logging framework does), but also tells `Serilog` to structure the data in `key / value` pairs, `FirstName/LastName` keys and theirs values.

The outcome of this feature is to store structured data into `nosql` databases like `mongodb` or `Elasticsearch` and we can filter, export data, create dashboards and even create useful KPIs for example.
```csharp
Log.Information("Hello {FirstName} {LasttName}", "Ali", "MSELMI");
```
As you can see, `Seq` captured the events coming from `Serilog` in structured manner.

![Seq](https://i0.wp.com/mselmi.net/wp-content/uploads/2020/04/2020-04-19-21_34_11-Seq-and-30-more-pages-Personal-Microsoft%E2%80%8B-Edge.png?w=1524&ssl=1 "Seq")

And now we can filter the logs using SQL-like language using structured data.

![Seq](https://i1.wp.com/mselmi.net/wp-content/uploads/2020/04/2020-04-19-21_41_32-Seq-and-30-more-pages-Personal-Microsoft%E2%80%8B-Edge.png?w=1528&ssl=1"Seq")

## Conclusion
`Log4net` has served as default logging choice for the past two decades, but `Serilog` offered a new way of logging (Structured logging, enrichments) and `C#` based configuration.

In most cases, I would recommend you to use `Serilog` logging framework and to continue to use `log4net` only when you are working on legacy system