AOP를 통해 모든 request parameter(혹은 requset body)와 response를 로그를 찍어보기로 한다.현재 컨트롤러에서 수동으로 각각의 endpoint마다 로그를 찍는 코드가 추가되어 있는데, AOP를 이용하면 좋을 것 같았다!

의존성 추가

build.gradle에 의존성을 추가해준다.

Aspect작성

aop라는 패키지를 생성하고, 패키지 하위에 LoggingAspect라는 클래스를 만들었다..

Pointcut

controller 패키지 하위의 모든 public 메서드와 매칭시킨다.@annotation을 이용하면 애노테이션별로 매칭시킬 수도 있다. @PostMapping과 매칭시켜서 POST요청에만 로그를 찍는다던지..

/* controller 패키지에 포함된 public 메서드와 매칭 */
@Pointcut("within(test.rest.api.controller..*)")
public void onRequest() { }

참고로 애노테이션으로 매칭시키는 방법이다.

// POST
@Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping)")

// GET
@Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")

Advice

Advice는 실제로 실행될 내용을 적는 부분이다.

 /* Pointcut 과 매칭되는 메서드의 실행 전, 후에 실행
 *  @Around advice 는 꼭 proceed()가 필요하다. */
@Around("onRequest()")
public Object logAction(ProceedingJoinPoint joinPoint) throws Throwable{
    Class clazz = joinPoint.getTarget().getClass();
    Logger logger = LoggerFactory.getLogger(clazz);
    Object result = null;
    try {
        result = joinPoint.proceed(joinPoint.getArgs());
        return result;
    } finally {
        logger.info(getRequestUrl(joinPoint, clazz));
        logger.info("parameters" + JSON.toJSONString(params(joinPoint)));
        logger.info("response: " + JSON.toJSONString(result, true));
    }
}

getRequestUrl()

JoinPoint와 joinPoint가 실행된 class를 이용해 요청 URI를 구한다.

HttpServletRequset를 통해 구하는 방법도 있지만, 이 방법을 택했다.