ノーマル/同期/シングルスレッドコンソールアプリケーションでは、NDC.Pushは「現在のアイテム」(潜在的に複数のネストレベルで、この例では1レベル)を管理するために正常に動作します。例えばasync/awaitメソッドを使用してNDCのようなlog4netスタックを管理する方法は?
:
private static ILog s_logger = LogManager.GetLogger("Program");
static void Main(string[] args)
{
BasicConfigurator.Configure();
DoSomeWork("chunk 1");
DoSomeWork("chunk 2");
DoSomeWork("chunk 3");
}
static void DoSomeWork(string chunkName)
{
using (NDC.Push(chunkName))
{
s_logger.Info("Starting to do work");
Thread.Sleep(5000);
s_logger.Info("Finishing work");
}
}
これは期待するだけの「プログラム」(基本コンフィギュレータのデフォルトパターン)
の右にある「チャンクX」NDCエントリを示し、出力をログになります232 [9] INFOプログラムチャンク1 - 仕事を行うために開始し
5279 [9] INFOプログラムチャンク1 - 仕上げ作業
5279 [9] INFOプログラムチャンク2 - 仕事を行うために開始し
10292 [9] INFOプログラムチャンク2 - 仕上げ作業
10292 [9] INFOプログラムのチャンク3 - 仕事に
を行うために開始15299 [9] INFOプログラムチャンク3 - 仕上げ作業
しかし、私は「通常の」非同期メソッドを使用してそれを維持する方法を理解できません。このやろうとして例えば
、:
private static ILog s_logger = LogManager.GetLogger("Program");
static void Main(string[] args)
{
BasicConfigurator.Configure();
var task1 = DoSomeWork("chunk 1");
var task2 = DoSomeWork("chunk 2");
var task3 = DoSomeWork("chunk 3");
Task.WaitAll(task1, task2, task3);
}
static async Task DoSomeWork(string chunkName)
{
using (log4net.LogicalThreadContext.Stacks["NDC"].Push(chunkName))
//using (log4net.ThreadContext.Stacks["NDC"].Push(chunkName))
{
s_logger.Info("Starting to do work");
await Task.Delay(5000);
s_logger.Info("Finishing work");
}
}
はすべて「正常」開始、それらを表示しますが、タスクは別のスレッドで完了すると、スタックが失われているが(私はlog4net.LogicalThreadContextを望んでいました。私が推測するように、TPL-'aware 'とする)。
234 [10] INFOプログラムチャンク1 - 仕事をするために開始
265 [10] INFOプログラムチャンク2 - 仕事をするために開始
265 [10] INFOプログラムチャンク3 - 開始仕事を行うために
5280 [7] INFOプログラム(ヌル) - 仕上げ作業
5280 [12] INFOプログラム(ヌル) - 仕上げ作業
5280 [12] INFOプログラム(ヌル) - log4netの新しいTaskContext(など)を追加することの外で作業
を仕上げ、この種の活動を追跡する方法はありますか?
実際には、async/await構文の砂糖を使用するのが本当に目的です。スレッドアフィニティを強制するか、タスクごとに並行して辞書を保持するなどの作業を実行可能なオプションにする可能性が高いですが、できるだけ同期バージョンのコードに近いものを使用してください。 :)
私は最近、Microsoftが 'async'を扱うために.NET 4.5 RTWで' CallContext'を修正したことを発見しました。 log4netのNDCや 'Logical * Data'を使った他のソリューションは' async'メソッド(.NET 4.5のみ)で期待通りに動作します。 –
@StephenCleary素晴らしい!ありがとう! –
私はそれが論理スレッドのコンテキストから来ている問題であるかどうかはわかりません。親と子のスレッドが同じスタックを共有しているので、log4netの実装は間違っています。子が親スタックのクローンを受け取るようにして、親がスタックを変更しても子を混乱させないようにしてください... –