Adding Serilog to an ASP.NET Core 2+ Web Application

I use Serilog to log to a SQL database in most of my web applications and although it’s pretty well documented the details relevant to my projects are spread out over a few sites so I figured I’d gather them here together for future reference.

Packages

Install these packages from NuGet, though obviously you can adjust the sinks depending on where you prefer to log your events.

  • Serilog.AspNetCore
  • Serilog.Sinks.MSSqlServer
  • Serilog.Sinks.Console
  • Serilog.Sinks.ApplicationInsights

Code

Logging is best initialized in the Program class of the application as then if the application fails at startup details of the failure will logged, the downside of this is that configuration options aren’t available through dependency injection in Program so the configuration properties need to be retrieved explicitly.

This is based on the sample project from the Serilog.AspNetCore repository. If you’re adding a custom column as with the “VerificationCode” column below then you need to add it your logging table manually as it won’t be auto-created.


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)
	{
		ColumnOptions columnOptions = new ColumnOptions();
		// Don't include the Properties XML column.
		columnOptions.Store.Remove(StandardColumn.Properties);
		// Do include the log event data as JSON.
		columnOptions.Store.Add(StandardColumn.LogEvent);
		// Add additional VerificationCode column
		columnOptions.AdditionalDataColumns = new Collection
		{
			new DataColumn {DataType = typeof (string), ColumnName = "VerificationCode"},
		};

		Log.Logger = new LoggerConfiguration()
			.MinimumLevel.Debug()
			.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
			.Enrich.FromLogContext()
			.WriteTo.MSSqlServer(Configuration.GetConnectionString("LogConnection"), "_logs", columnOptions: columnOptions)
			.WriteTo.Console()
			.WriteTo.ApplicationInsightsEvents("<YOUR_APPLICATION_INSIGHTS_KEY>")
			.CreateLogger();

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

			BuildWebHost(args).Run();

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

	public static IWebHost BuildWebHost(string[] args) =>
		WebHost.CreateDefaultBuilder(args)
			.UseStartup<Startup>()
			.UseSerilog()
			.Build();
}

The Serilog logger is also available in your controllers without needing to be specifically injected, this is available project wide because we’ve set the logger static property of the log in the Program.cs file.


public class HomeController : Controller
{
	[HttpGet]
	public async Task<IActionResult> Index()
	{
		Log.Information("In the controller!");

		return View();
	}
}

The logs here go to the console (this can be viewed in debug by going to the output window and choosing “ASP.NET Core Web Server” from the “Show output list”), Application Insights and to a SQL database. Happily the SQL sink has now been updated for .NET Core and details can be found here. In the above example the additional column “LogEvent” is being captured as JSON in the logging SQL table. If creating a separate SQL user for logging it should be granted insert, update and select rights on the table.


grant insert, update, select on object::_logs to sql_user_resource

4 Comments

joe · 12th May 2018 at 7:11 pm

Are you able to inject a Logger of type ILogger to your application with this in place. I have not been able to figure this out. I am using the globally available Log to log to Serilog. Thanks for the writeup.

    Shinigami · 13th May 2018 at 11:23 am

    Hi Joe, yes, you can inject a serilog ilogger into your controller using this. I’m on holiday at the moment and don’t have access to any of my code but I’ll update the post with an example when I’m back next week.

Lukas · 9th July 2018 at 9:50 pm

Hello, how can you add custom database column (for example user, traceId, environment, etc..) into database log table ?

    Shinigami · 10th July 2018 at 9:51 am

    Hi Lukas, yep, you can indeed add custom columns, you just need to add the column to your table and then set the AdditionalColumns property in the ColumnOptions.

    ColumnOptions columnOptions = new ColumnOptions();
    // Don’t include the Properties XML column.
    columnOptions.Store.Remove(StandardColumn.Properties);
    // Do include the log event data as JSON.
    columnOptions.Store.Add(StandardColumn.LogEvent);
    // Add additional VerificationCode column
    columnOptions.AdditionalDataColumns = new Collection
    {
    new DataColumn {DataType = typeof (string), ColumnName = “VerificationCode”},
    };

    Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Debug()
    .MinimumLevel.Override(“Microsoft”, LogEventLevel.Information)
    .Enrich.FromLogContext()
    .WriteTo.MSSqlServer(Configuration.GetConnectionString(“Log”), “_logs”, columnOptions: columnOptions)
    .WriteTo.Console()
    //.WriteTo.ApplicationInsightsEvents(““)
    .CreateLogger();

    This is documented on their GitHub page (https://github.com/serilog/serilog-sinks-mssqlserver) as well.

Leave a Reply

Your email address will not be published. Required fields are marked *