Journalisation des performances de printemps

Journalisation des performances de printemps

1. Vue d'ensemble

Dans ce didacticiel, nous examinerons quelques options de base proposées par Spring Framework pour la surveillance des performances.

2. PerformanceMonitorInterceptor

Une solution simple pour obtenir des fonctionnalités de surveillance de base pour le temps d'exécution de nos méthodes, nous pouvons utiliser la classePerformanceMonitorInterceptor hors de Spring AOP (Aspect Oriented Programming).

Spring AOP permet de définir des problèmes transversaux dans les applications, c'est-à-dire un code qui intercepte l'exécution d'une ou de plusieurs méthodes, afin d'ajouter des fonctionnalités supplémentaires.

La classePerformanceMonitorInterceptor est un intercepteur qui peut être associé à n'importe quelle méthode personnalisée à exécuter en même temps. Cette classe utilise une instanceStopWatch pour déterminer l'heure de début et de fin de l'exécution de la méthode.

Créons une simple classePerson et une classePersonService avec deux méthodes que nous surveillerons:

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();
    }
}

Pour pouvoir utiliser l'intercepteur de surveillance Spring, nous devons définir un pointcut et un conseiller:

@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();
    }
}

Le pointcut contient une expression qui identifie les méthodes que nous voulons être interceptées - dans notre cas, la méthodegetFullName() de la classePersonService.

Après avoir configuré le beanperformanceMonitorInterceptor(), nous devons associer l'intercepteur au pointcut. Ceci est réalisé par un conseiller, comme indiqué dans l'exemple ci-dessus.

Enfin, l'annotation@EnableAspectJAutoProxy activeAspectJ support pour nos beans. En termes simples, AspectJ est une bibliothèque créée pour faciliter l'utilisation de Spring AOP grâce à des annotations pratiques telles que@Pointcut.

Après avoir créé la configuration, nous devonsset the log level of the interceptor class to TRACE, car c'est le niveau auquel il enregistre les messages.

Par exemple, en utilisant Jog4j, nous pouvons y parvenir via le fichierlog4j.properties:

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

Pour chaque exécution de la méthodegetAge(), nous verrons le messageTRACE dans le journal de la console:

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

3. Intercepteur de surveillance des performances personnalisé

Si nous voulons quemore control over the way the performance monitoring soit fait, nous pouvons implémenter notre propre intercepteur personnalisé.

Pour cela, étendons la classeAbstractMonitoringInterceptor et remplaçons la méthodeinvokeUnderTrace() pour consigner le début, la fin et la durée d'une méthode, ainsi qu'un avertissement si l'exécution de la méthode dure plus de 10 ms:

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!");
            }
        }
    }
}

Les étapes à suivre pour associer l'intercepteur personnalisé à une ou plusieurs méthodes, comme dans la section précédente, doivent être suivies.

Définissons un pointcut pour la méthodegetAge() dePersonService et associons-le à l’intercepteur que nous avons créé:

@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());
}

Définissons le niveau de journalisation surINFO pour l'intercepteur personnalisé:

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

L'exécution de la méthode getAge() a produit la sortie suivante:

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. Conclusion

Dans ce tutoriel rapide, nous avons introduit une surveillance simple des performances dans Spring.

Comme toujours, le code source complet de cet article peut être trouvéover on Github.