somoly.tistory.com
article thumbnail

Json 통신 request 및 response 패킷 로깅을 위한 필터를 작성해 보았습니다.

@Slf4j
public class HttpLoggingFilter extends OncePerRequestFilter implements Filter {
  private static final List<MediaType> VISIBLE_TYPES = Arrays.asList(
    MediaType.APPLICATION_JSON,
    MediaType.APPLICATION_JSON_UTF8,
  );

  @Data
  private static class HttpLogData {
    private String method;
    private String uri;
    private Map<String, Collection<String>> headers = new HashMap<>();
    private String rawBody;
    private Integer status;
  }

  @SuppressWarnings("NullableProblems")
  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
    throws ServletException, IOException {
    if (isAsyncDispatch(request)) {
      filterChain.doFilter(request, response);
    } else {
      doFilterWrapped(wrapRequest(request), wrapResponse(response), filterChain);
    }
  }

  private void doFilterWrapped(ContentCachingRequestWrapper request, ContentCachingResponseWrapper response, FilterChain filterChain)
    throws ServletException, IOException {
    try {
      filterChain.doFilter(request, response);
    } finally {
      if (log.isInfoEnabled()) {
        HttpLogData req = getRequest(request);
        HttpLogData res = getResponse(request, response);
        log.info("{}", req);
        log.info("{}", res);
      }
      response.copyBodyToResponse();
    }
  }

  private HttpLogData getHttpInfo(ContentCachingRequestWrapper request) {
    var data = new HttpLogData();

    data.method = request.getMethod();

    String queryString = request.getQueryString();
    if (queryString == null) {
      data.uri = request.getRequestURI();
    } else {
      data.uri = request.getRequestURI() + "?" + queryString;
    }

    return data;
  }

  private HttpLogData getRequest(ContentCachingRequestWrapper request) {
    HttpLogData data = getHttpInfo(request);

    Collections.list(request.getHeaderNames()).forEach(headerName ->
      data.headers.put(headerName, Collections.list(request.getHeaders(headerName))));

    byte[] content = request.getContentAsByteArray();
    if (content.length > 0) {
      data.rawBody = getContentString(content, request.getContentType(), request.getCharacterEncoding());
    }

    return data;
  }

  private HttpLogData getResponse(ContentCachingRequestWrapper request, ContentCachingResponseWrapper response) {
    HttpLogData data = getHttpInfo(request);

    data.status = response.getStatus();

    response.getHeaderNames().forEach(headerName ->
      data.headers.put(headerName, response.getHeaders(headerName)));

    byte[] content = response.getContentAsByteArray();
    if (content.length > 0) {
      data.rawBody = getContentString(content, response.getContentType(), response.getCharacterEncoding());
    }

    return data;
  }

  private String getContentString(byte[] content, String contentType, String contentEncoding) {
    var mediaType = MediaType.valueOf(contentType);
    boolean visible = VISIBLE_TYPES.stream().anyMatch(visibleType -> visibleType.includes(mediaType));
    if (visible) {
      try {
        var contentString = new String(content, contentEncoding);
        if (!contentString.isBlank()) {
          try {
            var jsonObject = new JSONObject(contentString);
            return jsonObject.toString();
          } catch (JSONException e) {
          }
        }
        return contentString;
      } catch (UnsupportedEncodingException e) {
        return "";
      }
    } else {
      return "";
    }
  }

  private ContentCachingRequestWrapper wrapRequest(HttpServletRequest request) {
    if (request instanceof ContentCachingRequestWrapper) {
      return (ContentCachingRequestWrapper) request;
    } else {
      return new ContentCachingRequestWrapper(request);
    }
  }

  private ContentCachingResponseWrapper wrapResponse(HttpServletResponse response) {
    if (response instanceof ContentCachingResponseWrapper) {
      return (ContentCachingResponseWrapper) response;
    } else {
      return new ContentCachingResponseWrapper(response);
    }
  }
}

 

디펜던시 추가

<!-- lombok -->
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <optional>true</optional>
</dependency>

<!-- json -->
<dependency>
  <groupId>org.json</groupId>
  <artifactId>json</artifactId>
</dependency>

 

필터 설정 추가

@Configuration
public class FilterConfig {
  @Bean
  public FilterRegistrationBean<HttpLoggingFilter> httpLoggingFilter() {
    var registration = new FilterRegistrationBean<HttpLoggingFilter>();
    registration.setFilter(new HttpLoggingFilter());
    registration.addUrlPatterns("/api/*"); // 필터를 적용할 Url 패턴
    registration.setName("httpLoggingFilter");
    registration.setOrder(1);
    return registration;
  }
}

 

'SpringBoot' 카테고리의 다른 글

Spring 6 의 HTTP Interface  (0) 2023.03.14
Retrying Feign Calls  (0) 2023.03.14
RedisTemplate 과 Json Serializer 설정  (0) 2019.07.09
MongoDB _class 필드 제거하기  (0) 2019.07.09
404 NoHandlerFoundException 설정  (1) 2019.07.04
profile

somoly.tistory.com

@RxCats

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!