Spring Performance Logging

Spring Performance Logging

1. обзор

В этом руководстве мы рассмотрим несколько основных вариантов, которые Spring Framework предлагает для мониторинга производительности.

2. PerformanceMonitorInterceptorс

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

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

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

Давайте создадим простой классPerson и классPersonService с двумя методами, которые мы будем отслеживать:

public class Person {
    private String lastName;
    private String firstName;
    private LocalDate dateOfBirth;

    // standard constructors, getters, setters
}
public class PersonService {

    public String getFullName(Person person){
        return person.getLastName()+" "+person.getFirstName();
    }

    public int getAge(Person person){
        Period p = Period.between(person.getDateOfBirth(), LocalDate.now());
        return p.getYears();
    }
}

Чтобы использовать перехватчик мониторинга Spring, нам нужно определить pointcut и advisor:

@Configuration
@EnableAspectJAutoProxy
@Aspect
public class AopConfiguration {

    @Pointcut(
      "execution(public String com.example.performancemonitor.PersonService.getFullName(..))"
    )
    public void monitor() { }

    @Bean
    public PerformanceMonitorInterceptor performanceMonitorInterceptor() {
        return new PerformanceMonitorInterceptor(true);
    }

    @Bean
    public Advisor performanceMonitorAdvisor() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("com.example.performancemonitor.AopConfiguration.monitor()");
        return new DefaultPointcutAdvisor(pointcut, performanceMonitorInterceptor());
    }

    @Bean
    public Person person(){
        return new Person("John","Smith", LocalDate.of(1980, Month.JANUARY, 12));
    }

    @Bean
    public PersonService personService(){
        return new PersonService();
    }
}

Pointcut содержит выражение, определяющее методы, которые мы хотим перехватить - в нашем случае это методgetFullName() классаPersonService.

После настройки bean-компонентаperformanceMonitorInterceptor() нам нужно связать перехватчик с pointcut. Это достигается с помощью советника, как показано в примере выше.

Наконец, аннотация@EnableAspectJAutoProxy включаетAspectJ support для наших bean-компонентов. Проще говоря, AspectJ - это библиотека, созданная для упрощения использования Spring AOP с помощью удобных аннотаций, таких как@Pointcut.

После создания конфигурации нам нужноset the log level of the interceptor class to TRACE, так как это уровень, на котором он регистрирует сообщения.

Например, используя Jog4j, мы можем добиться этого с помощью файлаlog4j.properties:

log4j.logger.org.springframework.aop.interceptor.PerformanceMonitorInterceptor=TRACE, stdout

При каждом выполнении методаgetAge() мы будем видеть сообщениеTRACE в журнале консоли:

2017-01-08 19:19:25 TRACE
  PersonService:66 - StopWatch
  'com.example.performancemonitor.PersonService.getFullName':
  running time (millis) = 10

3. Пользовательский перехватчик мониторинга производительности

Если мы хотим, чтобыmore control over the way the performance monitoring был готов, мы можем реализовать наш собственный перехватчик.

Для этого давайте расширим классAbstractMonitoringInterceptor и переопределим методinvokeUnderTrace(), чтобы регистрировать начало, конец и продолжительность метода, а также предупреждение, если выполнение метода длится более 10 мс:

public class MyPerformanceMonitorInterceptor extends AbstractMonitoringInterceptor {

    public MyPerformanceMonitorInterceptor() {
    }

    public MyPerformanceMonitorInterceptor(boolean useDynamicLogger) {
            setUseDynamicLogger(useDynamicLogger);
    }

    @Override
    protected Object invokeUnderTrace(MethodInvocation invocation, Log log)
      throws Throwable {
        String name = createInvocationTraceName(invocation);
        long start = System.currentTimeMillis();
        log.info("Method " + name + " execution started at:" + new Date());
        try {
            return invocation.proceed();
        }
        finally {
            long end = System.currentTimeMillis();
            long time = end - start;
            log.info("Method "+name+" execution lasted:"+time+" ms");
            log.info("Method "+name+" execution ended at:"+new Date());

            if (time > 10){
                log.warn("Method execution longer than 10 ms!");
            }
        }
    }
}

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

Давайте определим pointcut для методаgetAge() дляPersonService и свяжем его с созданным нами перехватчиком:

@Pointcut("execution(public int com.example.performancemonitor.PersonService.getAge(..))")
public void myMonitor() { }

@Bean
public MyPerformanceMonitorInterceptor myPerformanceMonitorInterceptor() {
    return new MyPerformanceMonitorInterceptor(true);
}

@Bean
public Advisor myPerformanceMonitorAdvisor() {
    AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
    pointcut.setExpression("com.example.performancemonitor.AopConfiguration.myMonitor()");
    return new DefaultPointcutAdvisor(pointcut, myPerformanceMonitorInterceptor());
}

Давайте установим уровень журнала наINFO для пользовательского перехватчика:

log4j.logger.com.example.performancemonitor.MyPerformanceMonitorInterceptor=INFO, stdout

Выполнение метода getAge() дало следующий результат:

2017-01-08 19:19:25 INFO PersonService:26 -
  Method com.example.performancemonitor.PersonService.getAge
  execution started at:Sun Jan 08 19:19:25 EET 2017
2017-01-08 19:19:25 INFO PersonService:33 -
  Method com.example.performancemonitor.PersonService.getAge execution lasted:50 ms
2017-01-08 19:19:25 INFO PersonService:34 -
  Method com.example.performancemonitor.PersonService.getAge
  execution ended at:Sun Jan 08 19:19:25 EET 2017
2017-01-08 19:19:25 WARN PersonService:37 -
  Method execution longer than 10 ms!

4. Заключение

В этом кратком руководстве мы представили простой мониторинг производительности в Spring.

Как всегда, полный исходный код этой статьи можно найти наover on Github.

Related