We used to do this:
// Configure logging providers
builder.Logging.ClearProviders();
builder.Logging.AddSerilog();
builder.Logging.AddCustomLoggerProvider();
However, to use UseSerilogRequestLogging
you have to do services.AddSerilog()
I can’t manage to get the custom logger provider to work. We tried using AddSerilog(this IServiceCollection collection, ILogger logger = null, bool dispose = false, LoggerProviderCollection providers = null)
but it doesn’t seem to work.
var loggerProviders = new Serilog.Extensions.Logging.LoggerProviderCollection();
loggerProviders.AddProvider(new CustomLoggerProvider());
services.AddSerilog(null, false, loggerProviders);
The
builder.Services.AddSerilog()
call will redirect all log events through your Serilog pipeline.
src: https://github.com/serilog/serilog-aspnetcore/blob/680af2e3c6b16740366d6dc4a96d20cfa9ceab01/README.md?plain=1#L51
How can we add custom logger providers to the Serilog pipeline?
3
You can add “AddHttpLogging” to service providers.
builder.Services.AddHttpLogging(options =>
{
options.LoggingFields = HttpLoggingFields.RequestHeaders |
HttpLoggingFields.RequestBody |
HttpLoggingFields.ResponseHeaders |
HttpLoggingFields.ResponseBody;
});
then add this to “WebApplication”
app.UseSerilogRequestLogging();
app.UseHttpLogging();
There’s no need for a custom logger. AddSerilog
adds Serilog as a custom logger to Microsoft.Extensions.Serilog
. Serilog itself needs to be configured separately. The question’s code seems to be using Serilog.AspNetCore. The package’s docs show how to configure Serilog, how to register it and how to enable request logging :
using Serilog;
//Serilog configuration
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateLogger();
try
{
Log.Information("Starting web application");
var builder = WebApplication.CreateBuilder(args);
// Integrate Serilog with Microsoft.Extensions.Logging
builder.Services.AddSerilog();
var app = builder.Build();
// This enables request logging
app.UseSerilogRequestLogging();
app.MapGet("/", () => "Hello World!");
app.Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "Application terminated unexpectedly");
}
finally
{
Log.CloseAndFlush();
}
The application code can keep using ILogger, but the actual logging will be performed by Serilog
Customizing logging
Services.AddSerilog
effectively replaces the Microcoft.Extensions.Logging internals with Serilog, so all enrichment, filtering, export configuration needs to be done through Serilog. Luckily, Serilog supports just about everything, which is why it’s one of the most popular logging libraries in .NET.
Serilog doesn’t have logging providers, so asking about a “custom logging provider” doesn’t explain anything. It could refer to any of the actual Serilog concepts: Sinks to export log events to various destinations, Enrichers to add extra information to log events or Filters to control what events get logged where. It could even refer to Loggers and sub-loggers
It’s quite easy for example to log errors to different files or to a database, using the appropriate sinks, in this case Serilog.Sinks.File
and Serilog.Sinks.MSSqlServer
. The following code is copied as-is from an actual application, logging to the console, an error file, a log file and a database table in JSON format :
// SQL logging configuration
var columnOpts = new ColumnOptions
{
AdditionalColumns = new Collection<SqlColumn>
{
new SqlColumn{ColumnName="ExecutionId",DataType=SqlDbType.UniqueIdentifier},
new SqlColumn{ColumnName="Application",DataType=SqlDbType.NVarChar,DataLength=200}
}
};
columnOpts.Store.Remove(StandardColumn.Properties);
columnOpts.Store.Add(StandardColumn.LogEvent);
columnOpts.LogEvent.DataLength = 2048;
Log.Logger = new LoggerConfiguration()
//Add some extra properties
.Enrich.WithProperty("ExecutionId", executionId)
.Enrich.WithProperty("Application", "dataloader")
// Log all to console
.WriteTo.Console()
// Log all to a rolling daily log file
.WriteTo.File("Logs/dataloader-log.txt", rollingInterval:RollingInterval.Day)
// Log errors only to an Errors file
.WriteTo.File("Logs/dataloader-errors.txt",LogEventLevel.Warning, rollingInterval:RollingInterval.Day)
// Log to the database
.WriteTo.MSSqlServer(
connectionString: cns,
sinkOptions: new MSSqlServerSinkOptions { TableName = "LogEvents", AutoCreateSqlTable = true },
columnOptions: columnOpts)
.CreateLogger();
If one wanted to include eg the user or tenant to the log event, one could add this as an additional property and map it to a column.
Filtering by source, level, tenant, or anything:
In the above example a level filter is specified through the restrictedToMinimumLevel
parameter. The same could be done using Filter.ByIncludingOnly
:
.WriteTo.File("Logs/bsploader-errors.txt", rollingInterval:RollingInterval.Day)
.Filter.ByIncludingOnly(e => e.Level >= LogEventLevel.Warning)
It’s also possible to filter by source. It’s also possible to apply different filters and sinks by using a sublogger :
.WriteTo.Logger(c=>c.Filter.ByIncludingOnly(Matching.FromSource<CsvExporter>())
.WriteTo.Console()
)
If the log evens are enriched eg with a user or tenant, that property can be used for filtering as well :
.Filter.ByIncludingOnly(Matching.WithProperty<string>("Tenant",
p => p =="TenantWithSpecialLogging")
.WriteTo.File("otherfile.txt",...)
6