В нашем программном обеспечении мы широко используем 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 от первой задачи, которая была на нем запущена). Оба являются серьезными проблемами в производственной системе.
Я не считаю нашу ситуацию особенной в любом случае, но я не мог найти много об этой проблеме в Интернете. Очевидно, что это не то, с чем сталкиваются многие люди, поэтому должен быть способ избежать этого. Что мы здесь делаем не так?