Trong phần mềm của chúng tôi, chúng tôi sử dụng rộng rãi MDC để theo dõi những thứ như ID phiên và tên người dùng cho các yêu cầu web. Điều này hoạt động tốt trong khi chạy trong chủ đề ban đầu. Tuy nhiên, có rất nhiều thứ cần được xử lý trong nền. Vì vậy, chúng tôi sử dụng java.concurrent.ThreadPoolExecutor
và java.util.Timer
các lớp cùng với một số dịch vụ thực thi async tự cuộn. Tất cả các dịch vụ này quản lý nhóm chủ đề riêng của họ.
Đây là những gì hướng dẫn của Logback nói về việc sử dụng MDC trong môi trường như vậy:
Một bản sao của bối cảnh chẩn đoán được ánh xạ không phải lúc nào cũng được kế thừa bởi các luồng công nhân từ luồng khởi tạo. Đây là trường hợp khi java.util.concản.Executors được sử dụng để quản lý luồng. Ví dụ, phương thức newCachedThreadPool tạo ra một ThreadPoolExecutor và giống như mã tổng hợp luồng khác, nó có logic tạo luồng phức tạp.
Trong các trường hợp như vậy, MDC.getCopyOfContextMap () được gọi trên luồng gốc (chủ) trước khi gửi một tác vụ cho người thi hành. Khi tác vụ chạy, như là hành động đầu tiên của nó, nó sẽ gọi MDC.setContextMapValues () để liên kết bản sao được lưu trữ của các giá trị MDC ban đầu với luồng được quản lý Executor mới.
Điều này sẽ ổn, nhưng rất dễ quên việc thêm các cuộc gọi đó, và không có cách nào dễ dàng để nhận ra vấn đề cho đến khi quá muộn. Dấu hiệu duy nhất với Log4j là bạn bị thiếu thông tin MDC trong nhật ký và với Logback, bạn nhận được thông tin MDC cũ (vì luồng trong nhóm bước đi kế thừa MDC của nó từ tác vụ đầu tiên được chạy trên nó). Cả hai đều là vấn đề nghiêm trọng trong một hệ thống sản xuất.
Tôi không thấy tình hình của chúng tôi đặc biệt theo bất kỳ cách nào, nhưng tôi không thể tìm thấy nhiều về vấn đề này trên web. Rõ ràng, đây không phải là điều mà nhiều người gặp phải, vì vậy phải có cách để tránh nó. Chúng ta đang làm gì sai ở đây?