로그 수집
- 실제 프로젝트는 코드에서 돌아가는 것이 아니라, 실질적으로 라이브 서버에서 돌아간다
- 따라서, log 수집은 매우 중요하다
- 로그를 한 곳에서 모아 중앙화해서 효과적으로 수집,분석이 가능하다
- 처음 web으로 들어가는 Filter 부분에서 로그를 처리한다
- 패키지는 상위에 두어, 다른 개발자가 보더라고 -> 이 패키지에서 filter 처리하는 것을 알 수 있게 한다
Override doFilter()

httpServletRequest의 getInputStream()은 한번 밖에 사용 못하므로, ContentCachingRequestWrapper 즉 Wrapper클래스를 이용해야 한다
- 그렇지 않으면, (java.lang.
IllegalStateException: getReader() has already been called for this request) 에러가 난다
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
ContentCachingRequestWrapper req = new ContentCachingRequestWrapper((HttpServletRequest) request);
ContentCachingResponseWrapper res = new ContentCachingResponseWrapper((HttpServletResponse) response);
chain.doFilter(req,res);
- doFilter의 request, response는 여러타입을 처리하기 위해 servlet타입이고
- 우리는 wrapper 클래스를 사용하기 위해서 생성자를 통해
ContentCachingRequestWraaper, ContentCachingResponseWrapper 로 만들어주었다
- chain.
doFilter()를 통해, Wrapper 클래스로 변환된 것을 뒤로 넘겨주면, 이제부터 뒤에서 받는 컨트롤러, 인터셉터등등 모든 request부분은 ContentCachingRequestWrapper로 래핑되어서 나가게 된다
- 또한 doFilter() 전,후로 실행 전,후가 나뉜다
doFilter() 전 : request가 들어가는 부분
doFilter() 후 : 다 돌고 response가 나가는 부분
- 가장 좋은 것은, 로그를 doFilter 전,후 모드 Header정보, Body정보를 남겨주는 것
- request에 들어올때 header,body정보를 찍을려면,
ContentCachingRequestWrapper 말고 별도의 캐싱할 클래스가 필요함...
- 이번 프로젝트에서는, 실행 후 response로 나가는 시점에 Log를 남긴다
코드
@Slf4j
@Component
public class LoggerFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
ContentCachingRequestWrapper req = new ContentCachingRequestWrapper((HttpServletRequest) request);
ContentCachingResponseWrapper res = new ContentCachingResponseWrapper((HttpServletResponse) response);
log.info("INIT URI={}",req.getRequestURI());
chain.doFilter(req,res);
Enumeration<String> headerNames = req.getHeaderNames();
StringBuilder headerValues = new StringBuilder();
headerNames.asIterator().forEachRemaining(headerKey->{
String headerValue = req.getHeader(headerKey);
headerValues
.append(headerKey)
.append(" : ")
.append(headerValue)
.append(" , ");
});
String requestBody = new String(req.getContentAsByteArray());
String uri = req.getRequestURI();
String method = req.getMethod();
log.info(">>>>> uri : {} , method : {} , header : {} , body : {}",uri,method,headerValues,requestBody);
StringBuilder responseHeaderValues = new StringBuilder();
res.getHeaderNames().forEach(headerKey -> {
String headerValue = req.getHeader(headerKey);
responseHeaderValues
.append(headerKey)
.append(" : ")
.append(headerValue)
.append(" , ");
});
String responseBody = new String(res.getContentAsByteArray());
log.info("<<<<< uri : {} , method : {} , header : {} , body : {}",uri,method,responseHeaderValues,responseBody);
res.copyBodyToResponse();
}
}
- 먼저 request부분에서
getHeaderName()을 통해 request의 header의 이름을 가져온다
- 그리고 headerValue부분을
StringBuilder로 만든다
- 가져온 이름들을에서
asIterator.forEachRemaining()을 통해 하나하나 이름의 값을 가져와,
StringBuillder에 헤더이름 : 헤더에대한 내용으로 값을 담아준다!!!
- requestBody부분은
request.getContentAsByteArray()로 가져온 후에 String으로 바꿔서 담아준다
- uri부분은
request.getRequestURI
- method부분도
request.getMethod로 가져와서
log.info(">>>>> uri : {} , method : {} , header : {} , body : {}"
, uri, method, headerValues, requestBody);
- 로 로그를 남겨준다
- response도 request와 동일하고
log.info("<<<<< uri : {} , method : {} , header : {} , body : {}"
, uri, method, responseHeaderValues, responseBody);
res.copyBodyToResponse();
- 그리고 우리가 responsebody의 내용을 읽어버렷기 때문에 , 마지막에 반드시 초기화를 해줘야 한다
- 그렇지 않으면... response-body부분이 비어져서 나가게 된다!
log 확인

- filter.Logger-Filter 우리가 만든 부분에서 로그가 잘 찍혀서 나오는 것을 알 수 있다
>>>>> : 부분이 request가 들어오는 정보이다, body는 비어있다
<<<<< : 부분이 response가 나가는 정보이다,