Author : HASSAN MD TAREQ

Installing packages

Install-Package Serilog.AspNetCore -DependencyVersion Highest

Install-Package Serilog.Settings.Configuration

Install-Package Serilog.Sinks.Console
Install-Package Serilog.Sinks.File
Install-Package Serilog.Sinks.Async

Install-Package Serilog.Formatting.Compact

Install-Package Serilog.Enrichers.Environment
Install-Package Serilog.Enrichers.Process
Install-Package Serilog.Enrichers.Thread

appsettings json

{
  "Serilog": {
    "MinimumLevel": {
      "Default": "Debug",
      "Override": {
        "Microsoft": "Warning",
        "System": "Warning"
      }
    },
    "Enrich": [
      "FromLogContext"
    ],
    "Properties": {
      "Application": "HoverApp"
    },
    "WriteTo": [
      {
        "Name": "Console",
        "Args": {
          "outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} <s:{SourceContext}>{NewLine}{Exception}",
          "theme": "Serilog.Sinks.SystemConsole.Themes.SystemConsoleTheme::Literate, Serilog.Sinks.Console"
        }
      },
      {
        "Name": "Async",
        "Args": {
          "configure": [
            {
              "Name": "File",
              "Args": {
                "formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact",
                "path": "C:\\serilog\\hoverapp_log.ndjson",
                "fileSizeLimitBytes": "null",
                "rollOnFileSizeLimit": "true",
                "retainedFileCountLimit": "null",
                "shared": "true"
              }
            }
          ]
        }
      }
    ]
  }
}

Logger initialization in Program class

  • all settings are in appsettings.json & can be overriden by fluent api (some settings are not possible by appsettings.json, those seeting are set by fluent api)
  • try/catch used to log application start-up exceptions
  • Plugging into ASP.NET Core with UseSerilog()
  • Important: Serilog in ASP.NET Core 3 plugs into the generic host and not webBuilder
  • https://github.com/serilog/serilog-aspnetcore

Program.cs

public class Program
{
	public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
		.SetBasePath(Directory.GetCurrentDirectory())
		.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
		.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
		.AddEnvironmentVariables()
		.Build();

	public static int Main(string[] args)
	{
		Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(Configuration).CreateLogger();

		try
		{
			Log.Information("Getting the motors running...");

			CreateHostBuilder(args).Build().Run();

			return 0;
		}
		catch (Exception ex)
		{
			Log.Fatal(ex, "Host terminated unexpectedly");
			return 1;
		}
		finally
		{
			Log.CloseAndFlush();
		}
	}

	public static IHostBuilder CreateHostBuilder(string[] args){
	
		// Serilog in ASP.NET Core 3 plugs into the generic host and not webBuilder
		
		return Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder => {
				webBuilder.UseStartup<Startup>();
			})
			.UseSerilog(); // <- Plug Serilog into the pipeline;
	}
}

Logging section in appsettings json

  • Since Serilog is plugged into ASP.Net core, all logging will be done by Serilog
  • Even if logging is done by ILogger<T> of ASP.Net core (by DI), logging will be done by Serilog
  • Logging section in appsettings.json will not be used by Serilog, so remove Logging section from all appsettings.json (default, Development, Production etc.)

Logging in Controller

HomeController.cs

using Serilog;

public class HomeController : Controller
{
    private static IFooService _fs;
    
    public HomeController(IFooService fs)
    {
        _fs = fs;
    }
    
    public IActionResult Index()
    {

        var foo = new Foo { Id = 2, FooName = "FooTwo" };
		
        Log.Information("Object: {@FooMan}", foo); // @ : destructuring operator
        
        return View();
    }
}

seq sink

seq in docker: Running seq in docker

seq sink package installation

Install-Package Serilog.Sinks.Seq

configuration for seq in appsettings.json

{
  "Serilog": {
    "MinimumLevel": {
      "Default": "Debug",
      "Override": {
        "Microsoft": "Warning",
        "System": "Warning"
      }
    },
    "Enrich": [
      "FromLogContext"
    ],
    "Properties": {
      "Application": "HoverApp"
    },
    "WriteTo": [
      // ... ... ...
      {
        "Name": "Seq",
        "Args": {
          "serverUrl": "http://localhost:5341",
          "compact": true
        }
      }
    ]
  }
}

Request logging

  • Serilog.AspNetCore includes middleware for smarter HTTP request logging ( The default request logging implemented by ASP.NET Core is noisy, with multiple events emitted per request)
  • UseSerilogRequestLogging() => plugs request logging middleware
  • It’s important that the UseSerilogRequestLogging() call appears before handlers such as MVC
  • to exclude noisy handlers from logging, such as UseStaticFiles(), by placing UseSerilogRequestLogging() after them
  • https://github.com/serilog/serilog-aspnetcore#request-logging

To enable the middleware, first change the minimum level for Microsoft.AspNetCore to Warning

{
  "Serilog": {
    "MinimumLevel": {
      "Default": "Debug",
      "Override": {
        "Microsoft.AspNetCore": "Warning"
      }
    },
    // ... ... ...
}

In Startup.cs, add the middleware with UseSerilogRequestLogging()

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

	app.UseSerilogRequestLogging(); // <-- Add this line

	// Other app configuration
	// ... ... ...
}

options callback on UseSerilogRequestLogging() (modify message template, events, properties etc.)

// ... ... ...

app.UseSerilogRequestLogging(options =>
{
    // Customize the message template
    options.MessageTemplate = "Handled {RequestPath}";
    
    // Emit debug-level events instead of the defaults
    options.GetLevel = (httpContext, elapsed, ex) => LogEventLevel.Debug;
    
    // Attach additional properties to the request completion event
    options.EnrichDiagnosticContext = (diagnosticContext, httpContext) =>
    {
        diagnosticContext.Set("RequestHost", httpContext.Request.Host.Value);
        diagnosticContext.Set("RequestScheme", httpContext.Request.Scheme);
    };
});

// ... ... ...

Response logging