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