DOKU Insight
Published in

DOKU Insight

Menambah Log untuk Processing Time di Spring Boot Menggunakan Anotasi Spring AOP

AOP (Aspect Oriented Programming) adalah cara untuk menambahkan behavior baru ke dalam code tanpa mengubah isi dari code yang sudah ada sebelumnya.Jenis AOP yang akan kita implementasi adalah annotation driven, contoh: @Transactional.

Dengan cukup menambahkan anotasi, kita tidak perlu menyentuh dan mengotori business logic yang sudah rapi. Oleh karena itu dalam artikel ini kita akan membuat custom annotation yang fungsinya adalah untuk menghitung processing time saat method dijalankan.

Pertama, tambahkan dependency berikut:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- optional untuk logging -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

Kedua, buat interface untuk anotasi tersebut. Nama interface akan menjadi nama anotasi yang akan digunakan nanti.

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

}
  • @Target menunjukkan di level mana anotasi tersebut dapat digunakan.
  • @Retention menunjukkan apakah anotasi akan tersedia saat JVM runtime atau tidak (defaultnya tidak).

Ketiga, buat class aspect:

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Slf4j
public class LoggingAspect {

@Around("@annotation(LogExecutionTime)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object proceed = joinPoint.proceed();
long executionTime = System.currentTimeMillis() - start;

log.info("Request processing time: " + executionTime + "ms");
return proceed;
}
}
  • @Aspect menunjukkan bahwa class tersebut adalah aspect. Penjelasan lebih lanjut mengenai aspect dapat dipelajari pada artikel-artikel mengenai Spring AOP, seperti: https://www.journaldev.com/2583/spring-aop-example-tutorial-aspect-advice-pointcut-joinpoint-annotations
  • @Component dibutuhkan untuk membuat class menjadi bean agar dapat dideteksi oleh Spring.
  • @Slf4j digunakan untuk logging, dalam hal ini “log.info”.
  • @Around adalah jenis advice yang menunjukkan bahwa kita menambahkan advice (code dalam method “logExecutionTime”) tersebut sebelum dan sesudah method execution. Ada tipe advice lainnya seperti “before” dan “after”. Di dalam anotasi around tersebut ada parameter yang menunjukkan bahwa advice tersebut akan diterapkan pada method dengan anotasi @LogExecutionTime.
  • Parameter ProceedingJoinPoint dalam method digunakan untuk menjalankan method yang sudah diberi anotasi @LogExecutionTime. Jika method tersebut dipanggil, maka method advice akan dijalankan terlebih dahulu. Dalam method advice ini kita menggunakan “joinPoint.proceed()” untuk menjalankan method yang diberi anotasi tersebut. Jika ingin mengetahui return type dan nama method yang dijalankan, bisa menggunakan “jointPoint.getSignature()”. Selengkapnya: https://www.eclipse.org/aspectj/doc/released/runtime-api/org/aspectj/lang/JoinPoint.html

Secara umum, yang dilakukan method advice tersebut adalah mencatat waktu sekarang dan ditampung ke variable start, lalu menjalankan method yang diberi anotasi, lalu menghitung lama waktu method tersebut dijalankan dengan cara mencatat waktu sekarang dikurangi waktu start. Setelah itu selisih waktu tersebut ditampilkan dalam log, lalu hasil dari method yang dijalankan di-return.

Untuk mencoba apakah berhasil, gunakan anotasi tersebut pada suatu method:

import com.example.logging.aop.utils.LogExecutionTime;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class PingController {

@GetMapping(value = "/ping")
@LogExecutionTime
public void test() throws InterruptedException {
Thread.sleep(2000);
}
}

Saat endpoint tersebut dipanggil dan method tersebut dijalankan, akan tampil log berikut:

Source code dari project ini dapat dilihat di:
https://github.com/plankrun/learn-logging-aop

Referensi

--

--

--

It’s beyond telling, it’s sharing

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Alexander Ang

Alexander Ang

A curious software developer who loves to write.

More from Medium

Asynchronous Rest service with messaging

Inter-Microservice Communication with OpenFeign using AWS AppMesh

How to deploy a Spring Boot Docker image at AWS ECS

Spring integration event logging using wiretap and interceptors