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.util.ContentCachingRequestWrapper;
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.util.*;
import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
@Component
@Slf4j
@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 int MAX_BODY = 10 * 1024;
private final IXmlProcessor xmlProcessor;
public HttpLoggingFilter(IXmlProcessor xmlProcessor) {
this.xmlProcessor = xmlProcessor;
}
@Override
protected boolean shouldNotFilter(HttpServletRequest request) {
String path = request.getRequestURI();
@ -52,7 +39,7 @@ public class HttpLoggingFilter extends OncePerRequestFilter {
long startNs = System.nanoTime();
HttpServletRequestWrapper req = wrapRequest(request);
ContentCachingRequestWrapper req = wrapRequest(request);
ContentCachingResponseWrapper resp = new ContentCachingResponseWrapper(response);
String correlationId = Optional.ofNullable(request.getHeader("X-Correlation-Id"))
@ -60,15 +47,14 @@ public class HttpLoggingFilter extends OncePerRequestFilter {
.orElse(UUID.randomUUID().toString());
resp.setHeader("X-Correlation-Id", correlationId);
String memberCode = parseMemberCode(req);
logIncomingRequest(req, correlationId, memberCode);
logIncomingRequest(req, correlationId);
try {
chain.doFilter(req, resp);
} finally {
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> respHeaders = headersMap(resp);
@ -92,46 +78,8 @@ public class HttpLoggingFilter extends OncePerRequestFilter {
}
}
private String parseMemberCode(HttpServletRequestWrapper req) {
String memberCode = null;
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);
private void logIncomingRequest(ContentCachingRequestWrapper req, String correlationId) {
Map<String, String> reqParams = paramsMap(req);
Map<String, String> reqHeaders = headersMap(req);
mask(reqHeaders);
@ -145,13 +93,8 @@ public class HttpLoggingFilter extends OncePerRequestFilter {
);
}
private static HttpServletRequestWrapper wrapRequest(HttpServletRequest request) throws IOException {
return switch (request.getRequestURI()) {
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);
};
private static ContentCachingRequestWrapper wrapRequest(HttpServletRequest request) throws IOException {
return (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));
}
private static Map<String, String> paramsMap(HttpServletRequestWrapper req, String memberCode) {
private static Map<String, String> paramsMap(HttpServletRequestWrapper req) {
Map<String, String> paramsMap = new LinkedHashMap<>();
req.getParameterMap().forEach((k, v) -> {
String params = String.join(", ", v);
@ -175,11 +118,6 @@ public class HttpLoggingFilter extends OncePerRequestFilter {
} catch (Exception e) {
// ignore
}
if (memberCode != null) {
paramsMap.put("memberCode", memberCode);
}
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;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import lombok.Getter;
import org.apache.commons.io.IOUtils;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@Getter
public class CachedHttpRequestWrapper extends HttpServletRequestWrapper {
private final String body;
private final byte[] body;
public CachedHttpRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
body = IOUtils.toString(request.getReader());
this.body = request.getInputStream().readAllBytes();
}
@Override
public ServletInputStream getInputStream() {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(getBody().getBytes());
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) {
}
};
return new CachedServletInputStream(body);
}
}

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) {
}
}