Nel nostro software utilizziamo ampiamente MDC per tracciare cose come ID di sessione e nomi utente per richieste web. Funziona bene durante l'esecuzione nel thread originale. Tuttavia, ci sono molte cose che devono essere elaborate in background. Per questo usiamo le classi java.concurrent.ThreadPoolExecutor
e java.util.Timer
insieme ad alcuni servizi di esecuzione asincrona self-roll. Tutti questi servizi gestiscono il proprio pool di thread.
Questo è ciò che il manuale di Logback ha da dire sull'uso di MDC in tale ambiente:
Una copia del contesto diagnostico mappato non può sempre essere ereditata dai thread di lavoro dal thread di avvio. Questo è il caso in cui java.util.concurrent.Executors viene utilizzato per la gestione dei thread. Ad esempio, il metodo newCachedThreadPool crea un ThreadPoolExecutor e, come altri codici di pool di thread, ha una complessa logica di creazione dei thread.
In tali casi, si consiglia di richiamare MDC.getCopyOfContextMap () sul thread originale (principale) prima di inviare un'attività all'esecutore. Quando l'attività viene eseguita, come prima azione, deve richiamare MDC.setContextMapValues () per associare la copia memorizzata dei valori MDC originali al nuovo thread gestito di Executor.
Questo andrebbe bene, ma è molto facile dimenticare di aggiungere quelle chiamate e non esiste un modo semplice per riconoscere il problema fino a quando non è troppo tardi. L'unico segno con Log4j è che si ottengono informazioni MDC mancanti nei registri e con Logback si ottengono informazioni MDC non aggiornate (poiché il thread nel pool di tread eredita il proprio MDC dalla prima attività eseguita su di esso). Entrambi sono seri problemi in un sistema di produzione.
Non vedo la nostra situazione in alcun modo speciale, ma non ho trovato molto su questo problema sul web. Apparentemente, questo non è qualcosa contro cui molte persone si scontrano, quindi ci deve essere un modo per evitarlo. Cosa stiamo facendo di sbagliato qui?