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] 의상 코디 정보
  • 공지사항

  • 인기 글

  • 태그

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

  • 최근 글

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

티스토리툴바