2015-05-04 39 views
1

我试图通过将日志消息分组在一起来解开日志。理想情况下,我会在每封邮件中追加一些标识符,表明它是实现某项工作的一组命令的一部分。跨异步调用持续线程的上下文

如果这是一个单线程应用程序,线程的ID将是候选人。但是,此解决方案大量使用async Task,这就排除了它的使用。是否有可能得到像下面这样的工作,其中Main()的每次执行总是会打印出相同的线程ID?

static async void Main() 
{ 
    var t = Task.Run(async() => await MyAsyncMethod()); 
    await t; 
} 

private static async Task MyAsyncMethod() 
{ 
    Debug.WriteLine("Log message: {0}", Thread.CurrentThread.ManagedThreadId); 

    await Task.Delay(1000); 

    Debug.WriteLine("Log message: {0}", Thread.CurrentThread.ManagedThreadId); 

    await Task.Delay(1000); 

    Debug.WriteLine("Log message: {0}", Thread.CurrentThread.ManagedThreadId); 
} 
+1

在方法开始时生成一个id并全部使用它?或者写一些与异步方法正在处理的相关的id。例如,如果它处理一些与客户相关的工作,它将是客户ID。 –

+0

@SriramSakthivel好的建议,但我试图摆脱不重构一个相当大的解决方案。理想情况下,我分组的属性与业务无关,因为我可以同时处理同一实体的多个工作角色,因此日志消息正在交织,这导致了我的困惑。 –

+0

在这种情况下,只需增量计数器就可以正常工作。 –

回答

4

IMO最好的方法是@SriramSakthivel建议:只需生成一个id并传递它。如果您有“消息”类型,则可以将其添加到该类型。

但是,如果这会导致代码更改过多,则可以隐式传递它。我有一个blog post with the gory details;总的想法是,你的数据存储为逻辑呼叫上下文的一部分:

public static class MyContext 
{ 
    private static readonly string name = Guid.NewGuid().ToString("N"); 

    private sealed class Wrapper : MarshalByRefObject 
    { 
    public Guid Value { get; set; } 
    } 

    public static Guid CurrentContext 
    { 
    get 
    { 
     var ret = CallContext.LogicalGetData(name) as Wrapper; 
     return ret == null ? Guid.Empty : ret.Value; 
    } 

    set 
    { 
     CallContext.LogicalSetData(name, new Wrapper { Value = value }); 
    } 
    } 
} 

然后你可以使用它从你的代码,例如:

private static async Task MyAsyncMethod() 
{ 
    MyContext.CurrentContext = Guid.NewGuid(); 

    Debug.WriteLine("Log message: {0}", MyContext.CurrentContext); 

    await Task.Delay(1000); 

    Debug.WriteLine("Log message: {0}", MyContext.CurrentContext); 

    await Task.Delay(1000); 

    Debug.WriteLine("Log message: {0}", MyContext.CurrentContext); 
} 

注意,这种做法提出了两个关键假设:

  1. 您的代码运行于.NET 4.5或更高版本。
  2. 被存储的数据是不可变的(在这种情况下是这样,因为Guid是不可变的)。

在.NET 4.6中看起来像这样的will be builtin

+0

看起来不错! 'CurrentContext'应该是公开的,不是吗? –

+0

修好了,谢谢! –