Использование аннотаций для ведения журнала трассировки

Я работал с кодовой базой компании, которая придерживается политики ведения большого количества журналов трассировки. Таким образом, почти каждый метод имеет фрагмент кода, который начинается так:

String LOG_METHOD = "nameOfMethod(String,List<Long>):void";
if(logger.isTraceEnabled()) { 
    Object[] params = new Object[] { string, list };
    logger.trace(CompanyMessages.newMethodInstanceMessage(this, LOG_METHOD, params)); 
}

и заканчиваться так (либо в finally-предложении, либо просто в конце метода:

if(logger.isTraceEnabled()) { 
    logger.trace(CompanyMessages.leaveMethodInstanceMessage(this, LOG_METHOD)); 
}

На самом деле там больше кода, но это основная идея. Это загромождает код, и другие кодеры постоянно запутывают его своими собственными интерпретациями, которые не используют определенный класс CompanyMessages, необходимый для форматирования сообщений, которые должны быть прочитаны инструментами мониторинга. Поэтому я ищу способ избавиться от всего кода выше и просто предоставить все методы, которые требуют ведения журнала трассировки, с аннотациями, такими как: @LogBefore('logLevel') и @LogAfter('logLevel').

Причина, по которой я выбрал это решение, заключается в том, чтобы другим разработчикам не нужно было изучать что-то новое, кроме как использовать аннотации вместо кода. Я работаю в серверной среде, в которой мы развертываем сотни веб-приложений и десятки разработчиков. Поэтому я искал способ реализовать это в веб-приложении без большого количества дополнительного кода или дополнительных больших библиотек. Это означает, что я ищу небольшую стабильную реализацию АОП с использованием аннотаций, подобных тем, которые я предложил, и которую легко настроить в каждом веб-приложении. Производительность также важна. Каков самый простой пример реализации этого с помощью АОП?

Изменить: я нашел что-то очень похожее на то, что я ищу, но у этого есть пара проблем. Все классы, которым требуется ведение журнала, должны быть настроены, что потребует больше ресурсов, чем простое использование аннотаций. Исправит ли это пружинная конфигурация <aop:aspectj-autoproxy/>?


person Community    schedule 09.04.2011    source источник


Ответы (3)


Похоже, что аспектно-ориентированное программирование (АОП) действительно может помочь вам в этом. Он отлично подходит для решения сквозных задач, таких как ведение журнала и отслеживание, и поддерживает аннотации, подобные тем, которые вам нужны.

Взгляните на AspectJ или Spring AOP.

Это потребует некоторого изучения принципов АОП и API, который вы выберете, но это определенно стоит затраченных усилий. В частности, ведение журнала и трассировка являются одними из первых руководств по АОП, с которыми вы столкнетесь, и их довольно легко сделать, не углубляясь.

person janhink    schedule 09.04.2011

Аннотации и точки АОП действительны. Используйте аннотации, чтобы предупредить платформу АОП о ведении журнала.

Еще я бы починил ваш регистратор.

У вас есть:

String LOG_METHOD = "nameOfMethod(String,List<Long>):void"
if(logger.isTraceEnabled()) { 
    Object[] params = new Object[] { string, list };
    logger.trace(CompanyMessages.newMethodInstanceMessage(this, LOG_METHOD, params) ); 
}

Вместо этого рассмотрите что-то вроде этого:

logger.trace(this, LOG_METHOD, string, list);

и вы можете реализовать это следующим образом:

public void trace(Object obj, Object args...) {
    if (parentLogger.isTraceEnabled()) {
        logger.trace(CompanyMessages.newMethodInstanceMessage(obj, LOG_METHOD, args);
    }
}

Большинство утилит ведения журнала были написаны до того, как в Java появились varargs, поэтому мы все еще видим то, что вы написали.

Мы также по-прежнему хотим, чтобы защита предотвращала ведение журнала вызовов, когда она не включена, но основная причина этого заключается в том, что большинство людей в прошлом делали то же, что и вы, или даже хуже:

logger.trace("My message: " + string + " with list " + list);

У которого есть дорогое выражение, включена ли трассировка или нет.

Но, используя varargs, вы можете получить и то, и другое. Просто используйте что-то вроде MessageFormat (что вы, вероятно, уже делаете), вы можете легко получить:

logger.trace("My message: {0} with list {1}", string, list);

С отключенной трассировкой это дешевый вызов метода, передающий 3 указателя. Таким образом, гораздо меньше мотивации охранять его и загромождать код.

Большинство современных логгеров плохо переопределяют, поэтому вам обычно приходится инкапсулировать его, а не просто расширять.

Это не решает вашу проблему напрямую, динамически генерируя информацию о трассировке. Но это простая золотая середина, которая легко и постепенно очищает существующую кодовую базу.

Кроме того, есть еще 2 варианта.

Во-первых, это использование постпроцессора, который прогоняет ваш код и добавляет регистрацию туда, где ее еще нет. Это избавляет вас от бремени ввода вручную, но это загромождает код (поскольку он все еще существует ВЕЗДЕ).

Во-вторых, использовать процессор аннотаций во время компиляции. Это более изощренно. Но то, что он делает, это во время компиляции, он проходит через ваши классы и дополняет их информацией во время компиляции. Приятно то, что ваш код чист (за исключением, возможно, аннотации), но также вся работа выполняется при компиляции. Там нет влияния времени выполнения, а не причудливых загрузчиков классов фабрик объектов. Как только он будет построен, вы можете выбросить свой процессор, он вообще не нужен во время выполнения.

Есть проект, чье имя ускользает от меня, который использует это. Он автоматически добавляет сеттеры/геттеры в ваш код при компиляции. Я слышал хорошие вещи об этом.

Фреймворки АОП вполне могут сделать это за вас при компиляции, я недостаточно знаком с ними, чтобы сказать об этом, но в любом случае эту технику стоит изучить.

Как минимум, оберните свой регистратор. Это инкрементальный, безопасный метод, который постепенно очищает ваш код и помогает вести журнал там, где аннотации в целом могут вам не подойти.

person Will Hartung    schedule 09.04.2011

Я не думаю, что аннотации были решением. Аннотирование класса или экземпляра означает предоставление классам дополнительной информации во время выполнения, само по себе это ничего не делает. Вам понадобится код, который обрабатывает классы с аннотациями и добавляет код до и после каждого метода на основе этих аннотаций во время выполнения.

Таким образом, нет возможности добавлять аннотации и готовы к работе, классы начинают регистрировать свои методы.

Решение должно быть АОП - именно для этой проблемы АОП был придуман в первую очередь. Определите классы/методы/действия для каждого метода, и проблема будет решена.

Что ж, возможно, вы можете заставить его работать с аннотациями и изменением классов во время выполнения, но в итоге вы получите самодельный АОП :-)

person Tomasz Stanczak    schedule 09.04.2011
comment
Спасибо, это заставило меня понять, что мой взгляд на работу аннотаций был ошибочным. - person mahler; 09.04.2011
comment
Хотелось бы хотя бы один пример АОП, пусть даже простой - person Jonathan; 17.10.2018