본문으로 건너뛰기
Advertisement

7.4 인터셉터와 API 로그 자동화

스프링에서 HandlerInterceptor 는 DispatcherServlet이 Controller를 호출하기 전과 후에 요청을 가로채어(Intercept) 특정 로직을 공통적으로 수행할 수 있게 해줍니다.

보통 인증(Authentication 체크)이나 범용적인 요청/응답 형식 조작, 그리고 클라이언트가 보낸 API 호출에 대한 로그 작성 에 매우 자주 사용됩니다.

HandlerInterceptor 인터페이스

인터셉터를 구현하려면 HandlerInterceptor를 상속(구현)합니다. 여기에는 세 가지 주요 메서드가 존재합니다.

  1. preHandle(): 컨트롤러 진입 전에 실행. (가장 많이 사용) false를 반환하면 메서드가 다음 단계(컨트롤러)로 넘어가지 않습니다.
  2. postHandle(): 컨트롤러 실행 후, 뷰 렌더링 전에 실행. (REST API에선 크게 빈도가 높지 않음)
  3. afterCompletion(): 모든 뷰 렌더링과 응답 전송 작업이 완전히 끝난 후 실행됩니다. 성공적으로 끝났든 예외가 발생했든 호출되기 때문에 시간 측정이나 최종 리소스 정리 등에 활용됩니다.

API 호출 로깅 인터셉터 구현 예제

요청이 들어온 시간과 URI, 그리고 요청 처리가 끝난 후 소요 시간을 측정해 로깅하는 인터셉터입니다.

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Slf4j
@Component
public class LoggingInterceptor implements HandlerInterceptor {

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 들어온 시점을 request 객체 속성(attribute)에 임시로 저장합니다.
request.setAttribute("startTime", System.currentTimeMillis());
log.info("[API Request] {} {}", request.getMethod(), request.getRequestURI());
return true;
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
long startTime = (Long) request.getAttribute("startTime");
long duration = System.currentTimeMillis() - startTime;

log.info("[API Response] {} {} - 처리 시간: {}ms, 응답 코드: {}",
request.getMethod(), request.getRequestURI(), duration, response.getStatus());

if (ex != null) {
log.error("[API Error] 예외 발생: ", ex);
}
}
}

인터셉터 등록

만들어진 인터셉터를 동작하게 하려면 스프링 컨테이너의 WebMvc 설정에 등록해줘야 합니다. WebMvcConfigurer를 구현하여 addInterceptors 메서드를 재정의합니다.

import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {

private final LoggingInterceptor loggingInterceptor;

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loggingInterceptor)
.addPathPatterns("/api/**") // 우리가 적용할 경로 패턴
.excludePathPatterns("/api/exclude"); // 로그 감시에서 제외할 패턴
}
}

이렇게 세팅해두면 이후에 컨트롤러를 수백 개 추가해도, 개발자가 일일이 System.out.println 등을 넣지 않아도 /api/ 아래의 모든 요청 및 응답 처리가 일목요연하게 로그화 되어 남게 됩니다. 이 로그는 장애 원인 분석, 속도가 느린 API의 성능 모니터링 시 매우 귀중한 자원이 됩니다.

Advertisement