Serilog not injecting `Microsoft.Extensions.Logging.ILogger<T>`

74 Views Asked by At

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.

1

There are 1 best solutions below

0
On

The Repository class, used for testing was wired up in DI using a factory method, and that factory method was passing a hard-coded null logger into the constructor.

Tip: Check your own class' DI config.