W normalnej/synchronicznej/jednowątkowej aplikacji konsoli NDC.Push działa dobrze w celu zarządzania "bieżącym elementem" (potencjalnie na wielu poziomach zagnieżdżania, ale tylko 1 poziom w tym przykładzie).jak zarządzać stosem log4net podobnym do NDC metodami async/await? (stos za zadanie?)
Na przykład:
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");
}
}
Spowoduje to Expect zalogować wyjścia, pokazując „klocek x” wejście NDC tuż na prawo od „Program” (domyślny wzorzec dla podstawowego konfiguratorze)
232 [9] kawałek INFO Program 1 - Rozpoczęcie działają
5279 [9] kawałek INFO Program 1 - wykończeniowe
5279 [9] INFO Program fragment 2 - Rozpoczęcie działają
10292 [9] INFO Program fragment 2 - wykończeniowe
10292 [9] INFO Program fragment 3 - Rozpoczęcie działają
15299 [9] INFO Program chunk 3 - Prace wykończeniowe
Nie mogę jednak dowiedzieć się, jak zachować to przy użyciu "normalnych" metod asynchronicznych.
Na przykład, starając się to zrobić:
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");
}
}
pokazuje im wszystko począwszy od „normalnie”, ale po zakończeniu wykonywania zadania na inny wątek, stos jest tracona (Miałam nadzieję, że się log4net.LogicalThreadContext być może TPL-'aware ").
234 [10] INFO Program fragment 1 - Rozpoczęcie działają
265 [10] INFO Program fragment 2 - Rozpoczęcie działają
265 [10] INFO Program fragment 3 - Uruchamianie do pracy
5280 [7] Informacje o programie (zerowy) - prace wykończeniowe
5280 [12] Informacje o programie (zerowy) - wykończeniowe
5280 [12] Informacje o programie (null) - wykończeniowe
Poza dodanie nowego TaskContext (lub podobne) do log4net, czy istnieje sposób śledzenia tego rodzaju działalności?
Chodzi o to, aby tak się stało z cukrem składającym się z asynów/czekania - albo wymuszenie jakiegoś rodzaju powinowactwa nitki, czy robienie takich rzeczy, jak utrzymywanie współbieżnego słownika po kluczowanym przez zadanie, są prawdopodobnie możliwymi opcjami, ale staram się zachować tak blisko synchronicznej wersji kodu, jak to możliwe. :)
FYI, Niedawno odkryłem, że Microsoft naprawił 'CallContext' w .NET 4.5 RTW, aby pracować z' async'. Tak więc NDC log4net i inne rozwiązania używające 'Logical * Data' będą działały zgodnie z oczekiwaniami w przypadku metod' async' (tylko w .NET 4.5). –
@StephenCleary super! Dzięki! –
Nie jestem pewien, czy to problem pochodzący z kontekstu wątku logicznego. Implementacja log4net wygląda na niepoprawną, ponieważ wątek nadrzędny i podrzędny mają ten sam stos. Dziecko powinno otrzymać klona stosu nadrzędnego, więc jeśli rodzic modyfikuje stos, nie zaburza to ... –