In a normal/synchronous/single-threaded console app, NDC.Push works fine for managing the 'current item' (potentially at multiple levels of nesting, but just 1 level for this example).
For example:
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");
}
}
This will result in the expect log output, showing a 'chunk X' NDC entry just to the right of 'Program' (the default pattern for the basic configurator)
232 [9] INFO Program chunk 1 - Starting to do work
5279 [9] INFO Program chunk 1 - Finishing work
5279 [9] INFO Program chunk 2 - Starting to do work
10292 [9] INFO Program chunk 2 - Finishing work
10292 [9] INFO Program chunk 3 - Starting to do work
15299 [9] INFO Program chunk 3 - Finishing work
However, I can't figure out how to maintain that using 'normal' async methods.
For instance, trying to do this:
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");
}
}
Shows them all starting "normally", but when the task completes on a different thread, the stack is lost (I was hoping the log4net.LogicalThreadContext would be TPL-'aware' I guess).
234 [10] INFO Program chunk 1 - Starting to do work
265 [10] INFO Program chunk 2 - Starting to do work
265 [10] INFO Program chunk 3 - Starting to do work
5280 [7] INFO Program (null) - Finishing work
5280 [12] INFO Program (null) - Finishing work
5280 [12] INFO Program (null) - Finishing work
Outside of adding a new TaskContext (or the like) to log4net, is there a way of tracking this kind of activity?
The goal is really to do so with the async/await syntax sugar - either forcing some kind of thread affinity or doing things like keeping a concurrent dictionary around keyed by task are likely workable options, but I'm trying to keep as close to the synchronous version of the code as possible. :)
CallContext
in .NET 4.5 RTW to work withasync
. So log4net's NDC and other solutions usingLogical*Data
will work as expected withasync
methods (on .NET 4.5 only). – Stephen Cleary