Adding Serilog to my ASP.NET Core (.NET 8) project, following the instructions in the serilog-aspnetcore repo. Everything appears to be in order;
however if I try to inject a Microsoft.Extensions.Logging.ILogger<T>
into any class in my application, it only ever recieves a null
object. Do I need an extra step to inject those? Or am I just doing something wrong?
Main application code:
public static async Task<int> Main(string[] args)
{
var tempLogger = InitializeTemporaryLogger();
try
{
var app = CreateBuilder(args, tempLogger).Build();
ConfigureHttpPipeline(app);
await app.RunAsync().ConfigureAwait(false);
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, "Application terminated unexpectedly");
return 1;
}
finally
{
await Log.CloseAndFlushAsync().ConfigureAwait(false);
}
}
Temporary logger:
using MEL = Microsoft.Extensions.Logging;
private static MEL.ILogger InitializeTemporaryLogger()
{
SelfLog.Enable(msg => Debug.WriteLine(msg));
SelfLog.Enable(Console.Error);
Log.Logger = new LoggerConfiguration()
.WriteTo.Debug(formatProvider: CultureInfo.InvariantCulture)
.WriteTo.Console(formatProvider: CultureInfo.InvariantCulture)
.MinimumLevel.Information()
// Can't use this for now, due to bug during parallel xUnit integration tests
// https://github.com/serilog/serilog-aspnetcore/issues/289
//.CreateBootstrapLogger();
.CreateLogger();
// Wrap the temporary Serilog logger in a Microsoft.Extensions.Logging wrapper
using var factory = new SerilogLoggerFactory(Log.Logger);
return factory.CreateLogger<Program>();
}
Application builder code:
using MEL = Microsoft.Extensions.Logging;
private static WebApplicationBuilder CreateBuilder(string[] args, MEL.ILogger? logger = null)
{
var builder = WebApplication.CreateBuilder(args);
// ...
builder.Host.UseSerilog((context, provider, config) =>
{
config
// These features are required, and thus hard-coded
.Enrich.FromLogContext()
.WriteTo.Debug(formatProvider: CultureInfo.InvariantCulture)
.WriteTo.Console(formatProvider: CultureInfo.InvariantCulture)
// All other settings come from config
.ReadFrom.Configuration(builder.Configuration);
});
// ...
return builder;
}
When running the application, the bootstrapping code writes to Serilog (console) successfully. So does the HTTP request middleware. So I know at least that much is wired up correctly.
Looking in the DI registrations, I can see a couple initial entries by Microsoft; then towards the end I see the Serilog entries. But nothing from Serilog about Microsoft.Extensions.Logging.ILogger<T>
:
DI Index |
Service Type | Implementation |
---|---|---|
14 | Microsoft.Extensions.Logging.ILoggerFactory |
Microsoft.Extensions.Logging.LoggerFactory |
15 | Microsoft.Extensions.Logging.ILogger'1 |
Microsoft.Extensions.Logging.Logger'1 |
... | ... | ... |
210 | Serilog.SerilogServiceCollectionExtensions+RegisteredLogger |
<factory> |
211 | Serilog.ILogger |
<factory> |
212 | Microsoft.Extensions.Logging.ILoggerFactory |
<factory> |
213 | Serilog.Extensions.Hosting.DiagnosticContext |
<factory> |
214 | Serilog.IDiagnosticContext |
<factory> |
When I retrieve an ILoggerFactory
from DI, I do get the SerilogLoggerFactory
back as expected.
The
Repository
class, used for testing was wired up in DI using a factory method, and that factory method was passing a hard-codednull
logger into the constructor.Tip: Check your own class' DI config.