#java #log4j #mdc
#java #log4j #mdc
Вопрос:
Я хочу передать произвольный объект в ThreadContext.put()
метод следующим образом:
MyObject originalMessage = new MyObject(...);
ThreadContext.put("originalMessage", originalMessage);
Но этот метод допускает только String
в качестве своего второго аргумента: docs here .
Есть ли способ поместить произвольный объект в log4j в MDC Log4j? Или альтернатива этому? Я хочу разрешить дальнейшие выполнения log.error()
для автоматической регистрации originalMessage
без необходимости передачи его в качестве параметра везде.
Кроме того, я не могу вызвать toString()
себя, поскольку я бы с нетерпением оценивал этот метод (который довольно тяжелый в этом объекте), поэтому я хочу, чтобы его вызов был отложен до тех пор, пока он не понадобится, точно так же, как при передаче произвольного объекта log.debug("{}", someObject)
.
Комментарии:
1. Вы можете выполнить поиск объекта, например, в формате json или создать
Map<String,Object>
сохранить объект там и поместить ключ вThreadContext
.2. Не могли бы вы объяснить подробнее?
put
Метод вThreadContext
принимает только строки, поэтому, если я использую JSONObject или Map, мне все равно нужно преобразовать его в строку, прежде чем я смогу поместить его в ThreadContext. Документы здесь: logging.apache.org/log4j/2.x/log4j-api/apidocs/org/apache /…3. Вы можете преобразовать некоторые объекты в строку с помощью json и отменить этот процесс.
4. Основная проблема заключается в том, что преобразование этого объекта в string слишком тяжелое, будь то с помощью toString или если я сначала преобразовываю его в JSONObject, а затем вызываю в нем toString . В моем случае размер этого объекта составляет несколько МБ, и этот метод выполняется много раз.
Ответ №1:
Я, наконец, нашел (взломанное) решение здесь и здесь .
Вместо этого (который не компилируется):
ThreadContext.put("originalMessage", originalMessage);
Я могу сделать:
final var threadContextMap = (ObjectThreadContextMap) ThreadContext.getThreadContextMap();
threadContextMap.putValue("originalMessage", originalMessage);
Это работает до тех пор, пока вы добавляете эту опцию JVM:
-Dlog4j2.threadContextMap=org.apache.logging.log4j.spi.CopyOnWriteSortedArrayThreadContextMap
Теперь это выглядит хакерски, потому что метод getThreadContextMap() должен возвращать представление внутренней карты только для чтения:
Возвращает доступную только для чтения внутреннюю структуру данных, используемую для хранения пар ключ-значение контекста потока …
Итак, это решение использует эту карту только для чтения и, зная, что реализация не доступна только для чтения, изменяет ее… не самое прозрачное решение, но оно работает.