Хочу прикрутить к log4j возможность логирования бинарных данных. По сути мне нужно принять byte[]
и отдать его в appender.
Как-то так
byte[] data = {1, 2, 3};
log.debug(data);
Вопросы:
MessageLayout
Update
Как оказалось, одного Layout мало. Нужны еще манипуляции с интерфейсом Message
Обнаружилась такая проблема
при вызове
byte[] data = {1, 2, 3};
log.debug(data);
я попадаю в метод log
класса LoggerConfig
и там выполняется такая строчка
LogEvent logEvent = this.logEventFactory.createEvent(loggerName, marker, fqcn, level, data, (List)props, t);
где data
объект класса ReusableObjectMessage
у которого в поле obj
лежит мой массив.
Далее идет вызов
public LogEvent createEvent(String loggerName, Marker marker, String fqcn, Level level, Message message, List<Property> properties, Throwable t) {
MutableLogEvent result = (MutableLogEvent)mutableLogEventThreadLocal.get();
............
result.setMessage(message);
............
}
А метод MutableLogEvent.setMessage
реализован так
public void setMessage(Message msg) {
if (msg instanceof ReusableMessage) {
ReusableMessage reusable = (ReusableMessage)msg;
reusable.formatTo(this.getMessageTextForWriting());
this.messageFormat = msg.getFormat();
if (this.parameters != null) {
this.parameters = reusable.swapParameters(this.parameters);
this.parameterCount = reusable.getParameterCount();
}
} else {
this.message = InternalAsyncUtil.makeMessageImmutable(msg);
}
}
На строке
reusable.formatTo(this.getMessageTextForWriting());
идет жесткое преобразование объекта в строку а попытка обменяться параметрами
this.parameters = reusable.swapParameters(this.parameters);
приводит к фикции
public Object[] swapParameters(final Object[] emptyReplacement) {
return emptyReplacement;
}
хотя сами параметры у Message определены
public Object[] getParameters() {
return new Object[] {obj};
}
Итого получилось:
Реализуем свой Layout
@Plugin(
name = "BinaryLayout",
category = "Core",
elementType = "layout",
printObject = true
)
public class BinaryLayout extends MessageLayout {
@Override
public byte[] toByteArray(LogEvent event) {
Object[] params = event.getMessage().getParameters();
int size = 0;
int count = 0;
byte[] res = null;
for (Object obj : params) {
if (obj instanceof byte[]) {
byte[] tmp = (byte[])obj;
if (tmp.length > 0) {
size += tmp.length;
count++;
res = tmp;
}
}
}
if (count > 1) {
res = new byte[size];
size = 0;
for (Object obj : params) {
if (obj instanceof byte[]) {
byte[] tmp = (byte[])obj;
if (tmp.length > 0) {
System.arraycopy(tmp, 0, res, size, tmp.length);
size += tmp.length;
}
}
}
}
return res;
}
@PluginFactory
public static Layout<?> createLayout() {
return new BinaryLayout();
}
}
@Plugin
говорит, что упоминания в конфиге name = "BinaryLayout"
это к нам. Категория для layout должна быть Core
, а иначе наш layout не находится, elementType
и так ясно, а printObject
говорит, что метод toString
у нас не переопределен и печатать наш объект бессмысленно@PluginFactory
определяет фабричный метод, который создаст наш layoutРеализуем интерфейс Message
При записи в лог используем объект класса ObjectMessage
. Т.к. этот класс не является наследником ReusableMessage
, то при создании объекта LogEvent
не теряются наши данные
Объявляем в конфиге appender с нашим layout
<Appenders>
<File name="test" filename="log/test.log" append="false">
<BinaryLayout/>
</File>
</Appenders>
И, собственно, само использование
Logger log = LogManager.getLogger("test");
byte[] data = {1, 2, 3, 4};
log.debug(new ObjectMessage(data));
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Мне нужно сделать, чтобы программа могла занимать только один порт, это я сделал с помощью флагов: -Djavasecurity