В нашем программном обеспечении мы широко используем MDC для отслеживания таких вещей, как идентификаторы сеансов и имена пользователей для веб-запросов. Это отлично работает при работе в исходном потоке. Однако есть много вещей, которые нужно обрабатывать в фоновом режиме. Для этого мы используем классы java.concurrent.ThreadPoolExecutor
и java.util.Timer
вместе с некоторыми службами самовращающегося асинхронного выполнения. Все эти службы управляют своим собственным пулом потоков.
Это то, что руководство Logback говорит об использовании MDC в такой среде:
Копия отображенного диагностического контекста не всегда может быть унаследована рабочие потоки из инициирующего потока. Это тот случай, когда java.util.concurrent.Executors используется для управления потоками. Например, Метод newCachedThreadPool создает ThreadPoolExecutor и, как и другой код объединения потоков, имеет сложную логику создания потоков.
В таких случаях рекомендуется, чтобы MDC.getCopyOfContextMap () вызывалась в исходном (главном) потоке перед отправкой задачи в исполнитель. Когда задача запускается в качестве своего первого действия, она должна вызвать MDC.setContextMapValues (), чтобы связать сохраненную копию исходных значений MDC с новым управляемым потоком Executor.
Это было бы хорошо, но это очень легко забудьте добавить эти вызовы, и нет простого способа распознать проблему, пока не станет слишком поздно. Единственным признаком Log4j является то, что в журналах отсутствует информация о MDC, а с помощью Logback вы получаете устаревшую информацию о MDC (поскольку поток в пуле протектора наследует свой MDC от первой задачи, которая была запущена на нем). Оба являются серьезными проблемами в производственной системе.
Я не вижу в нашей ситуации ничего особенного, но я не смог найти много информации об этой проблеме в Интернете. Очевидно, это не то, с чем сталкиваются многие люди, поэтому должен быть способ избежать этого. Что мы здесь делаем не так?