как управлять стеком log4net, подобным NDC, с помощью методов async/await? (стек для каждой задачи?)

В обычном/синхронном/однопоточном консольном приложении NDC.Push прекрасно работает для управления «текущим элементом» (возможно, на нескольких уровнях вложенности, но в данном примере только на 1 уровне).

Например:

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");
    }
}

Это приведет к выводу журнала ожиданий, показывающему запись NDC «фрагмент X» сразу справа от «Программы» (шаблон по умолчанию для базового конфигуратора)

232 [9] ИНФО Часть программы 1 - Начало работы

5279 [9] ИНФО Часть программы 1 - Завершение работы

5279 [9] ИНФО Часть программы 2 - Начало работы

10292 [9] ИНФО Часть программы 2 - Завершение работы

10292 [9] ИНФО Часть программы 3 - Начало работы

15299 [9] ИНФО Часть программы 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 ' Наверное).

234 [10] INFO Часть программы 1 — Начало работы

265 [10] INFO Часть программы 2 — Начало работы

265 [10] INFO Часть программы 3 — Начало работы

5280 [7] Программа INFO (нулевая) - Отделочные работы

5280 [12] Программа INFO (нулевая) - Отделочные работы

5280 [12] Программа INFO (нулевая) - Отделочные работы

Вне добавления новый TaskContext (или аналогичный) для log4net, есть ли способ отслеживания такого рода активности?

На самом деле цель состоит в том, чтобы сделать это с помощью синтаксического сахара async/await — либо форсировать какое-то сходство потоков, либо делать такие вещи, как сохранение параллельного словаря вокруг ключевого слова задачи, вероятно, являются работоспособными вариантами, но я пытаюсь сохранить как максимально приближенный к синхронному варианту кода. :)

14
задан James Manning 20 March 2012 в 04:24
поделиться