restful json request response 패킷 로깅 필터

2019. 7. 4. 14:05·SpringBoot

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
'SpringBoot' 카테고리의 다른 글
  • Retrying Feign Calls
  • RedisTemplate 과 Json Serializer 설정
  • MongoDB _class 필드 제거하기
  • 404 NoHandlerFoundException 설정
somoly
somoly
About me.
  • somoly
    somoly.tistory.com
    somoly
  • 전체
    오늘
    어제
    • 전체 (55)
      • SpringBoot (8)
      • Kotlin (5)
      • Javascript (4)
      • 백엔드 (6)
      • Linux (25)
      • Windows (1)
      • IT (2)
      • FF14 (1)
      • 애니 (1)
      • Figure (1)
      • 회사생활 (1)
  • 블로그 메뉴

    • HOME
    • TAGS
    • MEDIA
    • LOCATION
    • GUESTBOOK
    • ADMIN
    • WRITE
  • 링크

    • [FF14] 5.0 (71-80) 제작 레벨링 매크로
    • [FF14] 갈론드벨
    • [FF14] FFLogs
    • [FF14] Ariyala 장비 시뮬레이터
    • [FF14] 낚시 도우미
    • [FF14] 인테리어 정보
    • [FF14] 의상 코디 정보
  • 공지사항

  • 인기 글

  • 태그

    종료
    Kotlin
    ubuntu
    우분투
    tabulator
    설치
    VirtualBox
    Spring
    동영상
    피규어
    부팅
    linux
    utf-8
    dynamodb local
    interactive table
    versioncomapre
    string methods
    83인치
    HTTP
    P2P
    javascript
    exchage method
    30일전
    리눅스
    accesskey
    springboot
    77인치
    jvminline
    bcmod
    최후의 재림
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
somoly
restful json request response 패킷 로깅 필터
상단으로

티스토리툴바