0

In a .NET web application, I'm using Autofac + Serilog + Microsoft.Extensions.Logging. I would like to use a custom enricher to log the current user ID from a proprietary connection object, like this:

    public class ConnectionUserIdEnricher : ILogEventEnricher
    {
        private readonly FooConnection _fooConnection;

        public InnovatorUserIdEnricher(FooConnection _fooConnection)
        {
            _fooConnection = fooConnection;
        }

        public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
        {
            LogEventProperty userIdProperty = propertyFactory.CreateProperty("FooConnectionUserId", _fooConnection.UserId);
            logEvent.AddPropertyIfAbsent(userIdProperty);
        }
    }

The connection would be correctly injected using Autofac. I have found this question and this article, which both explain exactly what I'd like to do. However, my container configuration looks different, namely like this:

public class FooContainer
{
    public static Lazy<IContainer> Container = new Lazy<IContainer>(BuildContainer, LazyThreadSafetyMode.ExecutionAndPublication);

    public static LoggerFactory CreateLoggerFactory(IOptions<SeqLogOptions> seqLogOptions)
    {
        LoggerConfiguration loggerConfigurator = new LoggerConfiguration().MinimumLevel.Debug()
                                                                          .Enrich.FromLogContext()
                                                                          .Enrich.WithMachineName()
                                                                          .Enrich.WithThreadId()
                                                                          .Enrich.WithProcessId()

            .WriteTo.Seq(seqLogOptions.Value.SeqUrl, apiKey: seqLogOptions.Value.SeqApiKey);

        Log.Logger = loggerConfigurator.CreateLogger();
        var loggerFactory = new LoggerFactory(new[] {new SerilogLoggerProvider(Log.Logger)});
        return loggerFactory;
    }
    
    public static IContainer BuildContainer(ILoggerFactory loggerFactory)
    {
        var containerBuilder = new ContainerBuilder();
        containerBuilder.RegisterAssemblyTypes(typeof(FooRepository<>).Assembly);
        // [...]
        containerBuilder.RegisterInstance(loggerFactory).As<ILoggerFactory>();
        containerBuilder.RegisterGeneric(typeof(Logger<>)).As(typeof(ILogger<>));
    
        IContainer container = containerBuilder.Build();
        return container;
    }
}

So since I don't use the UseSerilog method, I don't have the services parameter available. Is there a way to make this work anyway, without changing the whole container setup? Ideally, this would also work if the FooConnection service/component can't be resolved (either not enriching the user ID or using a NULL value).

Edit: The answer to this question about using a middleware seems very useful, but we are not using ASP.NET Core. We use the container directly from a classical .NET code (could be either a .NET web application or a console application) like this:

    FooConnection fooConnection = ThirdPartyLibrary.GetCurrentConnection();

    using (ILifetimeScope lifetimeScope = FooContainer.Container.Value.BeginLifetimeScope(x => x.RegisterInstance(fooConnection)))
    {
        var component = lifetimeScope.Resolve<ISomeService>>();
        // ...
    }

Maybe it would make more sense to hook into the registration of the FooConnection, update the LogContext whenever a new FooConnection component is registered? I would like to keep the container, uhm, contained, so that code that uses the container does not have to worry about setting up the log context.

TravelingFox
  • 484
  • 5
  • 18
  • 1
    Does this answer your question? [How do I get a serilog enricher to work with dependency injection while keeping it on startup?](https://stackoverflow.com/questions/57460579/how-do-i-get-a-serilog-enricher-to-work-with-dependency-injection-while-keeping) – C. Augusto Proiete Jan 29 '21 at 23:46
  • 1
    Use a middleware so that you can leverage ASP .NET's dependency injection to get your `FooConnection`, and push properties to the LogContext. Example here: https://stackoverflow.com/a/57488163 – C. Augusto Proiete Jan 29 '21 at 23:47
  • @C.AugustoProiete Thank you, that was really useful. Unfortunately, I don't think it can be used like that for our scenario. I have updated the question, if you care to have another look. Thank you! – TravelingFox Jan 31 '21 at 22:07

0 Answers0