Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UseSerilog Infinite loop: ReadFrom.Services + KinesisFirehoseSink #48

Open
edmacdonald opened this issue Jun 18, 2021 · 3 comments
Open

Comments

@edmacdonald
Copy link

If you use the Two-stage initialization from here:
https://github.com/serilog/serilog-aspnetcore#two-stage-initialization

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .UseSerilog((context, services, configuration) => configuration
                    .ReadFrom.Configuration(context.Configuration)
                    .ReadFrom.Services(services)
                    .Enrich.FromLogContext()
                    .WriteTo.Console())
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });

and configure a KinesisFirehoseSink like so...

public void ConfigureServices(IServiceCollection services)
{
	services.AddAWSService<IAmazonKinesisFirehose>();
	services.AddSingleton(new KinesisFirehoseSinkOptions("LoggingStream"));
	services.AddTransient<ILogEventSink, KinesisFirehoseSink>();
}

You end up in an infinite loop because the IAmazonKinesisFirehose factory is looking for an ILoggerFactory.

@b-mcbride
Copy link

I am experiencing a similar issue when using .AddAzureClients from the Microsoft.Extensions.Azure NuGet package. Did you figure out how to work around this?

@edmacdonald
Copy link
Author

I just ditched the two-stage init. I came to the conclusion it's not that important to me and creates more issues than it solves. Initialization changes infrequently, errors outside development are rare, and when they do happen I make sure they fail spectacularly and if need be I can look at a file log on the host. I don't need them sent to kinesis.

@IvaskevychYuriy
Copy link

IvaskevychYuriy commented Dec 21, 2022

I believe I bump into the same issue - custom service that needs ILogger<T> dependency:

Sample

using Serilog;

Log.Logger = new LoggerConfiguration()
    .WriteTo.Console()
    .CreateBootstrapLogger();

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSingleton<FooService>();

builder.Host.UseSerilog((context, services, configuration) =>
{
    var service = services.GetRequiredService<FooService>();
});

builder.Build().Run();

public class FooService
{
    private readonly ILogger<FooService> _logger;

    public FooService(ILogger<FooService> logger)
        => _logger = logger;
}

Setup

NET 6, web application scaffolded by VS, the following packages added:

  • Serilog.AspNetCore 6.1.0

Issue

This gets stuck in an infinite loop like OP described. In me specific case thread dies after 252 iterations and the app never starts...

Shouldn't a bootstrap logger be used initially in such case - this would've solved the isssue I believe?

Addional info

The same exact thing happens when using pre-net6 configuration via GenericHost:

using Serilog;

Log.Logger = new LoggerConfiguration()
    .WriteTo.Console()
    .CreateBootstrapLogger();

Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>())
    .UseSerilog((context, services, configuration) =>
    {
        var service =   services.GetRequiredService<FooService>();
    })
    .Build()
    .Run();

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<FooService>();
    }

    public void Configure(IApplicationBuilder app) { }
}

Workaround (kinda)

Well, this is far far from ideal, but I've come up with builing GenericHost first, resolving services from there and then building another GenericHost this time with .UseSerilog() and use built ServiceProvider there.

Note: this solution is for pre-net6 Program.cs but I could imagine a similar approach could be taken with WebApplicationBuilder
Note: this causes a noticable performace hit on application startup, so use with caution

// ...

var serviceProvider = Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>())
    .Build()
    .Services;

Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>())
    .UseSerilog((context, _, configuration) =>
    {
        var service = serviceProvider.GetRequiredService<FooService>();
    })
    .Build()
    .Run();

// ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants