Setting up Serilog in ASP.NET core with JSON configuration and write the logs to JSON formatted file

Serilog is a diagnostic logging library for .NET applications. It is easy to set up, has a clean API, and runs on all recent .NET platforms.
I assume you already have an ASP.NET application, so I will start directly with the required steps to set up Serilog in that application.

Step 1) Initially, we will need four packages:

  1. Serilog.AspNetCore:  this package will route ASP.NET Core log messages through Serilog, also by installing this package we will install all other required packages for ASP.NET including the Serilog package.
  2. Serilog.Settings.Configuration: this package required so we can read from  Microsoft.Extensions.Configuration sources, including .NET Core’s appsettings.json file.
  3. Serilog.Enrichers.Environment: this package will enrich Serilog events with information from the process environment.
  4. Serilog.Enrichers.Thread: this package will enrich Serilog events with properties from the current thread.

install these packages by using Nuget Manager or the following commands if you prefer command lines:

Install-Package  Serilog.AspNetCore
Install-Package Serilog.Settings.Configuration
Install-Package Serilog.Enrichers.Environment
Install-Package Serilog.Enrichers.Thread

Step 2) Change Program.cs file to the following code :

public class Program
    {
        public static void Main(string[] args)
        {
            var configuration = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json")
                .Build();

            Log.Logger = new LoggerConfiguration()
                .ReadFrom.Configuration(configuration)
                .CreateLogger();


            try
            {
                Log.Warning("Application Starting...");
                CreateHostBuilder(args).Build().Run();
            }
            catch (Exception ex)
            {
                Log.Fatal(ex, "Application terminated unexpectedly");
            }
            finally
            {
                // clean the code 
                Log.CloseAndFlush();
            }

        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .UseSerilog() // Sets Serilog as the logging provider
            .ConfigureWebHostDefaults(webBuilder =>
            {
               webBuilder.UseStartup<Startup>();
            });
    }

In this code, we provide a mechanism for reading configuration values using the ConfigurationBuilder so we can read the Serilog configuration from appsettings.json file.

var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();

then add ReadFrom method which is a Serilog extension method of LoggerSettingsConfiguration to read the configuration values in appseting.json

Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();

then wrap the CreateHostBuilder(args).Build().Run(); with a try, catch, and finally block so we can use the logger safely, in the finally block we make sure to write any pending logs if there are any by using Log.CloseAndFlush();.

finally, we change the logger provider to use Serilog by adding UseSerilog() which is a Serling extension method of IWebHostBuilder.

public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .UseSerilog() // Sets Serilog as the logging provider
            .ConfigureWebHostDefaults(webBuilder =>
            {
               webBuilder.UseStartup<Startup>();
            });

Step 3)  Change appsettings.json to the following :

{
  "Serilog": {
  "Using": [],
  "MinimumLevel": {
    "Default": "Information",
    "Override": {
      "Microsoft": "Warning",
      "System": "Warning"
      }
    },
  "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ],
  "WriteTo": [
    { "Name": "Console" },
    {
      "Name": "File",
      "Args": {
            "path": "Logs/log.json",
            "rollingInterval": "Day",
            "formatter": "Serilog.Formatting.Json.JsonFormatter, Serilog"
          }
    }
  ]
 },
 "AllowedHosts": "*"
}

first, remove the “Logging” section in appsetting.json since this section is related to the default ASP.NET logger.
second, add the Serilog section in appsetting.json , this section includes the following sections:
Serilog: this is the Root section name.
Using: this section contains list of assemblies in wich configuration methods (WriteTo.File(), Enrich.WithThreadId()) resides.
MinimumLevel: this section determines at which level log events are generated.
Enrich: adds additional content to every log by choosing the Enricher name (Enrichers packages can be added from NuGet Package Manager)
WriteTo: this section will determine where to write the logs.

Run the application, go to Log folder in the root of your application, check the file content you will find a rich and informative logs that include machine name and thread id, the ThreadId came from the enricher we added to the application, if we need to add more information to the log we can check other enrichers packages.

Extra Configurations: 
1) We can log information about each request in ASP.NET by adding app.UseSerilogRequestLogging() middleware into Startup.cs 

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSerilogRequestLogging();


app.UseRouting();

app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}

Note that adding app.UseSerilogRequestLogging() after app.UseStaticFiles() will not log requests of static files like .js or .css files, if you want to log these requests add app.UseSerilogRequestLogging() before app.UseStaticFiles()

2) If we want to use text formatting instead of JSON formatting, the log message can be formatted using “outputTemplate” section inside file section like the following :


{

"Serilog": {
"Using": [],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ],
"WriteTo": [
{ "Name": "Console" },
{
"Name": "File",
"Args": { "path": "App_Data/Logs/log.log" },
"outputTemplate": "{Timestamp:G} {Message}{NewLine:1}{Exception:1}"
}
]
},

"AllowedHosts": "*"
}

3) Default file size limit is 1 GB to handle the file size and rolling policies check https://github.com/serilog/serilog-sinks-file

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s