2015-05-04 41 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

修好了,謝謝! –