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 |