我一直在尝试使用Log4nets LogicalThreadContext为每个日志条目提供上下文。我的应用程序非常重视async / await,但是从阅读各种文章开始,LogicalThreadContext应该可以与.NET 4.5以后的异步代码一起正常工作。我使用的是.NET 4.5.1和log4net 2.0.3
我遇到了Stephen Cleary关于日志记录和.NET CallContext的一个很棒的article,结果我决定采用他的代码并使其适应log4net,试图看看是否有什么东西我的代码中可能导致问题的错误。
首先,我完全按原样运行Stephens代码并获得预期的输出
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>
接下来,我修改了代码以使用log4net而不是Stephens自定义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>");
}
}
}
我希望得到与以前类似的输出,但这次我得到了以下
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>
请注意,单独的逻辑线程上下文开始重叠。这向我表明log4net并没有正确使用CallContext,但从我能找到的所有内容来看,他们已经解决了这个问题。
有没有其他人遇到过这个或知道为什么会这样?
答案 0 :(得分:3)
我刚刚在我们的一个项目中遇到过这个问题。这应该解决它:https://github.com/apache/log4net/pull/12。
代码基本上遵循@StephenCleary描述的shallow-copy-on-write
和immutable
规则,并且附带的测试用例可以承受Task.WhenAll
场景。