Federleistungsprotokollierung

Spring Performance Logging

1. Überblick

In diesem Tutorial werden einige grundlegende Optionen erläutert, die das Spring Framework für die Leistungsüberwachung bietet.

2. PerformanceMonitorInterceptor

Als einfache Lösung, um grundlegende Überwachungsfunktionen für die Ausführungszeit unserer Methoden zu erhalten, können wir die KlassePerformanceMonitorInterceptoraus Spring AOP (Aspect Oriented Programming) verwenden.

Spring AOP ermöglicht die Definition von Querschnittsthemen in Anwendungen, dh Code, der die Ausführung einer oder mehrerer Methoden abfängt, um zusätzliche Funktionen hinzuzufügen.

Die KlassePerformanceMonitorInterceptor ist ein Interceptor, der jeder benutzerdefinierten Methode zugeordnet werden kann, die gleichzeitig ausgeführt werden soll. Diese Klasse verwendet eineStopWatch-Instanz, um die Anfangs- und Endzeit des Methodenlaufs zu bestimmen.

Erstellen wir eine einfachePerson-Klasse und einePersonService-Klasse mit zwei Methoden, die wir überwachen werden:

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

Um den Spring Monitoring Interceptor nutzen zu können, müssen Sie einen Pointcut und einen Advisor definieren:

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

Der Pointcut enthält einen Ausdruck, der die Methoden identifiziert, die abgefangen werden sollen - in unserem Fall diegetFullName()-Methode derPersonService-Klasse.

Nach dem Konfigurieren derperformanceMonitorInterceptor()-Bean müssen wir den Interceptor dem Pointcut zuordnen. Dies wird durch einen Berater erreicht, wie im obigen Beispiel gezeigt.

Schließlich aktiviert die Annotation@EnableAspectJAutoProxyAspectJ support für unsere Bohnen. Einfach ausgedrückt ist AspectJ eine Bibliothek, die erstellt wurde, um die Verwendung von Spring AOP durch praktische Anmerkungen wie@Pointcut zu vereinfachen.

Nach dem Erstellen der Konfiguration müssen wirset the log level of the interceptor class to TRACE eingeben, da dies die Ebene ist, auf der Nachrichten protokolliert werden.

Mit Jog4j können wir dies beispielsweise über die Dateilog4j.propertieserreichen:

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

Bei jeder Ausführung der MethodegetAge() wird die MeldungTRACE im Konsolenprotokoll angezeigt:

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

3. Benutzerdefinierter Interceptor zur Leistungsüberwachung

Wennmore control over the way the performance monitoring ausgeführt werden soll, können wir unseren eigenen benutzerdefinierten Interceptor implementieren.

Erweitern Sie dazu die KlasseAbstractMonitoringInterceptorund überschreiben Sie die MethodeinvokeUnderTrace(), um Start, Ende und Dauer einer Methode zu protokollieren, sowie eine Warnung, wenn die Methodenausführung länger als 10 ms dauert:

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

Die gleichen Schritte zum Zuordnen des benutzerdefinierten Interceptors zu einer oder mehreren Methoden wie im vorherigen Abschnitt müssen ausgeführt werden.

Definieren wir einen Pointcut für diegetAge()-Methode vonPersonService und ordnen Sie ihn dem von uns erstellten Interceptor zu:

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

Setzen wir die Protokollstufe für den benutzerdefinierten Interceptor aufINFO:

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

Die Ausführung der Methode getAge()ergab die folgende Ausgabe:

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

In diesem kurzen Tutorial haben wir im Frühjahr eine einfache Leistungsüberwachung eingeführt.

Wie immer finden Sie den vollständigen Quellcode für diesen Artikel inover on Github.