Как профилировать сложную обработку http-запросов в Spring Boot? - PullRequest
0 голосов
/ 12 февраля 2019

У меня сложный метод @RestController, что-то вроде этого:

@PostMapping("{id}")
@PreAuthorize("hasRole('ADMIN')")
@Transactional
public Response handleRequest(@PathVariable("id") long id, @RequestBody @Valid Request request) {
    return service.handleRequest(id, request);
}

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

  • запрос десериализации
  • проверка
  • проверка прав доступа
  • начало и окончание транзакции
  • сериализация ответа

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

Единственный способ сделать это сейчас - изменить этот метод так, чтобы он принимал HttpServletRequest и HttpServletResponse и выполнял эти части внутри тела метода.Но тогда я потеряю много преимуществ Spring Boot.

Ответы [ 2 ]

0 голосов
/ 13 февраля 2019

вы также можете проверить tuto для добавления пользовательских метрик для исполнительного механизма, но это кажется немного сложным (но вам придется кодировать свой собственный bean-компонент метрик и вставлять его в код, переопределять objectMapper для отображения и т. Д....)

или, может быть, активировать регистрационную информацию о Джексоне, Spring-Security, Javax.validation для проверки времени в журнале для каждой операции, но не очень точно

0 голосов
/ 13 февраля 2019

Нет необходимости изменять метод, чтобы ожидать HttpServletRequest.Вы можете использовать AspectJ

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

Создать методВременной аннотарион

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MethodTiming {
}

В вашем запросе создайте карту, в которой будут храниться все методы и время, затраченное на них:

  public class Request {
  private Map<String, Long> methodTimings = new TreeMap<String, Long>();

  public void addMethodTiming(String classAndMethodName, long executionTimeMillis) {
        Long value = methodTimings.get(classAndMethodName);
        if (value != null) {
            executionTimeMillis += value;
        }

        methodTimings.put(classAndMethodName, executionTimeMillis);
    }
  }

Затем создайте класс Aspect, который будет обрабатывать его:

@Aspect
@Component
public class MethodTimingAspect {
private static final String DOT = ".";

@Around("@annotation(MethodTiming)")
public Object timeAround(ProceedingJoinPoint joinPoint) throws Throwable  {
    Object result = null;

    StopWatch watch = new StopWatch();
    try {
        watch.start();
        result = joinPoint.proceed();
    } finally {
        watch.stop();
        long executionTime = watch.getLastTaskTimeMillis();

        String className = joinPoint.getTarget().getClass().getSimpleName();
        String methodName = joinPoint.getSignature().getName();
        String classAndMethodName = className + DOT + methodName;

        Object[] methodArgs = joinPoint.getArgs();
        if (methodArgs != null) {
            for (Object arg : methodArgs) {
                if (arg instanceof Request) {
                    // inject time back into Request
                    Request request = (Request) arg;
                    request.addMethodTiming(classAndMethodName, executionTime);

                    break;
                }
            }
        }

    }
    return result;
}

Наконец, просто добавьте @MethodTiming к методам, которые вы хотите измерить:

@MethodTiming
public Request handleRequest(Request request) {
// handle the Request
return request
}

Ваш объект запроса будет иметь после процесса что-то вроде

"methodTimings": {
    "RequestService.handleRequest": 2610,
    "AnotherRequestService.anotherMethod": 1351
}
...