Поднятие тревоги для долго выполняющихся методов в Spring Boot

RedDeveloper
24.06.2023 15:34
Поднятие тревоги для долго выполняющихся методов в Spring Boot

Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше времени, чем нужно? Что если вас попросили создать глобальное решение в вашем Spring Boot API? Если да, то эта статья может быть идеальной для вас.

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

  1. maxThresholdTime - Это будет переменная для установки ожидаемого максимального времени выполнения метода.
  2. executionTimeUnit - Это будет переменная для установки единицы времени, в которой вы хотите иметь максимальное время порога (maximumThresholdTime).
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExecutionTimeLogger {

 int maxThresholdTime() default 0;
 
 ExecutionTimeUnit executionTimeUnit() default ExecutionTimeUnit.SECONDS;
 
 enum ExecutionTimeUnit {
  MILLISECONDS, SECONDS, MINUTES
 }
}

Давайте теперь проверим, как эти дополнительные переменные становятся полезными в вашем аспекте. Если у вас нет базового понимания того, как работают @Aspect и @Around, пожалуйста, просмотрите начальную статью . Как вы можете видеть в приведенном ниже коде, теперь мы будем передавать класс Annotation в качестве параметра в нашем методе AOP.

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

В приведенном ниже коде мы проверяем, установлен ли ExecutionTimeUnit пользователем, если нет, то по умолчанию считается Second TimeUnit. Время выполнения метода вычисляется в заданном TimeUnit. После этого код проверяет, что если время выполнения превышает maxThresholdTime, то генерируется предупреждение в журналах.

@Aspect
@Component
public class ExecutionTimeLoggerAspect {

    static final Logger logger = LoggerFactory.getLogger(ExecutionTimeLoggerAspect.class);

    @Around("@annotation(executionTimeLogger)")
    public Object executionTimeLogger(ProceedingJoinPoint joinPoint, ExecutionTimeLogger executionTimeLogger) {

        try {

            long startTime = System.currentTimeMillis();
            Object proceed = joinPoint.proceed();
            long executionTime = (System.currentTimeMillis() - startTime);
            ExecutionTimeUnit executionTimeUnit = executionTimeLogger.executionTimeUnit();

            switch (executionTimeUnit) {
                case MILLISECONDS:
                    break;
                case MINUTES:
                    executionTime = executionTime / 60000;
                    break;
                case SECONDS:
                default:
                    executionTime = executionTime / 1000;
                    break;
            }

            int maxThresholdTime = executionTimeLogger.maxThresholdTime();

            if (maxThresholdTime > 0 && executionTime > maxThresholdTime) {
                logger.warn(
                        "{} method was executed in {} {} which was higher than expected Max Threshold Time of {} {}",
                        joinPoint.getSignature(), executionTime, executionTimeUnit, maxThresholdTime,
                        executionTimeUnit);
              // Trigger an Email
              // Log it in Database
            } else {
                logger.info("{} method was executed in {} {}", joinPoint.getSignature(), executionTime,
                        executionTimeUnit);
            }
            return proceed;
        } catch (Throwable e) {
            logger.error("There was an error while calculating method execution time for {}", joinPoint.getSignature(),
                    e);
            return null;
        }
    }
}

Давайте теперь проверим, как мы можем использовать эту аннотацию в различных комбинациях, чтобы получить преимущества концепций Spring AOP.

  1. В первом методе мы используем только аннотацию. Поэтому она будет просто регистрировать время выполнения метода
  2. Во втором методе мы передаем maxThresholdTime в качестве входного параметра аннотации. Таким образом, аннотация будет генерировать предупреждение, если метод займет более 2 секунд времени во время выполнения.
  3. В 3-м методе мы передаем maxThresholdTime & TimeUnit. Таким образом, аннотация выдаст предупреждение, если метод займет более 50 миллисекунд времени выполнения.
public class CustomizedExecutionLogging {

//Log method execution time
@ExecutionTimeLogger
 public void aspectMethodOne() throws InterruptedException {
  Thread.sleep(2000);
 }

//Log warning if method takes more than 2 seconds
 @ExecutionTimeLogger(maxThresholdTime = 2)
 public void aspectMethodTwo() throws InterruptedException {
  Thread.sleep(3000);
 }

//Log warning if method takes more than 50 milliseconds
 @ExecutionTimeLogger(maxThresholdTime = 50, executionTimeUnit = ExecutionTimeUnit.MILLISECONDS)
 public void aspectMethodThree() throws InterruptedException {
  Thread.sleep(100);
 }

}
#OUTPUT
C.n.a.e.ExecutionTimeLoggerAspect : void com.niket.agrawal.executionTimeLogger.MethodExecutions.aspectMethodOne() метод был выполнен за 2 СЕКУНДЫ
C.n.a.e.ExecutionTimeLoggerAspect : void com.niket.agrawal.executionTimeLogger.MethodExecutions.aspectMethodTwo() метод был выполнен за 3 СЕКУНДЫ, что выше ожидаемого максимального порогового времени в 2 СЕКУНДЫ
C.n.a.e.ExecutionTimeLoggerAspect : void com.niket.agrawal.executionTimeLogger.MethodExecutions.aspectMethodThree() метод был выполнен за 109 МИЛЛИСЕКУНД, что выше ожидаемого максимального порогового времени в 50 МИЛЛИСЕКУНД.

Пример кода можно посмотреть на GitHub: https://github.com/niket17590/executionTimeLogger

Как вы можете видеть, в мире Spring Boot & AOP существуют бесконечные возможности, а также он становится все лучше и лучше, когда концепции становятся ясными.

Надеюсь, эта статья поможет вам улучшить свои знания о концепциях Spring Boot & Spring AOP.

Надеюсь эта статья поможет вам улучшить свои знания о концепциях Spring Boot & Spring
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?

20.08.2023 18:21

Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в 2023-2024 годах? Или это полная лажа?".

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией

20.08.2023 17:46

В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.

Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox

19.08.2023 18:39

Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в частности, магию поплавков и гибкость flexbox.

Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest

19.08.2023 17:22

В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для чтения благодаря своей простоте. Кроме того, мы всегда хотим проверить самые последние возможности в наших проектах!

Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️

18.08.2023 20:33

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

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL

14.08.2023 14:49

Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип предназначен для представления неделимого значения.