8
スレッドプールでMDCを使用する方法
私たちのソフトウェアでは、MDCを幅広く使用して、セッションIDやWebリクエストのユーザー名などを追跡しています。これは、元のスレッドで実行している間は正常に機能します。ただし、バックグラウンドで処理する必要があるものはたくさんあります。そのために、いくつかの自己ロール非同期実行サービスとともにjava.concurrent.ThreadPoolExecutorおよびjava.util.Timerクラスを使用します。これらのサービスはすべて、独自のスレッドプールを管理します。 このような環境でのMDCの使用について、Logbackのマニュアルでは次のように述べています。 マップされた診断コンテキストのコピーは、開始スレッドから常にワーカースレッドに継承されるとは限りません。これは、java.util.concurrent.Executorsがスレッド管理に使用される場合です。たとえば、newCachedThreadPoolメソッドはThreadPoolExecutorを作成し、他のスレッドプールコードと同様に、複雑なスレッド作成ロジックを備えています。 このような場合、タスクをエグゼキューターに送信する前に、元の(マスター)スレッドでMDC.getCopyOfContextMap()を呼び出すことをお勧めします。タスクが実行されると、最初のアクションとして、MDC.setContextMapValues()を呼び出して、元のMDC値の格納されたコピーを新しいExecutorマネージスレッドに関連付けます。 これは問題ありませんが、これらの呼び出しを追加することを忘れるのは非常に簡単であり、手遅れになるまで問題を認識する簡単な方法はありません。Log4jの唯一の兆候は、ログにMDC情報が欠落していることと、Logbackを使用すると古いMDC情報が取得されることです(トレッドプールのスレッドは、実行された最初のタスクからMDCを継承するため)。どちらも本番システムでは深刻な問題です。 私たちの状況は特別なものだとは思いませんが、この問題についてウェブ上であまり見つけることができませんでした。どうやら、これは多くの人がぶつかる問題ではないので、それを回避する方法がなければなりません。ここで何が悪いのでしょうか?