En una aplicación de consola normal/síncrona/de un solo subproceso, NDC.Push funciona bien para administrar el 'elemento actual' (potencialmente en múltiples niveles de anidamiento, pero solo 1 nivel para este ejemplo).cómo administrar una pila log4net tipo NDC con métodos async/await? (¿por pila de tareas?)
Por ejemplo:
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");
}
}
Esto dará lugar a la salida de esperar que ingrese, mostrando una entrada de 'trozo X' NDC justo a la derecha del 'Programa' (el patrón predeterminado para el configurador básico)
232 [9] Programa INFO trozo 1 - Empezando a hacer el trabajo
5279 [9] trozo Programa INFO 1 - terminación
5279 [9] trozo Programa INFO 2 - Comenzando a hacer el trabajo
10292 [9] Programa INFO trozo 2 - terminación
10292 [9] Programa INFO trozo 3 - Comenzando a hacer el trabajo
15299 [9] INFO Programa fragmento 3 - Trabajo de acabado
Sin embargo, no puedo encontrar la manera de mantener eso utilizando los métodos asíncronos 'normales'.
Por ejemplo, tratando de hacer esto:
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");
}
}
les muestra toda la partida "normalmente", pero cuando se completa la tarea en un subproceso diferente, se pierde la pila (que estaba esperando la log4net.LogicalThreadContext gustaría ser TPL-'consciente ', supongo).
234 [10] Programa INFO trozo 1 - Empezando a hacer el trabajo
265 [10] Programa INFO trozo 2 - Comenzando a hacer el trabajo
265 [10] Programa INFO trozo 3 - Comenzando para hacer el trabajo
5280 [7] Programa INFO (null) - trabajos de acabado
5280 [12] Programa INFO (null) - terminación
5280 [12] Programa INFO (null) - terminación
Fuera de añadir un nuevo TaskContext (o similar) a Log4net, ¿hay una forma de seguimiento de este tipo de actividad?
El objetivo es realmente hacerlo con la sintaxis de asincronización/espera, ya sea forzando algún tipo de afinidad de hilos o haciendo cosas como mantener un diccionario simultáneo en función de la tarea, probablemente sean opciones viables, pero estoy tratando de mantener tan cerca de la versión síncrona del código como sea posible. :)
FYI, recientemente descubrí que Microsoft arregló 'CallContext' en .NET 4.5 RTW para que funcione con' async'. Entonces, el NDC de log4net y otras soluciones que usan 'Logical * Data' funcionarán como se espera con los métodos' async' (solo en .NET 4.5). –
@StephenCleary ¡increíble! ¡Gracias! –
No estoy seguro de que sea un problema proveniente del contexto del hilo lógico. La implementación de log4net me parece incorrecta porque los hilos padre e hijo comparten la misma pila. El niño debe recibir un clon de la pila padre para que si el padre modifica la pila no perturbe al niño ... –