log4net LogicalThreadContext nicht funktioniert

Ich haben, was entweder ein Fehler in der log4net, oder ein Missverständnis meinerseits.

Ich versuche zu verwenden LogicalThreadContext zu assoziieren einige Daten mit einem Aufruf von Kontext und haben es weitergegeben, um alle log-Anweisungen, die von einem thread in diesem Zusammenhang. Das ist der angebliche Vorteil von LogicalThreadContext über ThreadContext.

War ich nicht in der Lage, um die Ausbreitung zu arbeiten, so habe ich zusammen ein einfaches unit-test, um zu sehen, ob es funktionieren würde, und es nicht. Hier ist es:

[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");
    }
}

Meine log4net Konfiguration sieht so aus:

<?xml version="1.0" encoding="utf-8" ?>

<configuration>
    <configSections>
        <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
    </configSections>

    <log4net>
        <appender name="FileAppender" type="log4net.Appender.FileAppender">
            <file value="log.txt" />
            <appendToFile value="true" />
            <layout type="log4net.Layout.PatternLayout">
                <conversionPattern value="[%thread]|[%property{foo}]|%message%newline"/>
            </layout>
        </appender>

        <root>
            <level value="DEBUG" />
            <appender-ref ref="FileAppender" />
        </root>
    </log4net>
</configuration>

Und meine Ausgabe sieht wie folgt aus:

[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

Wie Sie sehen können, werden die Daten Schiebe ich auf die LTC-stack ist nur die Protokollierung von Aussagen auf dem gleichen thread. Die log-Anweisung aus, indem Sie die hintergrund-thread fehlt der Kontext-Daten. Debugging durch den test konnte ich sehen, dass, ja, dass LogicalThreadContext.Stacks.Count ist null auf der hintergrund-thread.

Graben in der log4net-Quelle, ich fand es unter Verwendung der CallContext Klasse. Diese Klasse tut, was es auf dem zinn sagt - es erlaubt den Kontext für das aktuelle "call", um die gespeichert und abgerufen werden. Wie es das macht, auf einem niedrigen Niveau, ich habe keine Ahnung.

CallContext hat zwei Sätze von Methoden, mit denen die Kontext-Informationen, die gespeichert und kann abgerufen werden: GetData/SetData und LogicalGetData/LogicalSetData. Die Dokumentation ist sehr Licht auf details in Bezug auf den Unterschied zwischen diesen zwei Gruppen von Methoden, aber die Beispiele verwenden GetData/SetData. Und so funktioniert log4net ist LogicalThreadContext.

Ein kurzer test zeigte, dass GetData/SetData zeigt das gleiche problem - Daten nicht verteilt threads. Ich dachte, ich würde geben LogicalGetData/LogicalSetData ein go statt:

[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();
    }
}

Dieser test geht - Kontext-information erfolgreich weitergegeben threads bei der Verwendung von LogicalGetData/LogicalSetData.

Also meine Frage ist: hat log4net bekommen dies falsch? Oder ist es etwas, was ich bin fehlt?

UPDATE: ich auch versucht zu tun eine benutzerdefinierte build von log4net mit seinen LogicalThreadContextProperties Klasse geändert, wie pro meine Erkenntnisse vor. Ich wieder ran mein Erster test und es funktionierte. Dies eben scheint mir zu offensichtlich ein problem für ein Produkt von so vielen Menschen, muss ich also davon ausgehen, ich bin etwas fehlt.

Schreibe einen Kommentar