1.배달플랫폼 - filter을 이용한 log 수집

ys·2024년 3월 2일

배달플랫폼

목록 보기
2/8

로그 수집

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

Override doFilter()

  • httpServletRequestgetInputStream()한번 밖에 사용 못하므로,  ContentCachingRequestWrapperWrapper클래스를 이용해야 한다
  • 그렇지 않으면, (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);

        // request 정보
        Enumeration<String> headerNames = req.getHeaderNames();
        StringBuilder headerValues = new StringBuilder();

        headerNames.asIterator().forEachRemaining(headerKey->{
            String headerValue = req.getHeader(headerKey);

            // authorization-token : ???? , user-agent : ??? , ....형태로 들어가게 된다
            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);

        // response 정보
        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가 나가는 정보이다,
profile
개발 공부,정리

0개의 댓글