Em nosso software, usamos extensivamente o MDC para rastrear itens como IDs de sessão e nomes de usuário para solicitações da Web. Isso funciona bem durante a execução no encadeamento original. No entanto, há muitas coisas que precisam ser processadas em segundo plano. Para isso, usamos as classes java.concurrent.ThreadPoolExecutor
e java.util.Timer
juntamente com alguns serviços de execução assíncrona autolaminados. Todos esses serviços gerenciam seu próprio pool de encadeamentos.
Isto é o que o manual do Logback tem a dizer sobre o uso do MDC em um ambiente como esse:
Uma cópia do contexto de diagnóstico mapeado nem sempre pode ser herdada pelos threads de trabalho do thread inicial. Este é o caso em que java.util.concurrent.Executors é usado para gerenciamento de encadeamentos. Por exemplo, o método newCachedThreadPool cria um ThreadPoolExecutor e, como outro código de pool de encadeamentos, possui uma lógica intrincada de criação de encadeamentos.
Nesses casos, é recomendável que MDC.getCopyOfContextMap () seja chamado no encadeamento original (mestre) antes de enviar uma tarefa ao executor. Quando a tarefa é executada, como primeira ação, ela deve chamar MDC.setContextMapValues () para associar a cópia armazenada dos valores originais do MDC ao novo encadeamento gerenciado pelo Executor.
Isso seria bom, mas é muito fácil esquecer de adicionar essas chamadas e não há uma maneira fácil de reconhecer o problema até que seja tarde demais. O único sinal com o Log4j é que você obtém informações ausentes do MDC nos logs e, com o Logback, obtém informações obsoletas do MDC (uma vez que o encadeamento no pool do piso herda o MDC da primeira tarefa executada nele). Ambos são problemas sérios em um sistema de produção.
Não vejo nossa situação de forma alguma, mas não pude encontrar muito sobre esse problema na web. Aparentemente, isso não é algo contra o qual muitas pessoas se deparam, então deve haver uma maneira de evitá-lo. O que estamos fazendo de errado aqui?