Spring Boot - AOP로 메서드 실행 시간 로깅하기

devdo·2024년 2월 22일
0

SpringBoot

목록 보기
39/43
post-thumbnail

메서드의 실행시간이 얼마나 걸리는지 확인하고 싶었습니다.

실행 시간을 측정하고 싶은 메서드에 @TimeTrace라는 어노테이션을 만들어서,

이를 Spring의 AOP 기능으로 공통모듈화 시켜보았습니다.


TimeTrace

TimeTrace 어노테이션

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

TimeTraceAspect.java

@Slf4j
@Component
@Aspect
public class TimeTraceAspect {

    @Pointcut("@annotation(com.wala.api.infra.aop.TimeTrace)")
    public void timeTracePointcut() {
    }

    @Around("timeTracePointcut()")
    public Object timeTrace(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        try {
            return joinPoint.proceed(); // 실제 타겟 호출
        } finally {
            long end = System.currentTimeMillis();
            long timeMs = end - start;
            log.info("{} - total time = {} ms", joinPoint.getSignature().toShortString(), timeMs);
        }
    }
}
  • PCD(Pointcut Designator)는 @annotaion을 사용
    - TimeTrace 어노테이션을 가지고 있는 메서드를 타겟으로 함
  • Advice는 실제 타겟 호출 전, 후에 로직이 있으므로 @Around를 사용
    - 실제 타겟 호출 전에 long start 시작, 마지막에 long end 종료하고 로그를 남기는 로직

테스트

// controller
@RestController  
@RequiredArgsConstructor  
public class HelloController {  
	private final HelloService helloService;  
	  
	@TimeTrace  
	@GetMapping("hello")  
	public void hello() throws InterruptedException {  
		helloService.hello();  
	}
}

// service
@Service  
public class HelloServiceImpl implements HelloService {  
  
	@TimeTrace  
	@Override  
	public void hello() throws InterruptedException {  
		Thread.sleep(1000);  
	}  
}

결과

... HelloServiceImpl.hello() - Total time = 1.005074833s 
... HelloController.hello() - Total time = 1.009257125s 

동작 원리

메서드에 @TimeTrace 어노테이션만 -> 프록시를 적용!

@SpringBootApplication 어노테이션을 안에 @EnableAutoConfiguration이 포함되어 있다.

개발자들이 사용할 라이브러리의 스프링 Bean을 직접 등록해서 사용해야한다면 번거로울 것이다.
⭐ 이 어노테이션이 자동으로 Bean으로 등록해준다.

그리고 Aop 빈 즉, @TimeTrace 같은 어노테이션을 Bean으로 등록할 때는 AnnotationAwareAspectJAutoProxyCreator라는 빈 후처리기가 자동으로 등록해준다!

빈 후처리기
객체를 스프링 빈에 등록하기 직전 조작을 할 수 있게 한다.

AnnotationAwareAspectJAutoProxyCreator이란?
@Aspect 어노테이션이 있는 스프링 빈을 BeanFactoryAspectJAdvisorBuilder를 통해 Advisor를 생성하고 저장함
Advisor의 정보를 기반으로 적용 대상을 확인하고 프록시를 생성함


또다른 예시(CPU,Memory 사용량 체크)

이런 AOP 방식으로 여러가지 메서드마다 공통모듈을 적용시킬 수 있다.

@CPUUsage, @MemoryUsage 어노테이션을 메서드로 붙여서 확인!

CPUUsage

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

MemoryUsage

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

MonitoringAspect

@Slf4j
@Component
@Aspect
public class MonitoringAspect {

    @Pointcut("@annotation(CPUUsage) || @annotation(MemoryUsage)")
    public void monitorPointcut() {}

    @Around("monitorPointcut()")
    public Object monitor(ProceedingJoinPoint joinPoint) throws Throwable {
            OperatingSystemMXBean operatingSystemMXBean  = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class);
            double cpuUsage = operatingSystemMXBean .getSystemCpuLoad() * 100;  // CPU 사용량
            log.info("CPU Usage: " + String.format("%.2f", cpuUsage) + "%");
            Runtime runtime = Runtime.getRuntime();
            double totalMemory = runtime.totalMemory();     // 현재 시스템의 총 메모리
            double freeMemory = runtime.freeMemory();       // 현재 시스템의 사용 가능한 메모리
            double usedMemory = totalMemory - freeMemory;   // 현재 시스템에서 사용 중인 메모리

            double memoryUsage = (usedMemory / totalMemory) * 100;
            log.info("Memory Usage: " + String.format("%.2f", memoryUsage) + "%");
            log.info("usedMemory: " + String.format("%.2f", (usedMemory / (1024 * 1024))) + " MB");
        return joinPoint.proceed();
    }

}
  • 결과



참고

profile
배운 것을 기록합니다.

0개의 댓글