Using .Net core default logger to log system events in production environment quite often can complicate things when attempting to aggregate and analise logs from multiple services via log analysers such as Sumo Logic.
Default Logger console writes are easy to read but basically become useless when thousands of messages are being collected into centralised analysis dashboard.
Serilog library on the other hand allows for structured event logging.
Also, with the help of various extensions and segregation of settings for dev and prod environment it possible to output coloured logs for ease of reading in IDE and de-serialise log message with JSON for improved data analysis.
IDE console Link to heading
Production console Link to heading
Setting up Serilog Link to heading
I use following nuget packages
- Serilog (main package)
- Serilog.AspNetCore (NetCore Adapter)
- Serilog.Sinks.Console (sink that writes log events to the console)
- Serilog.Settings.Configuration (Extension adapter for using appsettings.json)
some code omitted for brevity
Program.cs Link to heading
public static IHostBuilder CreateHostBuilder(string[] args) => | |
Host.CreateDefaultBuilder(args) | |
.UseSerilog((hostingContext, loggerConfiguration) => | |
loggerConfiguration | |
.ReadFrom.Configuration(hostingContext.Configuration)) | |
.ConfigureWebHostDefaults(webBuilder => | |
{ | |
webBuilder | |
.UseStartup<Startup>(); | |
}); |
Startup.cs Link to heading
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) | |
{ | |
... | |
app.UseSerilogRequestLogging(); | |
... | |
} |
It is safe to remove logging section from all appsettings.%ENV%.json files, Serilog has its separate overrides
appsettings.json Link to heading
{ | |
"Serilog": { | |
"Using": [ "Serilog.Sinks.Console"], | |
"MinimumLevel": { | |
"Default": "Warning", | |
"Override": { | |
"Microsoft": "Warning", | |
"System": "Warning", | |
"Microsoft.Hosting.Lifetime": "Debug" | |
} | |
}, | |
"Enrich": ["FromLogContext", "WithMachineName", "WithThreadId"] | |
} | |
} |
appsettings.Development.json Link to heading
{ | |
"Serilog": { | |
"MinimumLevel": { | |
"Default": "Information", | |
"Override": { | |
"Microsoft": "Information", | |
"System": "Information", | |
"Microsoft.Hosting.Lifetime": "Information" | |
} | |
}, | |
"WriteTo": [ | |
{ | |
"Name": "Console", | |
"Args": { | |
"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console" | |
} | |
} | |
] | |
} | |
} |
appsettings.Production.json Link to heading
{ | |
"Serilog": { | |
"WriteTo": [ | |
{ | |
"Name": "Console", | |
"Args": { | |
"formatter": "Serilog.Formatting.Json.JsonFormatter" | |
} | |
}] | |
} | |
} |
Sample use in ClazzService Link to heading
private readonly ILogger<PriceCalendarService> _logger; | |
public ClazzzService(ILogger<ClazzzService> logger) | |
{ | |
_logger = logger; | |
} | |
public async Task SomeMethod() | |
{ | |
try | |
{ | |
... | |
} | |
catch(Exception ex) | |
{ | |
_logger.LogError("{@EndPoint} {@HttpCode} {@ErrorCode} {@ErrorTitle} {@Request} {@ErrDetail}" | |
, _config.ServiceUrl | |
, HttpStatusCode.InternalServerError | |
, ErrorCodes.UnhandledErrorFromApi | |
, "Unhandled Error when getting response from Api for request" | |
, request.ToJsonStringSafe() | |
, ex); | |
} | |
} |