在.NETCore中,我想支持这样的方案:在某些情况下包装代码:

using(new LoggingContext("Method 1"))
{

}

这些上下文也可以相互嵌入
using(new LoggingContext("Method 1"))
{
   Method2();
}

void Method2()
{
   using(new LoggingContext("Method 2"))
   {
      logger.Log("ERROR")
   }
}

调用logger.Log("ERROR")后,我希望它记录传递的消息以及这些堆叠的上下文标识符,例如:



在单线程方案中,这非常容易-它需要全局访问的上下文堆栈。在.NET Core中,例如,一些public static AsyncLocal<Stack<LoggingContext>>

但是我不知道在这样的多线程方案中实现类似行为的最佳方法是什么:
using(LoggingContext("Method 1"))
{
    Task.WaitAll(
       new Task(() => Method("Method A", "A"),
       new Task(() => Method("Method B", "B")))
}

void Method(string contextName, string message)
{
   using(new LoggingContext(contextName)
   {
       _logger.Log(message)
   }
}

所需的日志如下所示:



当然,一项任务可以在另一项任务中开始,情况变得更加复杂。

需要注意的另一件事:
由于某些遗留原因,无法在我创建LoggingContext的任何地方传递依赖关系,它必须是一些静态解决方案。

我唯一想到的想法是,每当我创建一个新Task并将当前堆栈复制到新的ExecutionContext.SupressFlow对象时就使用AsyncLocal,但这是一个好的解决方案吗?对执行上下文造成困惑对我来说似乎有点不安全。

最佳答案

一种选择是在创建新任务时手动克隆或扩展父级日志上下文:

using(var parentContext = LoggingContext("Method 1"))
{
    Task.WaitAll(
       new Task(() => {
          using(parentContext.Clone())
          {
              Method("Method A", "A");
          }
       }),
       ...
}

它不是很漂亮,但是您可以编写一些辅助方法来处理困惑的位。例如:
using(var parentContext = LoggingContext("Method 1"))
{
    Task.WaitAll(
       parentContext.StartTask(() => Method("Method A", "A")),
       parentContext.StartTask(() => Method("Method B", "B")));
}

09-04 14:47