2022-08-26-TIL
2022-08-26-TIL
Today I Learned
Spring Boot Logging
Spring Boot에서 요청 단위 로그를 남기는 위치는 Filter, Interceptor, AOP 세 곳 중 하나다. 각 위치가 실행되는 순서와 차이는 6월 29일 TIL에 정리했고, 여기서는 로깅 관점에서 무엇을 볼 수 있는지로 비교한다.
| 위치 | 볼 수 있는 정보 | 로깅에 적합한 내용 |
|---|---|---|
| Filter | 서블릿 요청·응답 전체, 본문 스트림 | URL, 메서드, 상태 코드, 처리 시간, 요청·응답 본문 |
| Interceptor | 요청과 매핑된 핸들러(컨트롤러 메서드) | 어떤 컨트롤러가 처리했는지, 핸들러 단위 처리 시간 |
| AOP | 메서드 인자와 반환값, 예외 | 서비스 메서드 단위의 입력·출력, 실행 시간 |
선택 기준은 무엇을 남기고 싶은지다. HTTP 수준의 액세스 로그나 요청 본문은 Filter가 맡는다. 로깅 필터를 Spring Security 필터 체인보다 앞에 두면 인증 단계에서 거부된 요청까지 남길 수 있다. Stack Overflow 답변이 요약하듯, 함수나 클래스의 값까지 남겨야 한다면 메서드 인자와 반환값에 직접 접근할 수 있는 AOP가 맞다.
요청 본문을 Filter에서 남길 때는 주의할 점이 있다. 서블릿 요청의 입력 스트림은 한 번만 읽을 수 있어서, 로깅을 위해 먼저 읽어 버리면 컨트롤러가 본문을 받지 못한다. Spring의 ContentCachingRequestWrapper로 요청을 감싸면 읽히는 내용을 캐시해 두었다가 나중에 꺼낼 수 있다. 다만 이 래퍼는 내용이 실제로 소비되어야 캐시하므로, 체인을 통과한 뒤(filterChain.doFilter 이후)에 꺼내야 한다(ContentCachingRequestWrapper Javadoc).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
ContentCachingRequestWrapper req = new ContentCachingRequestWrapper(request);
ContentCachingResponseWrapper res = new ContentCachingResponseWrapper(response);
long start = System.currentTimeMillis();
try {
chain.doFilter(req, res);
} finally {
log.info("{} {} status={} took={}ms body={}",
req.getMethod(), req.getRequestURI(), res.getStatus(),
System.currentTimeMillis() - start,
new String(req.getContentAsByteArray(), StandardCharsets.UTF_8));
res.copyBodyToResponse();
}
}
응답 래퍼를 쓰면 마지막에 copyBodyToResponse()를 호출해야 클라이언트에게 본문이 전달된다. 개인정보나 토큰이 본문에 들어 있을 수 있으므로 실제로는 마스킹과 길이 제한이 필요하다.
- https://rollbar.com/blog/spring-boot-logging/
- https://stackoverflow.com/questions/15746676/logging-with-aop-in-spring
- https://www.baeldung.com/spring-boot-logging
- https://stackoverflow.com/questions/49467489/logginginterceptor-or-aop-logging#:~:text=Logging%20via%20LoggingInterceptor%20is%20better,values%20of%20functions%20or%20classes.
- https://koukia.ca/using-an-interceptor-for-a-cleaner-code-aop-c3c1f5e9d411
- https://programmer.ink/think/springboot-foundation-of-microservice-series-filter-interceptor-and-aop-aspect.html
- https://xzio.tistory.com/1999
- https://velog.io/@miot2j/Spring-Filter-Interceptor-AOP-%EC%B0%A8%EC%9D%B4-%EB%B0%8F-AOP%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-Logging%EC%9D%84-%EA%B5%AC%ED%98%84%ED%95%9C-%EC%9D%B4%EC%9C%A0
참고한 자료외부 출처 1
이 글은 저작권자의 CC BY 4.0 라이선스를 따릅니다.
댓글
아직 댓글이 없습니다