[TIL]2025.04.18

기 원·2025년 4월 18일

TIL - 2025.04.18

오늘 배운 것 개요

  • 내용: AOP 기반 어드민 API 접근 로깅 구현 방법 학습
  • 내용: @Around 어노테이션을 활용한 요청/응답 시점 로그 처리
  • 내용: joinPoint.getArgs()를 활용한 RequestBody 추출과 로깅 방법 확인

1. AOP 기반 어드민 접근 로깅

1. @AdminLogging 어노테이션

  • 어드민 API 접근 시 AOP 적용 대상을 명시하기 위해 사용
  • @Retention(RetentionPolicy.RUNTIME), @Target(ElementType.METHOD)으로 설정

2. AdminLogginAspect 클래스 구조

  • @Aspect, @Component로 정의
  • @Around("@annotation(...AdminLogging)")을 통해 AOP 진입
  • HttpServletRequest에서 사용자 정보(userId)와 요청 URI 추출
  • joinPoint.getArgs()를 통해 요청 파라미터(JSON 직렬화) 추출
  • joinPoint.proceed() 이후 응답 또는 예외를 처리

코드 개선

@Around("@annotation(org.example.expert.logging.AdminLogging)")
public Object logAdminAccess(ProceedingJoinPoint joinPoint) throws Throwable {
    Long userId = (Long) request.getAttribute("userId");
    String uri = request.getRequestURI();
    LocalDateTime time = LocalDateTime.now();
    String requestBody = objectMapper.writeValueAsString(joinPoint.getArgs());

    log.info("어드민 요청 - userId: {}, URI: {}, time: {}, request: {}", userId, uri, time, requestBody);

    Object result = null;
    try {
        result = joinPoint.proceed();
        return result;
    } catch (Throwable e) {
        log.warn("어드민 응답 실패 - userId: {}, URI: {}, error: {}", userId, uri, e.getMessage());
        throw e;
    } finally {
        if (result != null) {
            String responseJson = objectMapper.writeValueAsString(result);
            log.info("어드민 응답 - userId: {}, URI: {}, response: {}", userId, uri, responseJson);
        } else {
            log.info("어드민 응답 - userId: {}, URI: {}, response: 예외 발생 또는 반환값 없음");
        }
    }
}

개선된 점

  • 요청 파라미터를 통째로 JSON 직렬화하여 request에 기록
  • 응답 또는 예외 발생 여부에 따라 finally에서 로깅 분기 처리
  • 테스트에서도 요청과 응답 로그를 CapturedOutput으로 검증 가능

오늘의 결론

  1. @Around는 메서드 실행 전후를 포괄적으로 제어할 수 있는 강력한 도구
  2. joinPoint.getArgs()는 RequestBody와 PathVariable 모두 확인 가능
  3. 예외가 발생해도 finally 블록을 활용해 응답 로그를 일관되게 남길 수 있다
profile
노력하고 있다니까요?

0개의 댓글