У нашому програмному забезпеченні ми широко використовуємо MDC для відстеження таких речей, як ідентифікатори сесії та імена користувачів для веб-запитів. Це добре працює під час запуску в оригінальній нитці. Однак є багато речей, які потрібно обробити у фоновому режимі. Для цього ми використовуємо класи java.concurrent.ThreadPoolExecutor
та java.util.Timer
класи разом із деякими службами виконання асинхронізації. Усі ці служби управляють власним пулом потоків.
Ось що говорить посібник Logback щодо використання MDC в таких умовах:
Копія відображеного діагностичного контексту не завжди може бути успадкована робочими потоками від ініціюючої нитки. Це той випадок, коли java.util.concurrent.Execitors використовується для управління потоками. Наприклад, метод newCchedThreadPool створює ThreadPoolExecutor і, як і інший код об'єднання ниток, має складну логіку створення ниток.
У таких випадках рекомендується MDC.getCopyOfContextMap () викликати в оригінальній (головній) темі перед тим, як подати завдання виконавцю. Коли завдання виконується, як його перша дія, воно повинно викликати MDC.setContextMapValues (), щоб пов’язати збережену копію оригінальних значень MDC з новим керованим потоком виконавця.
Це було б добре, але забути додавання цих дзвінків дуже просто, і не існує простого способу розпізнати проблему, поки не пізно. Єдиний знак з Log4j полягає в тому, що ви отримуєте відсутність інформації про MDC в журналах, а при Logback ви отримуєте застарілу інформацію про MDC (оскільки нитка в пулі протектора успадковує його MDC від першого завдання, яке було виконано на ньому). Обидва є серйозними проблемами у виробничій системі.
Я не бачу в нашій ситуації особливої особливості, але я не зміг знайти багато про цю проблему в Інтернеті. Мабуть, це не те, проти чого багато людей наштовхуються, тому повинен бути спосіб уникнути цього. Що ми робимо тут неправильно?