Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
536 views
in Technique[技术] by (71.8m points)

c# - Log4net LogicalThreadContext not working as expected

I've been trying to use Log4nets LogicalThreadContext to provide context to each of my log entries. My application uses async/await quite heavily, but from reading various articles the LogicalThreadContext should work properly with asynchronous code, from .NET 4.5 onwards. I'm using .NET 4.5.1 and log4net 2.0.3

I came across a great article by Stephen Cleary about logging and the .NET CallContext, and as a result I decided to take his code and adapt it to use log4net, in an attempt to see if there was something wrong in my code that may have been causing the issue.

Firstly, I ran Stephens code exactly as is and got the expected output like so

Main 1: <SomeWork>
Main 1 A: <MoreWork>
Main 2: <SomeWork>
Main 2 A: <MoreWork>
Main 1 A: </MoreWork>
Main 1 B: <MoreWork>
Main 2 A: </MoreWork>
Main 2 B: <MoreWork>
Main 2 B: </MoreWork>
Main 2: </SomeWork>
Main 1 B: </MoreWork>
Main 1: </SomeWork>

Next, I modified the code to use log4net rather than Stephens custom MyStack

internal class Program
{
    private static readonly ILog Log = LogManager.GetLogger(typeof(Program));
    private const string StackName = "test";

    private static void Main(string[] args)
    {
        XmlConfigurator.Configure();

        using (LogicalThreadContext.Stacks[StackName].Push("Main"))
        {
            Task.WhenAll(SomeWork("1"), SomeWork("2")).Wait();
        }

        Console.ReadKey();
    }

    private static async Task SomeWork(string stackName)
    {
        using (LogicalThreadContext.Stacks[StackName].Push(stackName))
        {
            Log.Info("<SomeWork>");
            await MoreWork("A");
            await MoreWork("B");
            Log.Info("</SomeWork>");
        }
    }

    private static async Task MoreWork(string stackName)
    {
        using (LogicalThreadContext.Stacks[StackName].Push(stackName))
        {
            Log.Info("<MoreWork>");
            await Task.Delay(10);
            Log.Info("</MoreWork>");
        }
    }
}

I expected to get a similar output as before, but instead this time I got the following

Main 1: <SomeWork>
Main 1 A: <MoreWork>
Main 1 A 2: <SomeWork>
Main 1 A 2 A: <MoreWork>
Main 1 A 2 A: </MoreWork>
Main 1 B: <MoreWork>
Main 1 B: </MoreWork>
Main 1 B B: <MoreWork>
Main 1 B B: </MoreWork>
Main 1 B: </MoreWork>
Main 1: </SomeWork>
Main 1: </SomeWork>

Notice the separate logical thread contexts start to overlap. This indicates to me the log4net isn't using the CallContext correctly but from everything I can find it looks like they've already fixed any issues around this.

Has anyone else encountered this or know why this might be happening?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Unfortunately, it looks like log4net still does not work with async logical stacks.

The log4net NuGet package 2.0.3 is log4net 1.2.13 (the current version as of today). There was a bug reported (LOG4NET-317) because at that time LogicalThreadContext used CallContext instead of LogicalCallContext.

The current version of LogicalThreadContext does use LogicalThreadContext, but the current version of ThreadContextStacks does not correctly use an immutable stack.

Interestingly, Andrew Arnott correctly pointed out in the original bug report that they had to use an immutable stack. In 2011.

Feel free to write up a minimal repro and report it as a log4net bug. The key scenario is using the stack within multiple tasks that are combined using Task.WhenAll.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...