log4net LogicalThreadContext не работает

У меня есть то, что является либо ошибкой в ​​log4net, либо недопониманием с моей стороны.

Я Я пытаюсь использовать LogicalThreadContext , чтобы связать некоторые данные с контекстом вызова и распространить их на любые операторы журнала, сделанные любым потоком в этом контексте. Это предполагаемое преимущество LogicalThreadContext над ThreadContext .

Мне не удалось заставить распространение работать, поэтому я собрал простой модульный тест, чтобы проверить, будет ли оно работает, а это не так. Вот он:

[Fact]
public void log4net_logical_thread_context_test()
{
    XmlConfigurator.Configure();
    var log = LogManager.GetLogger(GetType());
    var waitHandle = new ManualResetEvent(false);

    using (LogicalThreadContext.Stacks["foo"].Push("Some contextual info"))
    {
        log.Debug("START");

        ThreadPool.QueueUserWorkItem(delegate
        {
            log.Debug("A DIFFERENT THREAD");
            waitHandle.Set();
        });

        waitHandle.WaitOne();
        log.Debug("STOP");
    }
}

Моя конфигурация log4net выглядит так:




    
        

И мои выходные данные выглядят так:

[xUnit.net STA Test Execution Thread]|[Some contextual info]|START
[32]|[(null)]|A DIFFERENT THREAD
[xUnit.net STA Test Execution Thread]|[Some contextual info]|STOP

Как вы можете видеть, данные, которые я помещаю в стек LTC, присутствуют только в сделанных операторах регистрации в том же потоке . В заявлении журнала, сделанном фоновым потоком, отсутствуют контекстные данные. Выполняя отладку теста, я действительно увидел, что LogicalThreadContext.Stacks.Count равен нулю в фоновом потоке.

Покопавшись в источнике log4net, я обнаружил, что он использует CallContext класс. Этот класс делает то, что написано на банке - он позволяет сохранять и извлекать контекст для текущего «вызова». Я понятия не имею, как это делается на низком уровне.

CallContext имеет два набора методов, с помощью которых можно сохранять и получать контекстную информацию: GetData / SetData ] и LogicalGetData / LogicalSetData . В документации очень мало деталей относительно разницы между этими двумя наборами методов, но в примерах используется GetData / SetData . Как и LogicalThreadContext в log4net.

Быстрый тест показал, что GetData / SetData демонстрирует ту же проблему - данные не передаются по потокам. Я подумал, что вместо этого дам LogicalGetData / LogicalSetData :

[Fact]
public void call_context_test()
{
    XmlConfigurator.Configure();
    var log = LogManager.GetLogger(GetType());

    var count = 5;
    var waitHandles = new ManualResetEvent[count];

    for (var i = 0; i < count; ++i)
    {
        waitHandles[i] = new ManualResetEvent(false);
        var localI = i;

        // on a bg thread, set some call context data
        ThreadPool.QueueUserWorkItem(delegate
        {
            CallContext.LogicalSetData("name", "value " + localI);
            log.DebugFormat("Set call context data to '{0}'", CallContext.LogicalGetData("name"));
            var localWaitHandle = new ManualResetEvent(false);

            // then on another bg thread, make sure the logical call context value is correct with respect to the "owning" bg thread
            ThreadPool.QueueUserWorkItem(delegate
            {
                var value = CallContext.LogicalGetData("name");
                log.DebugFormat("Retrieved call context data '{0}'", value);
                Assert.Equal("value " + localI, value);
                localWaitHandle.Set();
            });

            localWaitHandle.WaitOne();
            waitHandles[localI].Set();
        });
    }

    foreach (var waitHandle in waitHandles)
    {
        waitHandle.WaitOne();
    }
}

Этот тест проходит - контекстная информация успешно распространяется по потокам при использовании LogicalGetData / LogicalSetData .

Итак, мой вопрос: ошибся ли в log4net? Или мне чего-то не хватает?

ОБНОВЛЕНИЕ: Я также пробовал создать собственную сборку log4net с его классом LogicalThreadContextProperties , измененным согласно моим выводам выше. Я повторно провел свой первоначальный тест, и он сработал. Это просто кажется мне слишком очевидной проблемой для продукта, которым пользуется так много людей, поэтому я вынужден предположить, что я чего-то упускаю.

9
задан Kent Boogaart 3 August 2011 в 22:41
поделиться