http://jira.mfd.msk:8088/browse/BKI-3215 Moved member code logging logic to MemberCodeHttpLoggingFilter; Added CachedServletInputStream; Updated CachedHttpRequestWrapper

This commit is contained in:
Mikhail Trofimov 2025-10-06 17:11:03 +03:00
parent 3b9c2eaa15
commit f950f98536
4 changed files with 99 additions and 95 deletions

View file

@ -13,18 +13,11 @@ import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper; import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper; import org.springframework.web.util.ContentCachingResponseWrapper;
import ru.nbch.credit_tracker.config.rest.wrappers.CachedHttpRequestWrapper;
import ru.nbch.credit_tracker.entities.user_request.active_packages.MonitoringActivePackagesRequest;
import ru.nbch.credit_tracker.entities.user_request.all_packages.MonitoringAllPackagesRequest;
import ru.nbch.credit_tracker.service.xml.jaxb.IXmlProcessor;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
@Component @Component
@Slf4j @Slf4j
@Order(0) @Order(0)
@ -33,12 +26,6 @@ public class HttpLoggingFilter extends OncePerRequestFilter {
private static final Set<String> SENSITIVE_HEADERS = Set.of("authorization", "cookie", "set-cookie"); private static final Set<String> SENSITIVE_HEADERS = Set.of("authorization", "cookie", "set-cookie");
private static final int MAX_BODY = 10 * 1024; private static final int MAX_BODY = 10 * 1024;
private final IXmlProcessor xmlProcessor;
public HttpLoggingFilter(IXmlProcessor xmlProcessor) {
this.xmlProcessor = xmlProcessor;
}
@Override @Override
protected boolean shouldNotFilter(HttpServletRequest request) { protected boolean shouldNotFilter(HttpServletRequest request) {
String path = request.getRequestURI(); String path = request.getRequestURI();
@ -52,7 +39,7 @@ public class HttpLoggingFilter extends OncePerRequestFilter {
long startNs = System.nanoTime(); long startNs = System.nanoTime();
HttpServletRequestWrapper req = wrapRequest(request); ContentCachingRequestWrapper req = wrapRequest(request);
ContentCachingResponseWrapper resp = new ContentCachingResponseWrapper(response); ContentCachingResponseWrapper resp = new ContentCachingResponseWrapper(response);
String correlationId = Optional.ofNullable(request.getHeader("X-Correlation-Id")) String correlationId = Optional.ofNullable(request.getHeader("X-Correlation-Id"))
@ -60,15 +47,14 @@ public class HttpLoggingFilter extends OncePerRequestFilter {
.orElse(UUID.randomUUID().toString()); .orElse(UUID.randomUUID().toString());
resp.setHeader("X-Correlation-Id", correlationId); resp.setHeader("X-Correlation-Id", correlationId);
String memberCode = parseMemberCode(req); logIncomingRequest(req, correlationId);
logIncomingRequest(req, correlationId, memberCode);
try { try {
chain.doFilter(req, resp); chain.doFilter(req, resp);
} finally { } finally {
long tookMs = (System.nanoTime() - startNs) / 1_000_000; long tookMs = (System.nanoTime() - startNs) / 1_000_000;
Map<String, String> reqParams = paramsMap(req, memberCode); Map<String, String> reqParams = paramsMap(req);
Map<String, String> reqHeaders = headersMap(req); Map<String, String> reqHeaders = headersMap(req);
Map<String, String> respHeaders = headersMap(resp); Map<String, String> respHeaders = headersMap(resp);
@ -92,46 +78,8 @@ public class HttpLoggingFilter extends OncePerRequestFilter {
} }
} }
private String parseMemberCode(HttpServletRequestWrapper req) { private void logIncomingRequest(ContentCachingRequestWrapper req, String correlationId) {
String memberCode = null; Map<String, String> reqParams = paramsMap(req);
if (!(req instanceof CachedHttpRequestWrapper)) {
return null;
}
String body = ((CachedHttpRequestWrapper) req).getBody();
if (isBlank(body)) {
return null;
}
switch (req.getRequestURI()) {
case "/api/v1/signal/active_packages":
try {
MonitoringActivePackagesRequest activePackagesRequest = xmlProcessor.read(body, MonitoringActivePackagesRequest.class);
if (activePackagesRequest != null && isNotBlank(activePackagesRequest.getUserId())) {
memberCode = activePackagesRequest.getUserId().substring(0, 6);
}
} catch (Exception e) {
memberCode = null;
}
break;
case "/api/v1/signal/all_packages":
try {
MonitoringAllPackagesRequest allPackagesRequest = xmlProcessor.read(body, MonitoringAllPackagesRequest.class);
if (allPackagesRequest != null && isNotBlank(allPackagesRequest.getUserId())) {
memberCode = allPackagesRequest.getUserId().substring(0, 6);
}
} catch (Exception e) {
memberCode = null;
}
break;
default:
break;
}
return memberCode;
}
private void logIncomingRequest(HttpServletRequestWrapper req, String correlationId, String memberCode) {
Map<String, String> reqParams = paramsMap(req, memberCode);
Map<String, String> reqHeaders = headersMap(req); Map<String, String> reqHeaders = headersMap(req);
mask(reqHeaders); mask(reqHeaders);
@ -145,13 +93,8 @@ public class HttpLoggingFilter extends OncePerRequestFilter {
); );
} }
private static HttpServletRequestWrapper wrapRequest(HttpServletRequest request) throws IOException { private static ContentCachingRequestWrapper wrapRequest(HttpServletRequest request) throws IOException {
return switch (request.getRequestURI()) { return (request instanceof ContentCachingRequestWrapper c) ? c : new ContentCachingRequestWrapper(request, MAX_BODY);
case "/api/v1/signal/active_packages", "/api/v1/signal/all_packages" ->
new CachedHttpRequestWrapper(request);
default ->
(request instanceof ContentCachingRequestWrapper c) ? c : new ContentCachingRequestWrapper(request, MAX_BODY);
};
} }
@ -160,7 +103,7 @@ public class HttpLoggingFilter extends OncePerRequestFilter {
.collect(Collectors.toMap(h -> h, req::getHeader, (a, b) -> a, LinkedHashMap::new)); .collect(Collectors.toMap(h -> h, req::getHeader, (a, b) -> a, LinkedHashMap::new));
} }
private static Map<String, String> paramsMap(HttpServletRequestWrapper req, String memberCode) { private static Map<String, String> paramsMap(HttpServletRequestWrapper req) {
Map<String, String> paramsMap = new LinkedHashMap<>(); Map<String, String> paramsMap = new LinkedHashMap<>();
req.getParameterMap().forEach((k, v) -> { req.getParameterMap().forEach((k, v) -> {
String params = String.join(", ", v); String params = String.join(", ", v);
@ -175,11 +118,6 @@ public class HttpLoggingFilter extends OncePerRequestFilter {
} catch (Exception e) { } catch (Exception e) {
// ignore // ignore
} }
if (memberCode != null) {
paramsMap.put("memberCode", memberCode);
}
return paramsMap; return paramsMap;
} }

View file

@ -0,0 +1,55 @@
package ru.nbch.credit_tracker.config.rest.filters;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import ru.nbch.credit_tracker.config.rest.wrappers.CachedHttpRequestWrapper;
import java.io.IOException;
@Component
@Slf4j
@Order(1)
public class MemberCodeHttpLoggingFilter extends OncePerRequestFilter {
@Override
protected boolean shouldNotFilter(HttpServletRequest request) {
String path = request.getRequestURI();
return !(path.startsWith("/api/v1/signal/all_packages") || path.startsWith("/api/v1/signal/active_packages"));
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
CachedHttpRequestWrapper req = wrapRequest(request);
String body = IOUtils.toString(req.getBody(), req.getCharacterEncoding());
if (StringUtils.isNotBlank(body)) {
try {
int startIndex = body.indexOf("<UserId>") + 8;
int endIndex = body.indexOf("</UserId>");
String userId = body.substring(startIndex, endIndex);
log.info(
"HTTP (REQUEST) {} {} | memberCode={}",
req.getMethod(),
req.getRequestURI(),
userId.substring(0, 6)
);
} catch (Exception e) {
// ignore
}
}
filterChain.doFilter(req, response);
}
private static CachedHttpRequestWrapper wrapRequest(HttpServletRequest request) throws IOException {
return new CachedHttpRequestWrapper(request);
}
}

View file

@ -1,47 +1,25 @@
package ru.nbch.credit_tracker.config.rest.wrappers; package ru.nbch.credit_tracker.config.rest.wrappers;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream; import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper; import jakarta.servlet.http.HttpServletRequestWrapper;
import lombok.Getter; import lombok.Getter;
import org.apache.commons.io.IOUtils;
import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
@Getter @Getter
public class CachedHttpRequestWrapper extends HttpServletRequestWrapper { public class CachedHttpRequestWrapper extends HttpServletRequestWrapper {
private final String body; private final byte[] body;
public CachedHttpRequestWrapper(HttpServletRequest request) throws IOException { public CachedHttpRequestWrapper(HttpServletRequest request) throws IOException {
super(request); super(request);
body = IOUtils.toString(request.getReader()); this.body = request.getInputStream().readAllBytes();
} }
@Override @Override
public ServletInputStream getInputStream() { public ServletInputStream getInputStream() {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(getBody().getBytes()); return new CachedServletInputStream(body);
return new ServletInputStream() {
public int read() {
return byteArrayInputStream.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
};
} }
} }

View file

@ -0,0 +1,33 @@
package ru.nbch.credit_tracker.config.rest.wrappers;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import java.io.ByteArrayInputStream;
public class CachedServletInputStream extends ServletInputStream {
private final ByteArrayInputStream byteArray;
public CachedServletInputStream(byte[] data) {
this.byteArray = new ByteArrayInputStream(data);
}
public int read() {
return byteArray.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
}