Serilog static logger is SilentLogger when there's an exception in MassTransit AddBus()

Viewed 1533

We're currently running an ASP.NET Core 3 web app that uses MassTransit. We've chosen Serilog for our logging library and it works great for the most part. We've picked up a small edge case where it cannot log certain errors. In our Program.cs (Code snippet below) we initialize the static logger while the service is still starting up and it logs to the console with no problems

If an exception is thrown in the ConfigureServices method in the Startup.cs the service is killed and the exception is printed to the console as expected. However, if an exception is thrown in the MassTransit AddBus() method nothing is logged. After a little bit of debugging, we saw that the static logger we set up in Program.cs is being replaced with a SilentLogger and we believe it could be something internal in MassTransit that's causing this

The MassTransit initialization code can be found below as well

public class Program
{
    public static void Main(string[] args)
    {
        Log.Logger = new LoggerConfiguration()
            .Enrich.FromLogContext()
            .WriteTo.Console()
            .CreateLogger();

        try
        {
            Log.Information("Starting up app");
            CreateHostBuilder(args).Build().Run();
        }
        catch (Exception e)
        {
            Log.Fatal(e, "Host terminated unexpectedly");
        }
        finally
        {
            Log.CloseAndFlush();
        }
    }
}
serviceCollection.AddMassTransit(configurator =>
{
    configurator.AddConsumers(consumerAssembly());

    var queueName = appSettings.QueueName;
    configurator.AddBus(provider =>
    {
        MessageDataDefaults.ExtraTimeToLive = TimeSpan.FromDays(1);
        MessageDataDefaults.Threshold = 2000;
        MessageDataDefaults.AlwaysWriteToRepository = false;

        return Bus.Factory.CreateUsingRabbitMq(cfg =>
            {
                var configHost = appSettings.RabbitMq.Host;
                var configUser = appSettings.RabbitMq.Username;
                var configPassword = appSettings.RabbitMq.Password;

                cfg.Host(new Uri(configHost), h =>
                {
                    h.Username(configUser);
                    h.Password(configPassword);
                });

                cfg.ReceiveEndpoint(queueName, ec => ec.ConfigureConsumers(provider));
            });
    });

    serviceCollection.AddSingleton<IHostedService, BusHostedService>();
});

Any exception thrown within the AddBus method will cause this issue. Here are the versions we're currently using:

  • MassTransit 7.1.4
  • MassTransit RabbitMq 7.1.4
  • Serilog 2.10.0

Perhaps someone here has come across this issue before? Any assistance will be appreciated

2 Answers

I discovered the same issue and I don't believe the issue has anything to do with the Mass Transit/RabbitMq code.

I am in a .Net core console application. What we have in common is the CreateHostBuilder(args).Build().Run(); code. When an uncaught exception occurs within Run() and the global catch (Exception e) catches it and the Log.Logger is now a SilentLogger

I put in a work around to reinitialized the Log.Logger in my catch statement. Unfortunately SilentLogger is not public so my check is based on the class name

    catch (Exception e) {
         if (Log.Logger.GetType().Name == "SilentLogger")
         {
             InitLogger();
         }
         Log.Fatal(e, "Host terminated unexpectedly");
    }

where InitLogger() just reinitializes the logger just like in your example:

Log.Logger = new LoggerConfiguration()
            .Enrich.FromLogContext()
            .WriteTo.Console()
            .CreateLogger();

This looks like a bug to me where Log.Logger is torn down too early for some reason.

First, I cleaned up your configuration as it has some mixed usage and that's generally frowned upon.

As to the logging issue, MassTransit doesn't know anything about SeriLog, but you can tell MassTransit about Serilog. Use the Serilog.Extensions.Logging package, and be sure to add ILoggerFactory/ILogger<> to your service collection using their configuration methods.

serviceCollection.AddMassTransit(configurator =>
{
    configurator.AddConsumers(consumerAssembly());

    configurator.UsingRabbitMq((context,cfg) =>
    {
        // these can actually go anywhere before the bus is created
        MessageDataDefaults.ExtraTimeToLive = TimeSpan.FromDays(1);
        MessageDataDefaults.Threshold = 2000;
        MessageDataDefaults.AlwaysWriteToRepository = false;

        var configHost = appSettings.RabbitMq.Host;
        var configUser = appSettings.RabbitMq.Username;
        var configPassword = appSettings.RabbitMq.Password;

        cfg.Host(new Uri(configHost), h =>
        {
            h.Username(configUser);
            h.Password(configPassword);
        });

        var queueName = appSettings.QueueName;
        cfg.ReceiveEndpoint(queueName, ec => ec.ConfigureConsumers(context));
    });
});
serviceCollection.AddSingleton<IHostedService, BusHostedService>();

Possible syntax to add Serilog to the container:

services.TryAddSingleton<ILoggerFactory>(_ => new SerilogLoggerFactory());
services.TryAddSingleton(typeof(ILogger<>), typeof(Logger<>));
Related