How to properly time profile API written in Java Spring MVC?

Viewed 936

Input: I have API that becomes slower overtime I have access to it externally as a user and internally as a developer. I want to find a method to profile time and memory for each endpoint.

Output: Statistics for each endpoint after certain amount of time in stage/production environments to make a data set for further debugging of slow cases and possibly trigger messages/alerts when they happened.

Question: Is there any good monitor, load test framework that is easily plug-able to the Spring MVC application that I can start from?

Since, I didn't find any good solution so far. I tried to hibernate.statistics to track DB time and also manual time tracking with Apache StopWatch class. It works but this solutions are not very well maintainable and have their limitations.

1 Answers

You can do this using Spring AOP. Use aspects to store some data @Before, @After or @Around your methods.

You can add your custom annotation:

@Retention(RetentionPolicy.RUNTIME)
public @interface Profiling {
   String value();
}

Create an aspect:

@Aspect
public class ProfilingAspect{
    //for any method with @Profiling, no matter what the return type, name, or arguments are, call this method 
    @Around("execution(@foo.bar.packagename.Profiling * *(..)) && @annotation(profilingAnnotation)")
    public Object logDuration(ProceedingJoinPoint joinPoint, Profiling profilingAnnotation) throws Throwable {

        //capture the start time 
        long startTime = System.currentTimeMillis();

        //execute the method and get the result
        Object result = joinPoint.proceed();

        //capture the end time
        long endTime = System.currentTimeMillis();

        //calculate the duration and save it somewhere
        long duration = endTime - startTime;
        logger.info(profilingAnnotation.value()+": "+duration+"ms"); 

        //return the result to the caller
        return result; 
    }

}

Annotate your methods with @Profiling:

@Controller
public class HelloController{
     @RequestMapping("/api/example/hello")
     @Profiling("Hello World") 
     public @ResponseBody String getHelloWorld(){
          try {
              Thread.sleep(1000);
          } catch (InterruptedException e) {
              throw new RuntimeException("Sleep Interrupted", e);
          } 
          return "Hello World";
     } 

}

When invoked method will log something like: Hello World: 1007ms

Related