In unserer Software verwenden wir ausgiebig MDC um Dinge wie Sitzungs-IDs und Benutzernamen für Webanfragen zu verfolgen. Dies funktioniert gut, solange es im ursprünglichen Thread läuft.
Allerdings gibt es eine Menge Dinge, die im Hintergrund verarbeitet werden müssen. Dafür verwenden wir die java.concurrent.ThreadPoolExecutor
y java.util.Timer
Klassen zusammen mit einigen selbstgedrehten asynchron Ausführungsdienstleistungen. Alle diese Dienste verwalten ihren eigenen Thread-Pool.
Das ist es, was Handbuch von Logback über die Verwendung von MDC in einer solchen Umgebung zu sagen hat:
Eine Kopie des zugeordneten Diagnosekontextes kann nicht immer vom initiierenden Thread an Worker-Threads vererbt werden. Dies ist der Fall, wenn java.util.concurrent.Executors für das Thread-Management verwendet wird. Die Methode newCachedThreadPool beispielsweise erstellt einen ThreadPoolExecutor und verfügt wie anderer Thread-Pooling-Code über eine komplizierte Thread-Erstellungslogik.
In solchen Fällen wird empfohlen, dass MDC.getCopyOfContextMap() auf dem ursprünglichen (Master-)Thread aufgerufen wird, bevor eine Aufgabe an den Executor übergeben wird. Wenn die Aufgabe läuft, sollte sie als erste Aktion MDC.setContextMapValues() aufrufen, um die gespeicherte Kopie der ursprünglichen MDC-Werte mit dem neuen vom Executor verwalteten Thread zu verknüpfen.
Das wäre in Ordnung, aber man vergisst sehr leicht, diese Anrufe hinzuzufügen, und es gibt keine einfache Möglichkeit, das Problem zu erkennen, bevor es zu spät ist. Das einzige Anzeichen mit Log4j ist, dass Sie fehlende MDC-Informationen in den Protokollen erhalten, und mit Logback erhalten Sie veraltete MDC-Informationen (da der Thread im Tread-Pool sein MDC von der ersten Aufgabe erbt, die auf ihm ausgeführt wurde). Beides sind ernste Probleme in einem Produktionssystem.
Ich sehe unsere Situation in keiner Weise als etwas Besonderes an, aber ich konnte im Internet nicht viel über dieses Problem finden. Offenbar sind nicht viele Menschen mit diesem Problem konfrontiert, also muss es eine Möglichkeit geben, es zu vermeiden. Was machen wir hier falsch?