Использование Eclipse AspectJ для внедрения регистратора, который регистрирует контекст / метаданные выполняемого кода?

#java #aop #aspectj

#java #aop #aspectj

Вопрос:

Я пытаюсь определить аспект для внедрения регистратора.

Я хочу создать что-то вроде:

 import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public aspect LogInjector {

    private pointcut executionJoinPoints(): !within(LogInjector) amp;amp; execution (* *.*(..));

    before(): executionJoinPoints(){
        // Get class name of the executed code
        clazz = ...
        final Logger logger = LogManager.getLogger(clazz);

        // Get method name of the executed code
        method = ...

        // Get params name, type and values triplet or values at least if the previous is not possible, of the executed code
        params = ...

        // Get call stack of the executed code
        stack = ...

        logger.trace("{}.{}({}) - {}", clazz.name(), method.name(), params, stack);
    }

    after(): executionJoinPoints(){
        // Get class name of the executed code
        clazz = ...
        final Logger logger = LogManager.getLogger(clazz);

        // Get method name of the executed code
        method = ...

        // Get return value or exception of the executed code
        result = ...

        logger.trace("{}.{} = {}", clazz.name(), method.name(), result);
    }
}

  

Для этого я хочу получить метаданные / контекстные данные выполнения:

  • исключения
  • возвращаемые значения

Как можно получить эти метаданные / контекстные данные?

Комментарии:

1. Итак, вы задаете 6 разных вопросов (количество маркированных пунктов), ожидая, что кто-то сделает всю работу за вас. Я понимаю. Могу я спросить, читали ли вы какую-либо документацию, пробовали ли какие-либо методы, предлагаемые через автозаполнение в вашей точке соединения или аналогичные? Кроме того, известно ли вам о том, что такой универсальный аспект значительно замедлит работу вашего приложения, нацеливаясь на выполнение всех методов и извлекая всю возможную подробную информацию повсюду? Вы думали об отступах, чтобы отображать иерархии вызовов вместо создания трассировок стека для каждого вызываемого метода?

2. Для вызова подойдет отступ стека. С этим я могу справиться. С тех пор, как я задал вопрос, я разобрался со многими элементами, кроме как регистрировать возвращаемые значения и исключения. Кроме того, как мне ускорить аспект, не замедляя работу моего приложения? По сути, я хочу отслеживать через приложение протоколирование вызовов функций, возвращаемых значений и исключений.

Ответ №1:

Чтобы сохранить эффективность вашего аспекта, я рекомендую следующее:

  • Ограничьте свой pointcut целевыми пакетами и классами, которые вы действительно хотите отлаживать. Не регистрируйте / не отслеживайте весь мир. Вы также можете использовать абстрактный базовый аспект с абстрактным точечным разрезом и расширить аспект до конкретного подаспекта с конкретным точечным разрезом. Последнее может быть предоставлено даже через конфигурацию XML, если вы используете переплетение времени загрузки.
  • Используйте around() совет вместо before() / after() pair . Затем вам нужно только один раз вычислить некоторые из зарегистрированных значений и использовать их как до, так и после исходного вызова метода, выполняемого с помощью proceed() .
  • Просто регистрируйте thisJoinPoint вместо того, чтобы собирать вместе биты, содержащиеся в нем по умолчанию. Это уже даст вам тип точки соединения, сигнатуру метода, включая типы параметров и возвращаемое значение.
  • Не регистрируйте имена параметров, информация не добавляет реальной ценности. Кроме того, имена параметров подлежат рефакторингу и присутствуют только в том случае, если ваш код скомпилирован с отладочной информацией. Сохраняйте простоту и регистрируйте только значения параметров.
  • В around() упомянутом выше совете вы можете заключить proceed() вызов в try-catch-finally и удобно обрабатывать и регистрировать любые исключения и трассировки стека и / или переносить проверенные исключения в AspectJ SoftException или простой RuntimeException и повторно выбрасывать их. Все, что применимо к вашей ситуации.
  • Результаты вызова метода — это просто результаты proceed() , которые вы также должны вернуть из around() совета. Вы также можете вернуть что-то другое вместо этого (но оно должно иметь правильный возвращаемый тип) или полностью пропустить proceed() , если по какой-либо причине вы хотите пропустить выполнение целевого метода.

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

Комментарии:

1. Есть ли способ избежать proceed() и try-catch , но добиться того же. try-catch вам нужно перестроить, чтобы это привело к измененной трассировке стека. Также proceed() делает больше, чем просто захват возвращаемого значения с минимальными накладными расходами.

2. Почему вас беспокоит преждевременная оптимизация, если по замыслу вы создаете медленный аспект, используемый только для отладки в любом случае? Никто в здравом уме не будет всегда регистрировать каждый вызов метода в производственной среде. Почему должны proceed() быть накладные расходы? Он просто вызывает целевой метод, который в любом случае необходимо выполнить. Вместо этого вы могли бы использовать after returning after throwing советы и, но тогда вам придется вычислять вещи для регистрации несколько раз. Для ваших целей и around() советов это просто самая эффективная вещь. Если вы думаете, что знаете лучше, будьте моим гостем и продолжайте.