- ASP.NET Core MVC
- ASP.NET Core logging with Serilog
- ASP.NET Core managed config
- ASP.NET Core MVC with /api/-area
- ASP.NET Core API versioning
- ASP.NET Core API with Swagger UI
- ASP.NET Core EF in separate project
- ASP.NET Core AutoMapper
- ASP.NET Core response cache
- ASP.NET Core memory cache
- ASP.NET Core TypeScript
Logging is a vital component in a well written application. Correctly implemented it makes debugging easier and functions as an audit log.
I have been using NLog for years. It works fine with ASP.NET Core, but there have been things that annoy me. For instance the inability to hook up to events, requiring writing of custom target modules and messing around with config to make them work. Sure it works, but it is complexity and effort spent where I don’t feel it is necessary.
So recently I have been testing Serilog.
Install
In Packet Manager Console, or NuGet browser, install:
1 2 3 4 |
Install-Package Serilog.AspNetCore -DependencyVersion Highest Install-Package Serilog.Settings.Configuration Install-Package Serilog.Sinks.File Install-Package Serilog.Sinks.Debug |
Implement
In Program.cs we want to wrap the full execution of our application, so that we catch any errors during startup. So we read appsettings.json in Program.cs, and we encapsulate the whole execution in a try-catch.
In Program.cs, add using:
1 |
using Serilog; |
Currently your Program.cs should look like this:
1 2 3 4 5 6 7 8 9 10 11 |
public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); |
Change to:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
public static int Main(string[] args) { var configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json") .Build(); Log.Logger = new LoggerConfiguration() .ReadFrom.Configuration(configuration) .CreateLogger(); try { Log.Information("Starting web host"); 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) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder .UseSerilog() .UseStartup<Startup>(); }); |
Note the change of return type from void to int in main. Returning a return code is strictly not necessary, but good practice.
Add configuration section
Add a Serilog section to appsettings.json:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
"Serilog": { "Using": [ "Serilog.Sinks.Debug" ], "MinimumLevel": { "Default": "Debug", "Override": { "Microsoft": "Error" } }, "WriteTo": [ { "Name": "Debug" }, { "Name": "File", "Args": { "path": "Logs\\log.txt", "rollingInterval": "Day", "retainedFileCountLimit": 31 } } ] } |
Note that we are setting log level for Microsoft to Error, so we avoid logs filling up with irrelevant .Net Core internal log elements.
Testing
Run application and it will log to Debug (Output-window in Visual Studio) and Logs-folder under project root.
Using
You can go for straight forward use of static Log-object.
1 2 3 4 5 |
Log.Debug("Debug test"); Log.Information("Information test"); Log.Warning("Warning test"); Log.Error("Error test"); Log.Fatal("Fatal test"); |
Or using Dependency Injection by ASP.NET Core logging interface:
1 2 3 4 5 6 7 8 9 10 11 12 |
public class HomeController : Controller { private readonly ILogger<HomeController> _logger; public HomeController(ILogger<HomeController> logger) { _logger = logger; _logger.LogTrace("This will not be seen because minimum level is debug"); _logger.LogInformation("HomeController loaded"); } ... |