Usando log4net con WebApi - Manteniendo la misma identificación de correlación en toda la instancia

Tengo una clase LoggingHandler que estoy usando como manejador de mensajes para registrar (usando log4net) la solicitud y las respuestas a mi WebApi

public class LoggingMessageHandler : DelegatingHandler
{
    public ILogManager LogManager { get; set; }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        var controllerType = GlobalConfiguration.Configuration.Services
            .GetHttpControllerSelector()
            .SelectController(request)
            .ControllerType;

        var requestInfo = string.Format("{0} {1}", request.Method, request.RequestUri);
        var correlationId = request.GetCorrelationId().ToString();

        var requestMessage = await request.Content.ReadAsStringAsync();

        await LogIncommingMessageAsync(controllerType, correlationId, requestInfo, requestMessage.Replace("\r\n", ""));

        var response = await base.SendAsync(request, cancellationToken);

        string responseMessage;

        if (response.IsSuccessStatusCode)
            responseMessage = await response.Content.ReadAsStringAsync();
        else
            responseMessage = response.ReasonPhrase;

        await OutgoingMessageAsync(controllerType, correlationId, requestInfo, responseMessage);

        return response;
    }

    protected async Task LogIncommingMessageAsync(Type type, string correlationId, string requestInfo, string body)
    {
        var logger = LogManager.GetLogger(type);
        await Task.Run(() => logger.Debug("{0} {1} - API Request: \r\n{2}", correlationId, requestInfo, body));
    }

    protected async Task OutgoingMessageAsync(Type type, string correlationId, string requestInfo, string body)
    {
        var logger = LogManager.GetLogger(type);
        await Task.Run(() => logger.Debug("{0} {1} - API Response: \r\n{2}", correlationId, requestInfo, body));
    }
}

ILogManager se inyecta a través de Autofac (consulte nuestro módulo Autofac más abajo)

Mi problema es con una identificación de correlación;

¿Cómo se puede pasar esto más abajo en nuestra aplicación?

Por ejemplo, en otro conjunto, que contiene parte de nuestra lógica comercial, queremos usar una llamada a LogManager.GetLogger para obtener un registro para otro tipo, pero como se originó en la solicitud, reutilice el mismo ID de correlación, por lo que ¿Podemos atar nuestros mensajes de registro juntos?

Para mayor claridad, nuestro módulo Autofac se ve así:

public class LoggingAutofacModule : Autofac.Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterType<LogManager>().As<ILogManager>().InstancePerApiRequest();
    }

    protected override void AttachToComponentRegistration(IComponentRegistry registry, IComponentRegistration registration)
    {
        registration.Preparing += OnComponentPreparing;

        var implementationType = registration.Activator.LimitType;
        var injectors = BuildInjectors(implementationType).ToArray();

        if (!injectors.Any())
            return;

        registration.Activated += (s, e) =>
        {
            foreach (var injector in injectors)
                injector(e.Context, e.Instance);
        };
    }

    private static void OnComponentPreparing(object sender, PreparingEventArgs e)
    {
        var t = e.Component.Activator.LimitType;
        e.Parameters =
            e.Parameters.Union(new[] { new ResolvedParameter((p, i) => p.ParameterType == typeof(ILogger), (p, i) => e.Context.Resolve<ILogManager>().GetLogger(t)) });
    }

    private static IEnumerable<Action<IComponentContext, object>> BuildInjectors(Type componentType)
    {
        var properties =
            componentType.GetProperties(BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance)
                         .Where(p => p.PropertyType == typeof(ILogger) && !p.GetIndexParameters().Any())
                         .Where(p =>
                         {
                             var accessors = p.GetAccessors(false);
                             return accessors.Length != -1 || accessors[0].ReturnType == typeof(void);
                         });

        foreach (var propertyInfo in properties)
        {
            var propInfo = propertyInfo;
            yield return (context, instance) => propInfo.SetValue(instance, context.Resolve<ILogManager>().GetLogger(componentType), null);
        }
    }
}

Respuestas a la pregunta(1)

Su respuesta a la pregunta