From f888f9af4ccfc5450a505aeb684539521e5f3b49 Mon Sep 17 00:00:00 2001 From: Mikhail Trofimov Date: Tue, 30 Sep 2025 14:08:42 +0300 Subject: [PATCH 01/16] http://jira.mfd.msk:8088/browse/BKI-3230 Get rid of SimpleDateFormat --- .../builder/PersonFactoryBuilder.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/nbch/credit_tracker/builder/PersonFactoryBuilder.java b/src/main/java/ru/nbch/credit_tracker/builder/PersonFactoryBuilder.java index 65f6387..2bc69dd 100644 --- a/src/main/java/ru/nbch/credit_tracker/builder/PersonFactoryBuilder.java +++ b/src/main/java/ru/nbch/credit_tracker/builder/PersonFactoryBuilder.java @@ -6,13 +6,12 @@ import ru.nbch.credit_tracker.entities.external_request.signals.Person; import ru.nbch.credit_tracker.service.indic.PersonService; import ru.nbch.credit_tracker.utils.CTUtil; -import java.text.DateFormat; -import java.text.SimpleDateFormat; import java.time.LocalDate; +import java.time.format.DateTimeFormatter; @Slf4j public class PersonFactoryBuilder { - private final static DateFormat DATE_FORMAT = new SimpleDateFormat("dd.MM.yyyy"); + private final static DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("dd.MM.yyyy"); private final static String DEFAULT_DATE = "01.01.2000"; private final static String IP = "0"; @@ -57,10 +56,10 @@ public class PersonFactoryBuilder { person.setS(nameData.getLastName()); person.setN(nameData.getFirstName()); person.setM(StringUtils.isNotBlank(nameData.getMiddleName()) ? nameData.getMiddleName() : null); - person.setD(DATE_FORMAT.format(CTUtil.localDatetoDate(nameData.getBirthDate()))); + person.setD(DATE_FORMAT.format(nameData.getBirthDate())); person.setPn(getPn(passportData.getSerNum(), passportData.getIdNum())); - person.setPd(DATE_FORMAT.format(CTUtil.localDatetoDate(LocalDate.now()))); // Do not use passport iss_date. Signal service could reject the package + person.setPd(DATE_FORMAT.format(LocalDate.now())); // Do not use passport iss_date. Signal service could reject the package person.setDt(getDt(passportData.getIdType(), passportData.getIdType2())); if (person.getDt() != null && person.getDt().equals("999")) { person.setOdt(ODT); @@ -69,12 +68,12 @@ public class PersonFactoryBuilder { person.setIp(IP); person.setUid(uid); person.setOksm(OKSM); - person.setConsentDate(DATE_FORMAT.format(CTUtil.localDatetoDate(LocalDate.now()))); + person.setConsentDate(DATE_FORMAT.format(LocalDate.now())); person.setConsentPurpose(CONSENT_PURPOSE); person.setReportUser(REPORT_USER); person.setLiability(LIABILITY); person.setConsentPeriod(CONSENT_PERIOD); - person.setAgrDate(DATE_FORMAT.format(CTUtil.localDatetoDate(LocalDate.now()))); + person.setAgrDate(DATE_FORMAT.format(LocalDate.now())); person.setReportUserRegNum(REPORT_USER_REG_NUM); person.setReportUserTaxID(REPORT_USER_TAX_ID); person.setConsentHash(CONSENT_HASH); From 98622d78177411db0e66384e2c53a4cc4c257fc8 Mon Sep 17 00:00:00 2001 From: Mikhail Trofimov Date: Tue, 30 Sep 2025 14:15:33 +0300 Subject: [PATCH 02/16] http://jira.mfd.msk:8088/browse/BKI-3215 Log http requests; Log slow mapper calls; Added spring AOP --- pom.xml | 139 ++++++++++-------- .../component/MapperTimingAspect.java | 28 ++++ .../rest/filters/HttpLoggingFilter.java | 106 +++++++++++++ src/main/resources/logback.xml | 2 +- 4 files changed, 215 insertions(+), 60 deletions(-) create mode 100644 src/main/java/ru/nbch/credit_tracker/component/MapperTimingAspect.java create mode 100644 src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java diff --git a/pom.xml b/pom.xml index f876eb6..ffd17aa 100644 --- a/pom.xml +++ b/pom.xml @@ -27,6 +27,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-aop + org.mybatis.spring.boot mybatis-spring-boot-starter @@ -122,8 +126,83 @@ 3.0.4 test + + org.mockito + mockito-junit-jupiter + test + + + + docker-push-dev + + + + + io.fabric8 + docker-maven-plugin + 0.45.0 + + + Build and deploy docker container + install + + + push + + + + + + + ${project.artifactId}:${project.version} + ${registry.url} + + ${project.basedir}/Dockerfile + + + + + ${project.build.directory}/${project.build.finalName}.jar + . + + + ${project.basedir}/apm-agent/elastic-apm-agent-1.45.0.jar + . + + + ${project.basedir}/start-credit-tracker.sh + . + + + ${project.basedir}/credit-tracker.properties + . + + + ${project.basedir}/monitoring-request.xsd + . + + + ${project.basedir}/signal-package.xsd + . + + + + + + ${project.version} + + + + + + + + + + + credit-tracker @@ -181,65 +260,7 @@ - - io.fabric8 - docker-maven-plugin - 0.45.0 - - - Build and deploy docker container - install - - build - push - - - - - - - ${project.artifactId}:${project.version} - ${registry.url} - - ${project.basedir}/Dockerfile - - - - - ${project.build.directory}/${project.build.finalName}.jar - . - - - ${project.basedir}/apm-agent/elastic-apm-agent-1.45.0.jar - . - - - ${project.basedir}/start-credit-tracker.sh - . - - - ${project.basedir}/credit-tracker.properties - . - - - ${project.basedir}/monitoring-request.xsd - . - - - ${project.basedir}/signal-package.xsd - . - - - - - - ${project.version} - - - - - - + diff --git a/src/main/java/ru/nbch/credit_tracker/component/MapperTimingAspect.java b/src/main/java/ru/nbch/credit_tracker/component/MapperTimingAspect.java new file mode 100644 index 0000000..7802484 --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/component/MapperTimingAspect.java @@ -0,0 +1,28 @@ +package ru.nbch.credit_tracker.component; + +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.stereotype.Component; + +@Aspect +@Slf4j +@Component +public class MapperTimingAspect { + @Around("within(@org.apache.ibatis.annotations.Mapper *)") + public Object timeMapper(ProceedingJoinPoint pjp) throws Throwable { + long start = System.nanoTime(); + try { + return pjp.proceed(); + } finally { + long tookMs = (System.nanoTime() - start) / 1_000_000; + String method = pjp.getSignature().toShortString(); + if (tookMs > 200) { + log.warn("Slow mapper call {} took {} ms", method, tookMs); + } else { + log.debug("Mapper call {} took {} ms", method, tookMs); + } + } + } +} diff --git a/src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java b/src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java new file mode 100644 index 0000000..262a9d2 --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java @@ -0,0 +1,106 @@ +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.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.OncePerRequestFilter; +import org.springframework.web.util.ContentCachingRequestWrapper; +import org.springframework.web.util.ContentCachingResponseWrapper; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.stream.Collectors; + +@Component +@Slf4j +@Order(0) +public class HttpLoggingFilter extends OncePerRequestFilter { + + private static final Set SENSITIVE_HEADERS = Set.of("authorization", "cookie", "set-cookie"); + private static final int MAX_BODY = 10 * 1024; + + @Override + protected boolean shouldNotFilter(HttpServletRequest request) { + String path = request.getRequestURI(); + return path.startsWith("/actuator/health") || path.startsWith("/swagger") + || path.startsWith("/v3/api-docs") || path.startsWith("/static/"); + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) + throws ServletException, IOException { + + long startNs = System.nanoTime(); + + ContentCachingRequestWrapper req = wrapRequest(request); + ContentCachingResponseWrapper resp = new ContentCachingResponseWrapper(response); + + String correlationId = Optional.ofNullable(request.getHeader("X-Correlation-Id")) + .filter(StringUtils::hasText) + .orElse(UUID.randomUUID().toString()); + resp.setHeader("X-Correlation-Id", correlationId); + + try { + chain.doFilter(req, resp); + } finally { + long tookMs = (System.nanoTime() - startNs) / 1_000_000; + + String requestBody = readBody(req.getContentAsByteArray(), req.getCharacterEncoding()); + String responseBody = readBody(resp.getContentAsByteArray(), resp.getCharacterEncoding()); + + Map reqHeaders = headersMap(req); + Map respHeaders = headersMap(resp); + + mask(reqHeaders); + mask(respHeaders); + + log.info( + "HTTP {} {}{} | status={} | took={}ms | cid={} | reqHeaders={} | reqBody={} | respHeaders={} | respBody={}", + req.getMethod(), + req.getRequestURI(), + req.getQueryString() == null ? "" : "?" + req.getQueryString(), + resp.getStatus(), + tookMs, + correlationId, + reqHeaders, + requestBody, + respHeaders, + responseBody + ); + + resp.copyBodyToResponse(); + } + } + + private static ContentCachingRequestWrapper wrapRequest(HttpServletRequest request) { + return (request instanceof ContentCachingRequestWrapper c) ? c : new ContentCachingRequestWrapper(request, MAX_BODY); + } + + private static String readBody(byte[] buf, String encoding) { + if (buf == null || buf.length == 0) return ""; + var bytes = buf.length > MAX_BODY ? Arrays.copyOf(buf, MAX_BODY) : buf; + String body = new String(bytes, encoding != null ? java.nio.charset.Charset.forName(encoding) : StandardCharsets.UTF_8); + if (buf.length > MAX_BODY) body += "…[truncated]"; + return body; + } + + private static Map headersMap(HttpServletRequest req) { + return Collections.list(req.getHeaderNames()).stream() + .collect(Collectors.toMap(h -> h, req::getHeader, (a, b) -> a, LinkedHashMap::new)); + } + + private static Map headersMap(HttpServletResponse resp) { + return resp.getHeaderNames().stream() + .collect(Collectors.toMap(h -> h, resp::getHeader, (a, b) -> a, LinkedHashMap::new)); + } + + private static void mask(Map headers) { + headers.replaceAll((k, v) -> SENSITIVE_HEADERS.contains(k.toLowerCase()) ? "***" : v); + } +} diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 0825d76..88ce91c 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -8,7 +8,7 @@ - %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n utf-8 From 2c3b2822c20e31e6e4f629d693c1612200bd1e74 Mon Sep 17 00:00:00 2001 From: Mikhail Trofimov Date: Tue, 30 Sep 2025 14:20:45 +0300 Subject: [PATCH 03/16] http://jira.mfd.msk:8088/browse/BKI-3215 Moved SignalServerException logs to GlobalExceptionHandler; Added warn logs to GlobalExceptionHandler for SignalClientException --- .../component/MapperTimingAspect.java | 2 +- .../config/rest/GlobalExceptionHandler.java | 11 +++++- .../credit_tracker/enums/SignalError.java | 4 +-- .../exceptions/SignalServerException.java | 7 +++- .../credit_tracker/facade/SignalFacade.java | 34 ++++++------------- .../credit_tracker/utils/ValidationUtil.java | 32 +++++++++-------- .../utils/error/ExceptionUtils.java | 4 +-- 7 files changed, 48 insertions(+), 46 deletions(-) diff --git a/src/main/java/ru/nbch/credit_tracker/component/MapperTimingAspect.java b/src/main/java/ru/nbch/credit_tracker/component/MapperTimingAspect.java index 7802484..05902b2 100644 --- a/src/main/java/ru/nbch/credit_tracker/component/MapperTimingAspect.java +++ b/src/main/java/ru/nbch/credit_tracker/component/MapperTimingAspect.java @@ -18,7 +18,7 @@ public class MapperTimingAspect { } finally { long tookMs = (System.nanoTime() - start) / 1_000_000; String method = pjp.getSignature().toShortString(); - if (tookMs > 200) { + if (tookMs > 1000) { log.warn("Slow mapper call {} took {} ms", method, tookMs); } else { log.debug("Mapper call {} took {} ms", method, tookMs); diff --git a/src/main/java/ru/nbch/credit_tracker/config/rest/GlobalExceptionHandler.java b/src/main/java/ru/nbch/credit_tracker/config/rest/GlobalExceptionHandler.java index 4ce54fe..b0824b1 100644 --- a/src/main/java/ru/nbch/credit_tracker/config/rest/GlobalExceptionHandler.java +++ b/src/main/java/ru/nbch/credit_tracker/config/rest/GlobalExceptionHandler.java @@ -1,5 +1,6 @@ package ru.nbch.credit_tracker.config.rest; +import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -12,10 +13,12 @@ import ru.nbch.credit_tracker.entities.user_response.errors.*; import ru.nbch.credit_tracker.enums.SignalError; import ru.nbch.credit_tracker.exceptions.SignalClientException; import ru.nbch.credit_tracker.exceptions.SignalException; +import ru.nbch.credit_tracker.exceptions.SignalServerException; import ru.nbch.credit_tracker.utils.error.SimpleMessageResolver; import java.nio.charset.Charset; +@Slf4j @RestControllerAdvice public class GlobalExceptionHandler { @@ -43,14 +46,20 @@ public class GlobalExceptionHandler { public ResponseEntity handleClientException(SignalException ex) { HttpHeaders headers = new HttpHeaders(); headers.setContentType(new MediaType("application", "xml", Charset.forName(encoding))); + + String errorText = messageResolver.resolve(ex.getErrorMessage()); + CommonError commonError = getCommonError(ex); commonError.setStatus("error"); commonError.setErrorCode(ex.getErrorMessage().getSubject().getCode()); - commonError.setErrorText(messageResolver.resolve(ex.getErrorMessage())); + commonError.setErrorText(errorText); if (ex instanceof SignalClientException) { + log.warn("Response error: {}", errorText); return new ResponseEntity<>(commonError, headers, HttpStatus.BAD_REQUEST); } else { + Exception cause = ((SignalServerException) ex).getCause(); + log.error(cause.getMessage(), cause); return new ResponseEntity<>(commonError, headers, HttpStatus.INTERNAL_SERVER_ERROR); } } diff --git a/src/main/java/ru/nbch/credit_tracker/enums/SignalError.java b/src/main/java/ru/nbch/credit_tracker/enums/SignalError.java index 30f5e4c..ea68795 100644 --- a/src/main/java/ru/nbch/credit_tracker/enums/SignalError.java +++ b/src/main/java/ru/nbch/credit_tracker/enums/SignalError.java @@ -3,13 +3,13 @@ package ru.nbch.credit_tracker.enums; public enum SignalError implements IEnumKeyCode { ERROR_001("001", "Ошибка распаковки архива"), ERROR_002("002", "Отсутствует обязательный элемент: {}"), - ERROR_003("003", "Элемент ClientId не соответствует формату XXXXXXXXX"), + ERROR_003("003", "Элемент ClientId не соответствует формату XXXXXXXXX. Id: {}"), ERROR_005("005", "Неверный логин или пароль"), ERROR_006("006", "Доступ к услуге закрыт, обратитесь к курирующему менеджеру"), ERROR_007("007", "В системе уже существует пакет с таким именем"), ERROR_008("008", "PackageName не соответствует допустимому формату"), ERROR_009("009", "Превышен допустимый размер пакета"), - ERROR_010("010", "Идентификатор субъекта (Id) не соответствует допустимому формату"), + ERROR_010("010", "Идентификатор субъекта (Id) не соответствует допустимому формату: {}"), ERROR_011("011", "Получен невалидный XML"), ERROR_012("012", "Пакет {} не найден"), ERROR_013("013", "На стороне сервиса произошла ошибка, попробуйте повторить запрос позже или сообщите в техническую поддержку"), diff --git a/src/main/java/ru/nbch/credit_tracker/exceptions/SignalServerException.java b/src/main/java/ru/nbch/credit_tracker/exceptions/SignalServerException.java index 46dd713..dc1ef29 100644 --- a/src/main/java/ru/nbch/credit_tracker/exceptions/SignalServerException.java +++ b/src/main/java/ru/nbch/credit_tracker/exceptions/SignalServerException.java @@ -1,12 +1,17 @@ package ru.nbch.credit_tracker.exceptions; +import lombok.Getter; import ru.nbch.credit_tracker.enums.EnumKeyMessage; import ru.nbch.credit_tracker.enums.XmlErrorFormat; +@Getter public class SignalServerException extends SignalException { - public SignalServerException(EnumKeyMessage errorMessage, XmlErrorFormat errorFormat) { + private final Exception cause; + + public SignalServerException(EnumKeyMessage errorMessage, XmlErrorFormat errorFormat, Exception cause) { super(errorMessage, errorFormat); + this.cause = cause; } } diff --git a/src/main/java/ru/nbch/credit_tracker/facade/SignalFacade.java b/src/main/java/ru/nbch/credit_tracker/facade/SignalFacade.java index 218a1c8..ea6121d 100644 --- a/src/main/java/ru/nbch/credit_tracker/facade/SignalFacade.java +++ b/src/main/java/ru/nbch/credit_tracker/facade/SignalFacade.java @@ -109,21 +109,17 @@ public class SignalFacade { zipInputStream.getNextEntry(); filePath = writeTmpFile(zipInputStream); - if (filePath == null) { - throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError); - } } catch (Exception e) { if (e instanceof SignalClientException) { throw (SignalClientException) e; } - log.error(e.getMessage(), e); - throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError); + throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError, e); } finally { if (zipInputStream != null) { try { zipInputStream.close(); } catch (IOException e) { - throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError); + throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError, e); } } } @@ -140,8 +136,7 @@ public class SignalFacade { if (e instanceof SignalClientException) { throw (SignalClientException) e; } - log.error(e.getMessage(), e); - throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError); + throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError, e); } try { @@ -165,8 +160,7 @@ public class SignalFacade { if (e instanceof SignalClientException) { throw (SignalClientException) e; } - log.error(e.getMessage(), e); - throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError); + throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError, e); } // в отдельном потоке запускаем регистрацию субъектов, поиск фидов и расчет флагов просрочек @@ -200,7 +194,7 @@ public class SignalFacade { return monitoringRequest; } - private String writeTmpFile(ZipInputStream zipInputStream) { + private String writeTmpFile(ZipInputStream zipInputStream) throws IOException { String folderPath = config.getLoadDir() + File.separator + "tmp_folder" + File.separator; String filePath = folderPath + UUID.randomUUID() + "monitoring_request.xml"; CTUtil.createFolder(folderPath); @@ -214,9 +208,6 @@ public class SignalFacade { } return filePath; - } catch (Exception e) { - log.error("Ошибка при записи файла запроса постановки на мониторинг на диск", e); - return null; } } @@ -281,8 +272,7 @@ public class SignalFacade { if (e instanceof SignalClientException) { throw (SignalClientException) e; } - log.error(e.getMessage(), e); - throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringActivePackagesError); + throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringActivePackagesError, e); } } @@ -318,8 +308,7 @@ public class SignalFacade { if (e instanceof SignalClientException) { throw (SignalClientException) e; } - log.error(e.getMessage(), e); - throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringActivePackagesError); + throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringActivePackagesError, e); } } @@ -344,8 +333,7 @@ public class SignalFacade { if (e instanceof SignalClientException) { throw (SignalClientException) e; } - log.error(e.getMessage(), e); - throw serverExcp(SignalError.ERROR_017, XmlErrorFormat.MonitoringPackageDeleteError); + throw serverExcp(SignalError.ERROR_017, XmlErrorFormat.MonitoringPackageDeleteError, e); } } @@ -391,8 +379,7 @@ public class SignalFacade { if (e instanceof SignalClientException) { throw (SignalClientException) e; } - log.error(e.getMessage(), e); - throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringReportListError); + throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringReportListError, e); } } @@ -418,8 +405,7 @@ public class SignalFacade { if (e instanceof SignalClientException) { throw (SignalClientException) e; } - log.error(e.getMessage(), e); - throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringDownloadError); + throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringDownloadError, e); } } } diff --git a/src/main/java/ru/nbch/credit_tracker/utils/ValidationUtil.java b/src/main/java/ru/nbch/credit_tracker/utils/ValidationUtil.java index d0068b2..4885a27 100644 --- a/src/main/java/ru/nbch/credit_tracker/utils/ValidationUtil.java +++ b/src/main/java/ru/nbch/credit_tracker/utils/ValidationUtil.java @@ -1,5 +1,6 @@ package ru.nbch.credit_tracker.utils; +import lombok.extern.slf4j.Slf4j; import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest; import ru.nbch.credit_tracker.entities.user_request.monitoring_request.Subject; import ru.nbch.credit_tracker.enums.SignalError; @@ -10,25 +11,30 @@ import java.util.regex.Pattern; import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.clientExcp; +@Slf4j public class ValidationUtil { - private static String phoneRegex = "^\\d{9}$"; - private static String packageNameRegex = "^[A-Z0-9_]{1,22}$"; - private static String npIdRegex = "^\\S{1,36}$"; + private static final String phoneRegex = "^\\d{9}$"; + private static final String packageNameRegex = "^[A-Z0-9_]{1,22}$"; + private static final String npIdRegex = "^\\S{1,36}$"; public static void validateMonitoringRequest(MonitoringRequest request) throws SignalClientException { if (request == null) { throw clientExcp(SignalError.ERROR_011, XmlErrorFormat.MonitoringError); } - if (request.getUserId() == null) { - throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "UserId"); - } - if (request.getPackageName() == null) { throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "PackageName"); } + if (!validatePackageName(request.getPackageName())) { + throw clientExcp(SignalError.ERROR_008, XmlErrorFormat.MonitoringError); + } + + if (request.getUserId() == null) { + throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "UserId"); + } + if (request.getPassword() == null) { throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "Password"); } @@ -41,16 +47,12 @@ public class ValidationUtil { throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "Subject"); } - if (!validatePackageName(request.getPackageName())) { - throw clientExcp(SignalError.ERROR_008, XmlErrorFormat.MonitoringError); - } - for (Subject subject : request.getSubjects().getSubject()) { - if (!validatePhone(subject.getClientId())) { - throw clientExcp(SignalError.ERROR_003, XmlErrorFormat.MonitoringError); - } if (!validateNPId(subject.getId())) { - throw clientExcp(SignalError.ERROR_010, XmlErrorFormat.MonitoringError); + throw clientExcp(SignalError.ERROR_010, XmlErrorFormat.MonitoringError, subject.getId()); + } + if (!validatePhone(subject.getClientId())) { + throw clientExcp(SignalError.ERROR_003, XmlErrorFormat.MonitoringError, subject.getId()); } } } diff --git a/src/main/java/ru/nbch/credit_tracker/utils/error/ExceptionUtils.java b/src/main/java/ru/nbch/credit_tracker/utils/error/ExceptionUtils.java index a15457c..2e94e78 100644 --- a/src/main/java/ru/nbch/credit_tracker/utils/error/ExceptionUtils.java +++ b/src/main/java/ru/nbch/credit_tracker/utils/error/ExceptionUtils.java @@ -12,7 +12,7 @@ public class ExceptionUtils { return new SignalClientException(new EnumKeyMessage(enumKeyCode, args), xmlErrorFormat); } - public static SignalServerException serverExcp(IEnumKeyCode enumKeyCode, XmlErrorFormat xmlErrorFormat, Object... args) { - return new SignalServerException(new EnumKeyMessage(enumKeyCode, args), xmlErrorFormat); + public static SignalServerException serverExcp(IEnumKeyCode enumKeyCode, XmlErrorFormat xmlErrorFormat, Exception cause, Object... args) { + return new SignalServerException(new EnumKeyMessage(enumKeyCode, args), xmlErrorFormat, cause); } } From 061c24b89c9d595aeaf1000ab4a55660355f3dd9 Mon Sep 17 00:00:00 2001 From: Mikhail Trofimov Date: Tue, 30 Sep 2025 14:35:21 +0300 Subject: [PATCH 04/16] http://jira.mfd.msk:8088/browse/BKI-3215 Changed log lvl to warn for error checking; Added SetAndClearMdc annotation for packageName logging --- .../config/mdc/AopMdcConfig.java | 19 +++++++ .../credit_tracker/config/mdc/MdcAspect.java | 49 +++++++++++++++++++ .../config/mdc/SetAndClearMdc.java | 15 ++++++ .../credit_tracker/service/SignalService.java | 2 +- src/main/resources/logback.xml | 4 +- .../utils/ValidationUtilTest.java | 4 +- 6 files changed, 88 insertions(+), 5 deletions(-) create mode 100644 src/main/java/ru/nbch/credit_tracker/config/mdc/AopMdcConfig.java create mode 100644 src/main/java/ru/nbch/credit_tracker/config/mdc/MdcAspect.java create mode 100644 src/main/java/ru/nbch/credit_tracker/config/mdc/SetAndClearMdc.java diff --git a/src/main/java/ru/nbch/credit_tracker/config/mdc/AopMdcConfig.java b/src/main/java/ru/nbch/credit_tracker/config/mdc/AopMdcConfig.java new file mode 100644 index 0000000..1cfbbf1 --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/config/mdc/AopMdcConfig.java @@ -0,0 +1,19 @@ +package ru.nbch.credit_tracker.config.mdc; + +import org.aspectj.lang.annotation.Aspect; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.EnableAspectJAutoProxy; + +@Configuration +@ConditionalOnClass(Aspect.class) +@EnableAspectJAutoProxy(proxyTargetClass = true) +public class AopMdcConfig { + + @Bean + public MdcAspect mdcAspect() { + return new MdcAspect(); + } + +} diff --git a/src/main/java/ru/nbch/credit_tracker/config/mdc/MdcAspect.java b/src/main/java/ru/nbch/credit_tracker/config/mdc/MdcAspect.java new file mode 100644 index 0000000..3bcbddd --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/config/mdc/MdcAspect.java @@ -0,0 +1,49 @@ +package ru.nbch.credit_tracker.config.mdc; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.slf4j.MDC; +import ru.nbch.credit_tracker.entities.dto.UserPackage; +import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest; + +@Slf4j +@Aspect +public class MdcAspect { + + // For methods that set an MDC value (from a method argument) and then clear it at the end + @Around("@annotation(setAndClearMdc)") + public Object setAndClearMdcAdvice(ProceedingJoinPoint pjp, SetAndClearMdc setAndClearMdc) throws Throwable { + Object[] args = pjp.getArgs(); + int index = setAndClearMdc.argIndex(); + Object obj = (args != null && args.length > index) ? args[index] : null; + if (obj instanceof MonitoringRequest request) { + if (request.getPackageName() != null) { + putMdcValue(request.getPackageName(), setAndClearMdc.key()); + } + } else if (obj instanceof UserPackage userPackage) { + if (userPackage.getPackageName() != null) { + putMdcValue(userPackage.getPackageName(), setAndClearMdc.key()); + } + } else if (obj instanceof String packageName) { + putMdcValue(setAndClearMdc.key(), packageName); + } else { + log.debug("no packageName found for for {}", pjp.toShortString()); + } + try { + return pjp.proceed(); + } finally { + MDC.remove(setAndClearMdc.key()); + } + } + + private void putMdcValue(String value, String key) { + try { + MDC.put(key, "[" + value + "] "); + } catch (Throwable e) { + log.error("{}", ExceptionUtils.getStackTrace(e)); + } + } +} diff --git a/src/main/java/ru/nbch/credit_tracker/config/mdc/SetAndClearMdc.java b/src/main/java/ru/nbch/credit_tracker/config/mdc/SetAndClearMdc.java new file mode 100644 index 0000000..8d8a14a --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/config/mdc/SetAndClearMdc.java @@ -0,0 +1,15 @@ +package ru.nbch.credit_tracker.config.mdc; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +// Annotation to set an MDC key based on a method argument and clear it after method execution +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface SetAndClearMdc { + String key() default "ru.nbch.credit_tracker.log.mdc.key"; + // The index of the method argument to use for the MDC value (defaults to the first argument) + int argIndex() default 0; +} diff --git a/src/main/java/ru/nbch/credit_tracker/service/SignalService.java b/src/main/java/ru/nbch/credit_tracker/service/SignalService.java index 138a075..aa7d910 100644 --- a/src/main/java/ru/nbch/credit_tracker/service/SignalService.java +++ b/src/main/java/ru/nbch/credit_tracker/service/SignalService.java @@ -285,7 +285,7 @@ public class SignalService { request -> { if (!request.getPersons().isEmpty()) { List subjects = request.getPersons().stream().map(p -> { - log.error("Ошибка при формировании субъекта. package_id = {}, id = {}. Описание: {}", packageId, p.getUid(), p.getValue()); + log.warn("Ошибка при формировании субъекта. package_id = {}, id = {}. Описание: {}", packageId, p.getUid(), p.getValue()); return PhoneFidMap.builder() .id(p.getUid()) .errorText(p.getValue()) diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 88ce91c..ff8f347 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -8,7 +8,7 @@ - %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} %X{ru.nbch.credit_tracker.log.mdc.key} - %msg%n utf-8 @@ -22,7 +22,7 @@ 100MB - %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} %X{ru.nbch.credit_tracker.log.mdc.key} - %msg%n utf-8 diff --git a/src/test/java/ru/nbch/credit_tracker/utils/ValidationUtilTest.java b/src/test/java/ru/nbch/credit_tracker/utils/ValidationUtilTest.java index b8146f3..aea414b 100644 --- a/src/test/java/ru/nbch/credit_tracker/utils/ValidationUtilTest.java +++ b/src/test/java/ru/nbch/credit_tracker/utils/ValidationUtilTest.java @@ -69,12 +69,12 @@ public class ValidationUtilTest { Arguments.of( "/monitoring_request/invalid_phone_request.zip", SignalError.ERROR_003, - Collections.emptyList().toArray(new Object[0]) + new Object[]{"abc123"} ), Arguments.of( "/monitoring_request/invalid_id_request.zip", SignalError.ERROR_010, - Collections.emptyList().toArray(new Object[0]) + new Object[]{"#####"} ) ); } From e6bf35f337887943faf8ce2c3a0f99c1310d6fa5 Mon Sep 17 00:00:00 2001 From: Mikhail Trofimov Date: Tue, 30 Sep 2025 16:20:24 +0300 Subject: [PATCH 05/16] http://jira.mfd.msk:8088/browse/BKI-3215 Use MDC for monitoring, updating flags, setup monitoring; Update ValidationUtil to a service --- .../credit_tracker/config/mdc/MdcAspect.java | 6 +- .../credit_tracker/facade/SignalFacade.java | 32 +++- .../MonitoringErrorProcesingService.java | 18 ++ .../service/MonitoringService.java | 155 +++++++++--------- .../UpdateProcessingPackagesService.java | 24 ++- .../service/UpdatingFlagsService.java | 3 + ...dationUtil.java => ValidationService.java} | 8 +- ...ilTest.java => ValidationServiceTest.java} | 16 +- 8 files changed, 170 insertions(+), 92 deletions(-) rename src/main/java/ru/nbch/credit_tracker/utils/{ValidationUtil.java => ValidationService.java} (91%) rename src/test/java/ru/nbch/credit_tracker/utils/{ValidationUtilTest.java => ValidationServiceTest.java} (88%) diff --git a/src/main/java/ru/nbch/credit_tracker/config/mdc/MdcAspect.java b/src/main/java/ru/nbch/credit_tracker/config/mdc/MdcAspect.java index 3bcbddd..798f398 100644 --- a/src/main/java/ru/nbch/credit_tracker/config/mdc/MdcAspect.java +++ b/src/main/java/ru/nbch/credit_tracker/config/mdc/MdcAspect.java @@ -21,11 +21,11 @@ public class MdcAspect { Object obj = (args != null && args.length > index) ? args[index] : null; if (obj instanceof MonitoringRequest request) { if (request.getPackageName() != null) { - putMdcValue(request.getPackageName(), setAndClearMdc.key()); + putMdcValue(setAndClearMdc.key(), request.getPackageName()); } } else if (obj instanceof UserPackage userPackage) { if (userPackage.getPackageName() != null) { - putMdcValue(userPackage.getPackageName(), setAndClearMdc.key()); + putMdcValue(setAndClearMdc.key(), userPackage.getPackageName()); } } else if (obj instanceof String packageName) { putMdcValue(setAndClearMdc.key(), packageName); @@ -39,7 +39,7 @@ public class MdcAspect { } } - private void putMdcValue(String value, String key) { + private void putMdcValue(String key, String value) { try { MDC.put(key, "[" + value + "] "); } catch (Throwable e) { diff --git a/src/main/java/ru/nbch/credit_tracker/facade/SignalFacade.java b/src/main/java/ru/nbch/credit_tracker/facade/SignalFacade.java index ea6121d..81a1802 100644 --- a/src/main/java/ru/nbch/credit_tracker/facade/SignalFacade.java +++ b/src/main/java/ru/nbch/credit_tracker/facade/SignalFacade.java @@ -1,12 +1,16 @@ package ru.nbch.credit_tracker.facade; import lombok.extern.slf4j.Slf4j; +import org.slf4j.MDC; +import org.springframework.aop.framework.AopContext; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.core.io.FileUrlResource; import org.springframework.core.io.Resource; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; +import ru.nbch.credit_tracker.config.mdc.SetAndClearMdc; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; import ru.nbch.credit_tracker.entities.dto.UserPackage; import ru.nbch.credit_tracker.entities.user_request.active_packages.MonitoringActivePackagesRequest; @@ -31,7 +35,7 @@ import ru.nbch.credit_tracker.service.scoring.AuthorizationService; import ru.nbch.credit_tracker.service.signal.SignalRestService; import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor; import ru.nbch.credit_tracker.utils.CTUtil; -import ru.nbch.credit_tracker.utils.ValidationUtil; +import ru.nbch.credit_tracker.utils.ValidationService; import ru.nbch.credit_tracker.utils.ZipUtils; import javax.xml.stream.XMLStreamException; @@ -43,6 +47,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.time.LocalDateTime; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.UUID; import java.util.concurrent.ExecutorService; @@ -54,12 +59,17 @@ import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.serverExcp; @Slf4j @Service +@EnableAspectJAutoProxy(exposeProxy = true) public class SignalFacade { + + private SignalFacade self; + private final CreditTrackerSettings config; private final AuthorizationService authorizationService; private final SignalService signalService; private final SignalRestService signalRestService; private final MonitoringErrorProcesingService monitoringErrorProcesingService; + private final ValidationService validationService; private final StaxXmlProcessor staxXmlProcessor; private final ExecutorService executor; @@ -71,6 +81,7 @@ public class SignalFacade { SignalService signalService, SignalRestService signalRestService, MonitoringErrorProcesingService monitoringErrorProcesingService, + ValidationService validationService, StaxXmlProcessor staxXmlProcessor, @Qualifier("executorService") ExecutorService executor) { this.config = config; @@ -78,6 +89,7 @@ public class SignalFacade { this.signalService = signalService; this.signalRestService = signalRestService; this.monitoringErrorProcesingService = monitoringErrorProcesingService; + this.validationService = validationService; this.staxXmlProcessor = staxXmlProcessor; this.executor = executor; this.maxXmlFileSize = config.getMaxXmlFileSize() * 1024 * 1024; @@ -164,7 +176,7 @@ public class SignalFacade { } // в отдельном потоке запускаем регистрацию субъектов, поиск фидов и расчет флагов просрочек - registerFidsAndDebts(packageId, monitoringRequest.getPackageName(), filePath); + getCurrentProxy().registerFidsAndDebts(packageId, monitoringRequest.getPackageName(), filePath); return ResponseEntity.ok().body(new MonitoringSetupResponse()); } @@ -175,7 +187,7 @@ public class SignalFacade { monitoringRequest = staxXmlProcessor.read(in, MonitoringRequest.class, request -> { try { - ValidationUtil.validateMonitoringRequest(request); + validationService.validateMonitoringRequest(request); } catch (SignalClientException e) { if (request != null) { signalService.rejectPackage(request); @@ -211,8 +223,13 @@ public class SignalFacade { } } - private void registerFidsAndDebts(Integer packageId, String packageName, String filePath) { + @SetAndClearMdc(argIndex = 1) + public void registerFidsAndDebts(Integer packageId, String packageName, String filePath) { + Map context = MDC.getCopyOfContextMap(); executor.execute(() -> { + if (context != null) { + MDC.setContextMap(context); + } try { signalService.registerSubjects(filePath, packageId); CTUtil.removeFile(filePath); @@ -408,4 +425,11 @@ public class SignalFacade { throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringDownloadError, e); } } + + private SignalFacade getCurrentProxy() { + if (self == null) { + self = (SignalFacade) AopContext.currentProxy(); + } + return self; + } } diff --git a/src/main/java/ru/nbch/credit_tracker/service/MonitoringErrorProcesingService.java b/src/main/java/ru/nbch/credit_tracker/service/MonitoringErrorProcesingService.java index 1d68f97..74bd9d1 100644 --- a/src/main/java/ru/nbch/credit_tracker/service/MonitoringErrorProcesingService.java +++ b/src/main/java/ru/nbch/credit_tracker/service/MonitoringErrorProcesingService.java @@ -2,15 +2,21 @@ package ru.nbch.credit_tracker.service; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.springframework.aop.framework.AopContext; +import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.stereotype.Service; +import ru.nbch.credit_tracker.config.mdc.SetAndClearMdc; import ru.nbch.credit_tracker.entities.dto.UserPackage; import ru.nbch.credit_tracker.service.signal.SignalRestService; import ru.nbch.credit_tracker.utils.CTUtil; @Slf4j @Service +@EnableAspectJAutoProxy(exposeProxy = true) public class MonitoringErrorProcesingService { + private MonitoringErrorProcesingService self; + private final SignalService signalService; private final SignalRestService signalRestService; @@ -21,6 +27,11 @@ public class MonitoringErrorProcesingService { public void findErrors(Integer packageId) { UserPackage userPackage = signalService.findPackage(packageId); + getCurrentProxy().processPackage(userPackage, packageId); + } + + @SetAndClearMdc + public void processPackage(UserPackage userPackage, Integer packageId) { if (userPackage != null) { String packCode = userPackage.getUserId().substring(0, 6) + "_" + userPackage.getPackageName(); log.info("Проверка на ошибки при постановке на мониторинг. packCode={}, packageId={}", packCode, packageId); @@ -38,4 +49,11 @@ public class MonitoringErrorProcesingService { } } } + + private MonitoringErrorProcesingService getCurrentProxy() { + if (self == null) { + self = (MonitoringErrorProcesingService) AopContext.currentProxy(); + } + return self; + } } diff --git a/src/main/java/ru/nbch/credit_tracker/service/MonitoringService.java b/src/main/java/ru/nbch/credit_tracker/service/MonitoringService.java index 1f30550..07c5a10 100644 --- a/src/main/java/ru/nbch/credit_tracker/service/MonitoringService.java +++ b/src/main/java/ru/nbch/credit_tracker/service/MonitoringService.java @@ -2,6 +2,7 @@ package ru.nbch.credit_tracker.service; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.slf4j.MDC; import org.springframework.scheduling.concurrent.CustomizableThreadFactory; import org.springframework.stereotype.Service; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; @@ -69,83 +70,89 @@ public class MonitoringService { log.info("Start monitoring"); List packages = signalService.findPackagesOnMonitoring(); for (UserPackage userPackage : packages) { - log.info("Processing package {}", userPackage.getPackageName()); - if (!signalService.hasNonNullfids(userPackage.getId())) { - log.info("Package {} has no fids. Package will be skipped.", userPackage.getPackageName()); - continue; - } - SgnlOnlineReport onlineReports = signalRestService.getReports(userPackage.getUserId().substring(0, 6) + "_" + userPackage.getPackageName()); - - if (onlineReports == null) { - log.info("No reports found for package {}", userPackage.getPackageName()); - continue; - } - - // Формируем список имен файлов, по которым сработали сигналы. Сюда входят только те имена, у которых парсится дата формирования отчета - List fileNames = onlineReports.getOperationReport().getReports().getReports().stream().map(Report::getFilename) - .filter(fileName -> CTUtil.parseDateFromReportFileName(fileName) != null).toList(); - - if (fileNames.isEmpty()) { - log.info("No new report found for package {}", userPackage.getPackageName()); - continue; - } - - LocalDateTime lastDownloadedReportDate = CTUtil.parseDateFromReportFileName(userPackage.getLastDownloadedReport()); - - if (lastDownloadedReportDate != null) { - // Отбираем только те отчеты, дата которых позже даты последнего загруженного отчета - fileNames = fileNames.stream() - .filter(fileName -> CTUtil.parseDateFromReportFileName(fileName).isAfter(lastDownloadedReportDate)) // отфильтровали только те имена, которые парсятся в дату, так что null тут не придет - .sorted(Comparator.comparing(CTUtil::parseDateFromReportFileName)) // Сортируем по дате - .toList(); - } else { - fileNames = fileNames.stream() - .sorted(Comparator.comparing(CTUtil::parseDateFromReportFileName)) // Сортируем по дате - .toList(); - } - - if (StringUtils.isNotBlank(userPackage.getLastDownloadedReport())) { - log.info("Last downloaded report found for package {}. Last Downloaded Report Name: {}", userPackage.getPackageName(), userPackage.getLastDownloadedReport()); - } else { - log.info("Last Downloaded Report Name is empty"); - } - - for (String newReport : fileNames) { - try { - String loadedReportPath = null; - if (StringUtils.isBlank(userPackage.getLastDownloadedReport())) { - loadedReportPath = loadReport(userPackage.getId(), newReport); // по этому пакету еще не было загруженных отчетов, продолжаем работу с полученным - } else if (lastDownloadedReportDate != null) { - LocalDateTime newReportDate = CTUtil.parseDateFromReportFileName(newReport); - if (newReportDate.isAfter(lastDownloadedReportDate)) { - loadedReportPath = loadReport(userPackage.getId(), newReport); // полученный отчет новее записанного в базу - } - } - if (loadedReportPath == null) { - log.info("Report was not loaded for package {}", userPackage.getPackageName()); - continue; - } - - String responsePath = generateResponse(userPackage, loadedReportPath); - String fileName = null; - if (responsePath != null) { - fileName = createResponseFile(userPackage, responsePath); - } - if (fileName != null) { - log.info("New report fileName: {}", fileName); - updateSignalHits(userPackage, responsePath, fileName); - signalService.updateLastDownloadedReport(userPackage.getId(), newReport); - } else { - log.info("Report was not created for package {}", userPackage.getPackageName()); - } - } catch (Exception e) { - log.error(e.getMessage(), e); - } - } + MDC.put("ru.nbch.credit_tracker.log.mdc.key", "[" + userPackage.getPackageName() +"]"); + processPackage(userPackage); + MDC.remove("ru.nbch.credit_tracker.log.mdc.key"); } log.info("Finish monitoring"); } + private void processPackage(UserPackage userPackage) { + log.info("Processing package"); + if (!signalService.hasNonNullfids(userPackage.getId())) { + log.info("Package has no fids. Package will be skipped."); + return; + } + SgnlOnlineReport onlineReports = signalRestService.getReports(userPackage.getUserId().substring(0, 6) + "_" + userPackage.getPackageName()); + + if (onlineReports == null) { + log.info("No reports found for package"); + return; + } + + // Формируем список имен файлов, по которым сработали сигналы. Сюда входят только те имена, у которых парсится дата формирования отчета + List fileNames = onlineReports.getOperationReport().getReports().getReports().stream().map(Report::getFilename) + .filter(fileName -> CTUtil.parseDateFromReportFileName(fileName) != null).toList(); + + if (fileNames.isEmpty()) { + log.info("No new report found for package"); + return; + } + + LocalDateTime lastDownloadedReportDate = CTUtil.parseDateFromReportFileName(userPackage.getLastDownloadedReport()); + + if (lastDownloadedReportDate != null) { + // Отбираем только те отчеты, дата которых позже даты последнего загруженного отчета + fileNames = fileNames.stream() + .filter(fileName -> CTUtil.parseDateFromReportFileName(fileName).isAfter(lastDownloadedReportDate)) // отфильтровали только те имена, которые парсятся в дату, так что null тут не придет + .sorted(Comparator.comparing(CTUtil::parseDateFromReportFileName)) // Сортируем по дате + .toList(); + } else { + fileNames = fileNames.stream() + .sorted(Comparator.comparing(CTUtil::parseDateFromReportFileName)) // Сортируем по дате + .toList(); + } + + if (StringUtils.isNotBlank(userPackage.getLastDownloadedReport())) { + log.info("Last downloaded report found for package. Last Downloaded Report Name: {}", userPackage.getLastDownloadedReport()); + } else { + log.info("Last Downloaded Report Name is empty"); + } + + for (String newReport : fileNames) { + try { + String loadedReportPath = null; + if (StringUtils.isBlank(userPackage.getLastDownloadedReport())) { + loadedReportPath = loadReport(userPackage.getId(), newReport); // по этому пакету еще не было загруженных отчетов, продолжаем работу с полученным + } else if (lastDownloadedReportDate != null) { + LocalDateTime newReportDate = CTUtil.parseDateFromReportFileName(newReport); + if (newReportDate.isAfter(lastDownloadedReportDate)) { + loadedReportPath = loadReport(userPackage.getId(), newReport); // полученный отчет новее записанного в базу + } + } + if (loadedReportPath == null) { + log.info("Report was not loaded for package"); + continue; + } + + String responsePath = generateResponse(userPackage, loadedReportPath); + String fileName = null; + if (responsePath != null) { + fileName = createResponseFile(userPackage, responsePath); + } + if (fileName != null) { + log.info("New report fileName: {}", fileName); + updateSignalHits(userPackage, responsePath, fileName); + signalService.updateLastDownloadedReport(userPackage.getId(), newReport); + } else { + log.info("Report was not created for package"); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } + } + /** * Формирует результирующий xml файл для конечного пользователя на основе файла из официального сервиса сигналов * @return Путь к временному рещультирующему файлу @@ -297,7 +304,7 @@ public class MonitoringService { 10000, "/MonitoringSignalResponse/Subjects/Subject"); } catch (IOException e) { - throw new RuntimeException("Error while and updating hits", e); + throw new RuntimeException("Error while updating hits", e); } CTUtil.removeFile(responsePath); // удалям результирующий xml файл с диска (Он уже заархивирован к этому моменту) diff --git a/src/main/java/ru/nbch/credit_tracker/service/UpdateProcessingPackagesService.java b/src/main/java/ru/nbch/credit_tracker/service/UpdateProcessingPackagesService.java index 2888c82..1ca26c7 100644 --- a/src/main/java/ru/nbch/credit_tracker/service/UpdateProcessingPackagesService.java +++ b/src/main/java/ru/nbch/credit_tracker/service/UpdateProcessingPackagesService.java @@ -1,7 +1,10 @@ package ru.nbch.credit_tracker.service; import lombok.extern.slf4j.Slf4j; +import org.springframework.aop.framework.AopContext; +import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.stereotype.Service; +import ru.nbch.credit_tracker.config.mdc.SetAndClearMdc; import ru.nbch.credit_tracker.entities.dto.UserPackage; import ru.nbch.credit_tracker.enums.Status; import ru.nbch.credit_tracker.service.signal.SignalRestService; @@ -14,8 +17,11 @@ import java.util.List; */ @Slf4j @Service +@EnableAspectJAutoProxy(exposeProxy = true) public class UpdateProcessingPackagesService { + private UpdateProcessingPackagesService self; + private final SignalService signalService; private final SignalRestService signalRestService; private final MonitoringErrorProcesingService monitoringErrorProcesingService; @@ -33,25 +39,26 @@ public class UpdateProcessingPackagesService { List packages = signalService.findPackagesOnProcessing(); for (UserPackage userPackage : packages) { log.info("Updating flags for Package {}", userPackage.getPackageName()); - process(userPackage.getId(), userPackage.getPackageName()); + getCurrentProxy().process(userPackage.getId(), userPackage.getPackageName()); } log.info("Finish updating processing packages"); } - private void process(Integer packageId, String packageName) { + @SetAndClearMdc(argIndex = 1) + public void process(Integer packageId, String packageName) { try { SignalService.UpdateResult updateResult = signalService.updateSubjects(packageId, null); if (updateResult.isNoFidsFound()) { - log.info("No fids found for PackageId: {} PackageName: {}. Package status ON_MONITORING. No registration in signal service.", packageId, packageName); + log.info("No fids found for PackageId: {} . Package status ON_MONITORING. No registration in signal service.", packageId); signalService.updatePackageStatus(packageId, Status.ON_MONITORING); return; } if (signalRestService.setupMonitoring(packageId)) { - log.info("Package was successfully registered in signal service. PackageId: {} PackageName: {}", packageId, packageName); + log.info("Package was successfully registered in signal service. PackageId: {}", packageId); signalService.updatePackageStatus(packageId, Status.ON_MONITORING); monitoringErrorProcesingService.findErrors(packageId); } else { - log.info("Package registration was rejected by signal service. PackageId: {} PackageName: {}", packageId, packageName); + log.info("Package registration was rejected by signal service. PackageId: {}", packageId); signalService.updatePackageStatus(packageId, Status.ERROR); } } catch (Exception e) { @@ -59,4 +66,11 @@ public class UpdateProcessingPackagesService { log.error("Ошибка при поиске фидов или расчете флагов просрочек. Package_id {}", packageId, e); } } + + private UpdateProcessingPackagesService getCurrentProxy() { + if (self == null) { + self = (UpdateProcessingPackagesService) AopContext.currentProxy(); + } + return self; + } } diff --git a/src/main/java/ru/nbch/credit_tracker/service/UpdatingFlagsService.java b/src/main/java/ru/nbch/credit_tracker/service/UpdatingFlagsService.java index 19549fb..3f05e3f 100644 --- a/src/main/java/ru/nbch/credit_tracker/service/UpdatingFlagsService.java +++ b/src/main/java/ru/nbch/credit_tracker/service/UpdatingFlagsService.java @@ -1,6 +1,7 @@ package ru.nbch.credit_tracker.service; import lombok.extern.slf4j.Slf4j; +import org.slf4j.MDC; import org.springframework.scheduling.concurrent.CustomizableThreadFactory; import org.springframework.stereotype.Service; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; @@ -52,7 +53,9 @@ public class UpdatingFlagsService { List packages = signalService.findPackagesOnMonitoring(); for (UserPackage userPackage : packages) { log.info("Updating flags for Package {}", userPackage.getPackageName()); + MDC.put("ru.nbch.credit_tracker.log.mdc.key", "[" + userPackage.getPackageName() +"]"); updateFlags(userPackage.getId(), userPackage.getPackageName()); + MDC.remove("ru.nbch.credit_tracker.log.mdc.key"); } log.info("Finish updating flags"); } diff --git a/src/main/java/ru/nbch/credit_tracker/utils/ValidationUtil.java b/src/main/java/ru/nbch/credit_tracker/utils/ValidationService.java similarity index 91% rename from src/main/java/ru/nbch/credit_tracker/utils/ValidationUtil.java rename to src/main/java/ru/nbch/credit_tracker/utils/ValidationService.java index 4885a27..6273d7c 100644 --- a/src/main/java/ru/nbch/credit_tracker/utils/ValidationUtil.java +++ b/src/main/java/ru/nbch/credit_tracker/utils/ValidationService.java @@ -1,6 +1,8 @@ package ru.nbch.credit_tracker.utils; import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import ru.nbch.credit_tracker.config.mdc.SetAndClearMdc; import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest; import ru.nbch.credit_tracker.entities.user_request.monitoring_request.Subject; import ru.nbch.credit_tracker.enums.SignalError; @@ -12,13 +14,15 @@ import java.util.regex.Pattern; import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.clientExcp; @Slf4j -public class ValidationUtil { +@Service +public class ValidationService { private static final String phoneRegex = "^\\d{9}$"; private static final String packageNameRegex = "^[A-Z0-9_]{1,22}$"; private static final String npIdRegex = "^\\S{1,36}$"; - public static void validateMonitoringRequest(MonitoringRequest request) throws SignalClientException { + @SetAndClearMdc + public void validateMonitoringRequest(MonitoringRequest request) throws SignalClientException { if (request == null) { throw clientExcp(SignalError.ERROR_011, XmlErrorFormat.MonitoringError); } diff --git a/src/test/java/ru/nbch/credit_tracker/utils/ValidationUtilTest.java b/src/test/java/ru/nbch/credit_tracker/utils/ValidationServiceTest.java similarity index 88% rename from src/test/java/ru/nbch/credit_tracker/utils/ValidationUtilTest.java rename to src/test/java/ru/nbch/credit_tracker/utils/ValidationServiceTest.java index aea414b..baa0724 100644 --- a/src/test/java/ru/nbch/credit_tracker/utils/ValidationUtilTest.java +++ b/src/test/java/ru/nbch/credit_tracker/utils/ValidationServiceTest.java @@ -28,14 +28,17 @@ import java.util.zip.ZipInputStream; import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.clientExcp; -@SpringBootTest(classes = {ValidationUtilTest.TestConfig.class}) -public class ValidationUtilTest { +@SpringBootTest(classes = {ValidationServiceTest.TestConfig.class}) +public class ValidationServiceTest { private final StaxXmlProcessor staxXmlProcessor; + private final ValidationService validationService; @Autowired - public ValidationUtilTest(StaxXmlProcessor staxXmlProcessor) { + public ValidationServiceTest(StaxXmlProcessor staxXmlProcessor, + ValidationService validationService) { this.staxXmlProcessor = staxXmlProcessor; + this.validationService = validationService; } @Configuration @@ -46,6 +49,11 @@ public class ValidationUtilTest { staxReader.add(MonitoringRequestStaxReader::new); return new XmlProcessorStaxImpl(staxReader); } + + @Bean + public ValidationService validationService() { + return new ValidationService(); + } } private static Stream validationTestCases() { @@ -107,7 +115,7 @@ public class ValidationUtilTest { if(ex == null) { try { - ValidationUtil.validateMonitoringRequest(monitoringRequest); + validationService.validateMonitoringRequest(monitoringRequest); } catch (SignalClientException e) { ex = e; } From 6b5f39c755ed34a90b2942b76b48c4263b85640e Mon Sep 17 00:00:00 2001 From: Mikhail Trofimov Date: Tue, 30 Sep 2025 16:36:42 +0300 Subject: [PATCH 06/16] http://jira.mfd.msk:8088/browse/BKI-3215 Updated HttpLoggingFilter to log incoming requests --- .../rest/filters/HttpLoggingFilter.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java b/src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java index 262a9d2..aae7ecb 100644 --- a/src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java +++ b/src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java @@ -46,6 +46,8 @@ public class HttpLoggingFilter extends OncePerRequestFilter { .orElse(UUID.randomUUID().toString()); resp.setHeader("X-Correlation-Id", correlationId); + logIncomingRequest(req, correlationId); + try { chain.doFilter(req, resp); } finally { @@ -61,7 +63,7 @@ public class HttpLoggingFilter extends OncePerRequestFilter { mask(respHeaders); log.info( - "HTTP {} {}{} | status={} | took={}ms | cid={} | reqHeaders={} | reqBody={} | respHeaders={} | respBody={}", + "HTTP (RESPONSE) {} {}{} | status={} | took={}ms | cid={} | reqHeaders={} | reqBody={} | respHeaders={} | respBody={}", req.getMethod(), req.getRequestURI(), req.getQueryString() == null ? "" : "?" + req.getQueryString(), @@ -78,6 +80,24 @@ public class HttpLoggingFilter extends OncePerRequestFilter { } } + + private void logIncomingRequest(ContentCachingRequestWrapper req, String correlationId) { + String requestBody = readBody(req.getContentAsByteArray(), req.getCharacterEncoding()); + + Map reqHeaders = headersMap(req); + mask(reqHeaders); + + log.info( + "HTTP (REQUEST) {} {}{} | cid={} | reqHeaders={} | reqBody={}", + req.getMethod(), + req.getRequestURI(), + req.getQueryString() == null ? "" : "?" + req.getQueryString(), + correlationId, + reqHeaders, + requestBody + ); + } + private static ContentCachingRequestWrapper wrapRequest(HttpServletRequest request) { return (request instanceof ContentCachingRequestWrapper c) ? c : new ContentCachingRequestWrapper(request, MAX_BODY); } From d02b471466b16e9d267e1ecec64e1f6523064d14 Mon Sep 17 00:00:00 2001 From: Mikhail Trofimov Date: Wed, 1 Oct 2025 09:58:30 +0300 Subject: [PATCH 07/16] http://jira.mfd.msk:8088/browse/BKI-3231 Moved db properties to .properties and .env file --- credit-tracker.properties | 24 ++++++++++++++++++ docker_compose/credit_tracker_config.env | 25 +++++++++++++++++++ docker_compose/docker-compose.yml | 24 ++++++++++++++++++ .../config/datasource/DatabaseConfig.java | 6 ++--- .../datasource/IndicDataSourceConfig.java | 19 +++++++++++--- .../datasource/ScoringDataSourceConfig.java | 19 +++++++++++--- .../datasource/SignalDataSourceConfig.java | 19 +++++++++++--- .../config/settings/DataSourceSettings.java | 10 +++++++- 8 files changed, 133 insertions(+), 13 deletions(-) diff --git a/credit-tracker.properties b/credit-tracker.properties index a337a0e..e8ab0cb 100644 --- a/credit-tracker.properties +++ b/credit-tracker.properties @@ -11,18 +11,42 @@ ct.indic-data-source-settings.driver=com.ibm.db2.jcc.DB2Driver ct.indic-data-source-settings.url=${DB_URL_INDIC:jdbc:db2://10.230.227.101:2668/cprosd22:currentSchema=INDIC;} ct.indic-data-source-settings.username=${USERNAME_INDIC:tester} ct.indic-data-source-settings.password=${PASSWORD_INDIC:tester} +ct.indic-data-source-settings.maximum-pool-size=${MAXIMUM_POOL_SIZE_INDIC:10} +ct.indic-data-source-settings.minimum-idle=${MINIMUM_IDLE_INDIC:10} +ct.indic-data-source-settings.connection-timeout=${CONNECTION_TIMEOUT_INDIC:10000} +ct.indic-data-source-settings.validation-timeout=${VALIDATION_TIMEOUT_INDIC:5000} +ct.indic-data-source-settings.idle-timeout=${IDLE_TIMEOUT_INDIC:600000} +ct.indic-data-source-settings.max-lifetime=${MAX_LIFETIME_INDIC:1800000} +ct.indic-data-source-settings.keepalive-time=${KEEPALIVE_TIME_INDIC:0} +ct.indic-data-source-settings.leak-detection-threshold=${DETECTION_THRESHOLD_INDIC:0} # signal ct.signal-data-source-settings.driver=org.postgresql.Driver ct.signal-data-source-settings.url=${DB_URL_SIGNAL:jdbc:postgresql://10.200.200.133:5432/credit_tracker} ct.signal-data-source-settings.username=${USERNAME_SIGNAL:credit_tracker_user} ct.signal-data-source-settings.password=${PASSWORD_SIGNAL:-} +ct.signal-data-source-settings.maximum-pool-size=${MAXIMUM_POOL_SIZE_SIGNAL:10} +ct.signal-data-source-settings.minimum-idle=${MINIMUM_IDLE_SIGNAL:10} +ct.signal-data-source-settings.connection-timeout=${CONNECTION_TIMEOUT_SIGNAL:10000} +ct.signal-data-source-settings.validation-timeout=${VALIDATION_TIMEOUT_SIGNAL:5000} +ct.signal-data-source-settings.idle-timeout=${IDLE_TIMEOUT_SIGNAL:600000} +ct.signal-data-source-settings.max-lifetime=${MAX_LIFETIME_SIGNAL:1800000} +ct.signal-data-source-settings.keepalive-time=${KEEPALIVE_TIME_SIGNAL:0} +ct.signal-data-source-settings.leak-detection-threshold=${DETECTION_THRESHOLD_SIGNAL:0} # scoring ct.scoring-data-source-settings.driver=com.ibm.db2.jcc.DB2Driver ct.scoring-data-source-settings.url=${DB_URL_SCORING:jdbc:db2://10.230.227.101:2668/cprosd22:currentSchema=TEST_2_INDIC;} ct.scoring-data-source-settings.username=${USERNAME_SCORING:tester} ct.scoring-data-source-settings.password=${PASSWORD_SCORING:tester} +ct.scoring-data-source-settings.maximum-pool-size=${MAXIMUM_POOL_SIZE_SCORING:10} +ct.scoring-data-source-settings.minimum-idle=${MINIMUM_IDLE_SCORING:10} +ct.scoring-data-source-settings.connection-timeout=${CONNECTION_TIMEOUT_SCORING:10000} +ct.scoring-data-source-settings.validation-timeout=${VALIDATION_TIMEOUT_SCORING:5000} +ct.scoring-data-source-settings.idle-timeout=${IDLE_TIMEOUT_SCORING:600000} +ct.scoring-data-source-settings.max-lifetime=${MAX_LIFETIME_SCORING:1800000} +ct.scoring-data-source-settings.keepalive-time=${KEEPALIVE_TIME_SCORING:0} +ct.scoring-data-source-settings.leak-detection-threshold=${DETECTION_THRESHOLD_SCORING:0} ct.max_xml_file_size=${ACCEPTED_XML_SIZE:1024} spring.servlet.multipart.max-file-size=${ACCEPTED_ARCHIVE_SIZE:2048MB} diff --git a/docker_compose/credit_tracker_config.env b/docker_compose/credit_tracker_config.env index b395b4f..437d729 100644 --- a/docker_compose/credit_tracker_config.env +++ b/docker_compose/credit_tracker_config.env @@ -24,16 +24,41 @@ SERVER_PORT=8099 DB_URL_INDIC=jdbc:db2://10.230.227.101:2668/cprosd22:currentSchema=INDIC; USERNAME_INDIC=tester PASSWORD_INDIC=tester +MAXIMUM_POOL_SIZE_INDIC=10 +MINIMUM_IDLE_INDIC=10 +CONNECTION_TIMEOUT_INDIC=10000 +VALIDATION_TIMEOUT_INDIC=5000 +IDLE_TIMEOUT_INDIC=600000 +MAX_LIFETIME_INDIC=1800000 +KEEPALIVE_TIME_INDIC=0 +DETECTION_THRESHOLD_INDIC=0 + # signal DB_URL_SIGNAL=jdbc:postgresql://10.200.200.133:5432/credit_tracker USERNAME_SIGNAL=credit_tracker_user PASSWORD_SIGNAL= +MAXIMUM_POOL_SIZE_SIGNAL=10 +MINIMUM_IDLE_SIGNAL=10 +CONNECTION_TIMEOUT_SIGNAL=10000 +VALIDATION_TIMEOUT_SIGNAL=5000 +IDLE_TIMEOUT_SIGNAL=600000 +MAX_LIFETIME_SIGNAL=1800000 +KEEPALIVE_TIME_SIGNAL=0 +DETECTION_THRESHOLD_SIGNAL=0 # scoring DB_URL_SCORING=jdbc:db2://10.230.227.101:2668/cprosd22:currentSchema=TEST_2_INDIC; USERNAME_SCORING=tester PASSWORD_SCORING=tester +MAXIMUM_POOL_SIZE_SCORING=10 +MINIMUM_IDLE_SCORING=10 +CONNECTION_TIMEOUT_SCORING=10000 +VALIDATION_TIMEOUT_SCORING=5000 +IDLE_TIMEOUT_SCORING=600000 +MAX_LIFETIME_SCORING=1800000 +KEEPALIVE_TIME_SCORING=0 +DETECTION_THRESHOLD_SCORING=0 # размер в mb ACCEPTED_XML_SIZE=1024 diff --git a/docker_compose/docker-compose.yml b/docker_compose/docker-compose.yml index 1b06547..1c069df 100644 --- a/docker_compose/docker-compose.yml +++ b/docker_compose/docker-compose.yml @@ -23,12 +23,36 @@ services: - DB_URL_INDIC=${DB_URL_INDIC} - USERNAME_INDIC=${USERNAME_INDIC} - PASSWORD_INDIC=${PASSWORD_INDIC} + - MAXIMUM_POOL_SIZE_INDIC=${MAXIMUM_POOL_SIZE_INDIC} + - MINIMUM_IDLE_INDIC=${MINIMUM_IDLE_INDIC} + - CONNECTION_TIMEOUT_INDIC=${CONNECTION_TIMEOUT_INDIC} + - VALIDATION_TIMEOUT_INDIC=${VALIDATION_TIMEOUT_INDIC} + - IDLE_TIMEOUT_INDIC=${IDLE_TIMEOUT_INDIC} + - MAX_LIFETIME_INDIC=${MAX_LIFETIME_INDIC} + - KEEPALIVE_TIME_INDIC=${KEEPALIVE_TIME_INDIC} + - DETECTION_THRESHOLD_INDIC=${DETECTION_THRESHOLD_INDIC} - DB_URL_SIGNAL=${DB_URL_SIGNAL} - USERNAME_SIGNAL=${USERNAME_SIGNAL} - PASSWORD_SIGNAL=${PASSWORD_SIGNAL} + - MAXIMUM_POOL_SIZE_SIGNAL=${MAXIMUM_POOL_SIZE_SIGNAL} + - MINIMUM_IDLE_SIGNAL=${MINIMUM_IDLE_SIGNAL} + - CONNECTION_TIMEOUT_SIGNAL=${CONNECTION_TIMEOUT_SIGNAL} + - VALIDATION_TIMEOUT_SIGNAL=${VALIDATION_TIMEOUT_SIGNAL} + - IDLE_TIMEOUT_SIGNAL=${IDLE_TIMEOUT_SIGNAL} + - MAX_LIFETIME_SIGNAL=${MAX_LIFETIME_SIGNAL} + - KEEPALIVE_TIME_SIGNAL=${KEEPALIVE_TIME_SIGNAL} + - DETECTION_THRESHOLD_SIGNAL=${DETECTION_THRESHOLD_SIGNAL} - DB_URL_SCORING=${DB_URL_SCORING} - USERNAME_SCORING=${USERNAME_SCORING} - PASSWORD_SCORING=${PASSWORD_SCORING} + - MAXIMUM_POOL_SIZE_SCORING=${MAXIMUM_POOL_SIZE_SCORING} + - MINIMUM_IDLE_SCORING=${MINIMUM_IDLE_SCORING} + - CONNECTION_TIMEOUT_SCORING=${CONNECTION_TIMEOUT_SCORING} + - VALIDATION_TIMEOUT_SCORING=${VALIDATION_TIMEOUT_SCORING} + - IDLE_TIMEOUT_SCORING=${IDLE_TIMEOUT_SCORING} + - MAX_LIFETIME_SCORING=${MAX_LIFETIME_SCORING} + - KEEPALIVE_TIME_SCORING=${KEEPALIVE_TIME_SCORING} + - DETECTION_THRESHOLD_SCORING=${DETECTION_THRESHOLD_SCORING} - ACCEPTED_XML_SIZE=${ACCEPTED_XML_SIZE} - ACCEPTED_ARCHIVE_SIZE=${ACCEPTED_ARCHIVE_SIZE} - SIGNALS_ROOT_URI=${SIGNALS_ROOT_URI} diff --git a/src/main/java/ru/nbch/credit_tracker/config/datasource/DatabaseConfig.java b/src/main/java/ru/nbch/credit_tracker/config/datasource/DatabaseConfig.java index dafc1a7..e75ce61 100644 --- a/src/main/java/ru/nbch/credit_tracker/config/datasource/DatabaseConfig.java +++ b/src/main/java/ru/nbch/credit_tracker/config/datasource/DatabaseConfig.java @@ -1,18 +1,18 @@ package ru.nbch.credit_tracker.config.datasource; +import com.zaxxer.hikari.HikariDataSource; import org.springframework.boot.jdbc.DataSourceBuilder; import ru.nbch.credit_tracker.config.settings.DataSourceSettings; -import javax.sql.DataSource; - public class DatabaseConfig { - protected DataSource createDataSource(DataSourceSettings settings) { + protected HikariDataSource createDataSource(DataSourceSettings settings) { return DataSourceBuilder.create() .driverClassName(settings.driver()) .url(settings.url()) .username(settings.username()) .password(settings.password()) + .type(HikariDataSource.class) .build(); } diff --git a/src/main/java/ru/nbch/credit_tracker/config/datasource/IndicDataSourceConfig.java b/src/main/java/ru/nbch/credit_tracker/config/datasource/IndicDataSourceConfig.java index e83429b..cc2afc7 100644 --- a/src/main/java/ru/nbch/credit_tracker/config/datasource/IndicDataSourceConfig.java +++ b/src/main/java/ru/nbch/credit_tracker/config/datasource/IndicDataSourceConfig.java @@ -1,5 +1,6 @@ package ru.nbch.credit_tracker.config.datasource; +import com.zaxxer.hikari.HikariDataSource; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; @@ -10,6 +11,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; +import ru.nbch.credit_tracker.config.settings.DataSourceSettings; import javax.sql.DataSource; import java.sql.Connection; @@ -28,14 +30,25 @@ public class IndicDataSourceConfig extends DatabaseConfig { @Bean(name = "indicDataSource") public DataSource dataSource(CreditTrackerSettings config) throws SQLException { - DataSource dataSource = createDataSource(config.getIndicDataSourceSettings()); + DataSourceSettings indicSetings = config.getIndicDataSourceSettings(); + + HikariDataSource dataSource = createDataSource(indicSetings); + dataSource.setMaximumPoolSize(indicSetings.maximumPoolSize()); + dataSource.setMinimumIdle(indicSetings.minimumIdle()); + dataSource.setConnectionTimeout(indicSetings.connectionTimeout()); + dataSource.setValidationTimeout(indicSetings.validationTimeout()); + dataSource.setIdleTimeout(indicSetings.idleTimeout()); + dataSource.setMaxLifetime(indicSetings.maxLifetime()); + dataSource.setKeepaliveTime(indicSetings.keepaliveTime()); + dataSource.setLeakDetectionThreshold(indicSetings.leakDetectionThreshold()); + try (Connection connection = dataSource.getConnection()) { connection.isValid(3); } catch (SQLException e) { - log.error("Unable to connect to Indic url={}", config.getIndicDataSourceSettings().url(), e); + log.error("Unable to connect to Indic url={}", indicSetings.url(), e); throw e; } - log.info("Connected to Indic: url={}", config.getIndicDataSourceSettings().url()); + log.info("Connected to Indic: url={}", indicSetings.url()); return dataSource; } diff --git a/src/main/java/ru/nbch/credit_tracker/config/datasource/ScoringDataSourceConfig.java b/src/main/java/ru/nbch/credit_tracker/config/datasource/ScoringDataSourceConfig.java index 8d9bbde..d65b590 100644 --- a/src/main/java/ru/nbch/credit_tracker/config/datasource/ScoringDataSourceConfig.java +++ b/src/main/java/ru/nbch/credit_tracker/config/datasource/ScoringDataSourceConfig.java @@ -1,5 +1,6 @@ package ru.nbch.credit_tracker.config.datasource; +import com.zaxxer.hikari.HikariDataSource; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; @@ -10,6 +11,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; +import ru.nbch.credit_tracker.config.settings.DataSourceSettings; import javax.sql.DataSource; import java.sql.Connection; @@ -28,14 +30,25 @@ public class ScoringDataSourceConfig extends DatabaseConfig { @Bean(name = "scoringDataSource") public DataSource dataSource(CreditTrackerSettings config) throws SQLException { - DataSource dataSource = createDataSource(config.getScoringDataSourceSettings()); + DataSourceSettings scoringSetings = config.getScoringDataSourceSettings(); + + HikariDataSource dataSource = createDataSource(scoringSetings); + dataSource.setMaximumPoolSize(scoringSetings.maximumPoolSize()); + dataSource.setMinimumIdle(scoringSetings.minimumIdle()); + dataSource.setConnectionTimeout(scoringSetings.connectionTimeout()); + dataSource.setValidationTimeout(scoringSetings.validationTimeout()); + dataSource.setIdleTimeout(scoringSetings.idleTimeout()); + dataSource.setMaxLifetime(scoringSetings.maxLifetime()); + dataSource.setKeepaliveTime(scoringSetings.keepaliveTime()); + dataSource.setLeakDetectionThreshold(scoringSetings.leakDetectionThreshold()); + try (Connection connection = dataSource.getConnection()) { connection.isValid(3); } catch (SQLException e) { - log.error("Unable to connect to Scoring url={}", config.getScoringDataSourceSettings().url(), e); + log.error("Unable to connect to Scoring url={}", scoringSetings.url(), e); throw e; } - log.info("Connected to Scoring: url={}", config.getScoringDataSourceSettings().url()); + log.info("Connected to Scoring: url={}", scoringSetings.url()); return dataSource; } diff --git a/src/main/java/ru/nbch/credit_tracker/config/datasource/SignalDataSourceConfig.java b/src/main/java/ru/nbch/credit_tracker/config/datasource/SignalDataSourceConfig.java index c2e94c3..4e9167f 100644 --- a/src/main/java/ru/nbch/credit_tracker/config/datasource/SignalDataSourceConfig.java +++ b/src/main/java/ru/nbch/credit_tracker/config/datasource/SignalDataSourceConfig.java @@ -1,5 +1,6 @@ package ru.nbch.credit_tracker.config.datasource; +import com.zaxxer.hikari.HikariDataSource; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; @@ -10,6 +11,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; +import ru.nbch.credit_tracker.config.settings.DataSourceSettings; import javax.sql.DataSource; import java.sql.Connection; @@ -27,14 +29,25 @@ public class SignalDataSourceConfig extends DatabaseConfig { @Bean(name = "signalDataSource") public DataSource dataSource(CreditTrackerSettings config) throws SQLException { - DataSource dataSource = createDataSource(config.getSignalDataSourceSettings()); + DataSourceSettings signalSetings = config.getSignalDataSourceSettings(); + + HikariDataSource dataSource = createDataSource(signalSetings); + dataSource.setMaximumPoolSize(signalSetings.maximumPoolSize()); + dataSource.setMinimumIdle(signalSetings.minimumIdle()); + dataSource.setConnectionTimeout(signalSetings.connectionTimeout()); + dataSource.setValidationTimeout(signalSetings.validationTimeout()); + dataSource.setIdleTimeout(signalSetings.idleTimeout()); + dataSource.setMaxLifetime(signalSetings.maxLifetime()); + dataSource.setKeepaliveTime(signalSetings.keepaliveTime()); + dataSource.setLeakDetectionThreshold(signalSetings.leakDetectionThreshold()); + try (Connection connection = dataSource.getConnection()) { connection.isValid(3); } catch (SQLException e) { - log.error("Unable to connect to Signal url={}", config.getSignalDataSourceSettings().url(), e); + log.error("Unable to connect to Signal url={}", signalSetings.url(), e); throw e; } - log.info("Connected to Signal: url={}", config.getSignalDataSourceSettings().url()); + log.info("Connected to Signal: url={}", signalSetings.url()); return dataSource; } diff --git a/src/main/java/ru/nbch/credit_tracker/config/settings/DataSourceSettings.java b/src/main/java/ru/nbch/credit_tracker/config/settings/DataSourceSettings.java index 101c08d..f283f23 100644 --- a/src/main/java/ru/nbch/credit_tracker/config/settings/DataSourceSettings.java +++ b/src/main/java/ru/nbch/credit_tracker/config/settings/DataSourceSettings.java @@ -4,5 +4,13 @@ public record DataSourceSettings( String username, String password, String url, - String driver + String driver, + Integer maximumPoolSize, + Integer minimumIdle, + long connectionTimeout, + long validationTimeout, + long idleTimeout, + long maxLifetime, + long keepaliveTime, + long leakDetectionThreshold ) {} \ No newline at end of file From ea12395559fd41c68a8e9c94ae843605dabf32df Mon Sep 17 00:00:00 2001 From: Mikhail Trofimov Date: Wed, 1 Oct 2025 10:12:02 +0300 Subject: [PATCH 08/16] http://jira.mfd.msk:8088/browse/BKI-3231 Changed DETECTION_THRESHOLD_* property to LEAK_DETECTION_THRESHOLD_* --- credit-tracker.properties | 6 +++--- docker_compose/credit_tracker_config.env | 6 +++--- docker_compose/docker-compose.yml | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/credit-tracker.properties b/credit-tracker.properties index e8ab0cb..e8241c1 100644 --- a/credit-tracker.properties +++ b/credit-tracker.properties @@ -18,7 +18,7 @@ ct.indic-data-source-settings.validation-timeout=${VALIDATION_TIMEOUT_INDIC:5000 ct.indic-data-source-settings.idle-timeout=${IDLE_TIMEOUT_INDIC:600000} ct.indic-data-source-settings.max-lifetime=${MAX_LIFETIME_INDIC:1800000} ct.indic-data-source-settings.keepalive-time=${KEEPALIVE_TIME_INDIC:0} -ct.indic-data-source-settings.leak-detection-threshold=${DETECTION_THRESHOLD_INDIC:0} +ct.indic-data-source-settings.leak-detection-threshold=${LEAK_DETECTION_THRESHOLD_INDIC:0} # signal ct.signal-data-source-settings.driver=org.postgresql.Driver @@ -32,7 +32,7 @@ ct.signal-data-source-settings.validation-timeout=${VALIDATION_TIMEOUT_SIGNAL:50 ct.signal-data-source-settings.idle-timeout=${IDLE_TIMEOUT_SIGNAL:600000} ct.signal-data-source-settings.max-lifetime=${MAX_LIFETIME_SIGNAL:1800000} ct.signal-data-source-settings.keepalive-time=${KEEPALIVE_TIME_SIGNAL:0} -ct.signal-data-source-settings.leak-detection-threshold=${DETECTION_THRESHOLD_SIGNAL:0} +ct.signal-data-source-settings.leak-detection-threshold=${LEAK_DETECTION_THRESHOLD_SIGNAL:0} # scoring ct.scoring-data-source-settings.driver=com.ibm.db2.jcc.DB2Driver @@ -46,7 +46,7 @@ ct.scoring-data-source-settings.validation-timeout=${VALIDATION_TIMEOUT_SCORING: ct.scoring-data-source-settings.idle-timeout=${IDLE_TIMEOUT_SCORING:600000} ct.scoring-data-source-settings.max-lifetime=${MAX_LIFETIME_SCORING:1800000} ct.scoring-data-source-settings.keepalive-time=${KEEPALIVE_TIME_SCORING:0} -ct.scoring-data-source-settings.leak-detection-threshold=${DETECTION_THRESHOLD_SCORING:0} +ct.scoring-data-source-settings.leak-detection-threshold=${LEAK_DETECTION_THRESHOLD_SCORING:0} ct.max_xml_file_size=${ACCEPTED_XML_SIZE:1024} spring.servlet.multipart.max-file-size=${ACCEPTED_ARCHIVE_SIZE:2048MB} diff --git a/docker_compose/credit_tracker_config.env b/docker_compose/credit_tracker_config.env index 437d729..83cc49c 100644 --- a/docker_compose/credit_tracker_config.env +++ b/docker_compose/credit_tracker_config.env @@ -31,7 +31,7 @@ VALIDATION_TIMEOUT_INDIC=5000 IDLE_TIMEOUT_INDIC=600000 MAX_LIFETIME_INDIC=1800000 KEEPALIVE_TIME_INDIC=0 -DETECTION_THRESHOLD_INDIC=0 +LEAK_DETECTION_THRESHOLD_INDIC=0 # signal @@ -45,7 +45,7 @@ VALIDATION_TIMEOUT_SIGNAL=5000 IDLE_TIMEOUT_SIGNAL=600000 MAX_LIFETIME_SIGNAL=1800000 KEEPALIVE_TIME_SIGNAL=0 -DETECTION_THRESHOLD_SIGNAL=0 +LEAK_DETECTION_THRESHOLD_SIGNAL=0 # scoring DB_URL_SCORING=jdbc:db2://10.230.227.101:2668/cprosd22:currentSchema=TEST_2_INDIC; @@ -58,7 +58,7 @@ VALIDATION_TIMEOUT_SCORING=5000 IDLE_TIMEOUT_SCORING=600000 MAX_LIFETIME_SCORING=1800000 KEEPALIVE_TIME_SCORING=0 -DETECTION_THRESHOLD_SCORING=0 +LEAK_DETECTION_THRESHOLD_SCORING=0 # размер в mb ACCEPTED_XML_SIZE=1024 diff --git a/docker_compose/docker-compose.yml b/docker_compose/docker-compose.yml index 1c069df..91f933c 100644 --- a/docker_compose/docker-compose.yml +++ b/docker_compose/docker-compose.yml @@ -30,7 +30,7 @@ services: - IDLE_TIMEOUT_INDIC=${IDLE_TIMEOUT_INDIC} - MAX_LIFETIME_INDIC=${MAX_LIFETIME_INDIC} - KEEPALIVE_TIME_INDIC=${KEEPALIVE_TIME_INDIC} - - DETECTION_THRESHOLD_INDIC=${DETECTION_THRESHOLD_INDIC} + - LEAK_DETECTION_THRESHOLD_INDIC=${DETECTION_THRESHOLD_INDIC} - DB_URL_SIGNAL=${DB_URL_SIGNAL} - USERNAME_SIGNAL=${USERNAME_SIGNAL} - PASSWORD_SIGNAL=${PASSWORD_SIGNAL} @@ -41,7 +41,7 @@ services: - IDLE_TIMEOUT_SIGNAL=${IDLE_TIMEOUT_SIGNAL} - MAX_LIFETIME_SIGNAL=${MAX_LIFETIME_SIGNAL} - KEEPALIVE_TIME_SIGNAL=${KEEPALIVE_TIME_SIGNAL} - - DETECTION_THRESHOLD_SIGNAL=${DETECTION_THRESHOLD_SIGNAL} + - LEAK_DETECTION_THRESHOLD_SIGNAL=${DETECTION_THRESHOLD_SIGNAL} - DB_URL_SCORING=${DB_URL_SCORING} - USERNAME_SCORING=${USERNAME_SCORING} - PASSWORD_SCORING=${PASSWORD_SCORING} @@ -52,7 +52,7 @@ services: - IDLE_TIMEOUT_SCORING=${IDLE_TIMEOUT_SCORING} - MAX_LIFETIME_SCORING=${MAX_LIFETIME_SCORING} - KEEPALIVE_TIME_SCORING=${KEEPALIVE_TIME_SCORING} - - DETECTION_THRESHOLD_SCORING=${DETECTION_THRESHOLD_SCORING} + - LEAK_DETECTION_THRESHOLD_SCORING=${DETECTION_THRESHOLD_SCORING} - ACCEPTED_XML_SIZE=${ACCEPTED_XML_SIZE} - ACCEPTED_ARCHIVE_SIZE=${ACCEPTED_ARCHIVE_SIZE} - SIGNALS_ROOT_URI=${SIGNALS_ROOT_URI} From dc89f17761e40b2a1e1c1effa17c4b0ea6f046cd Mon Sep 17 00:00:00 2001 From: Mikhail Trofimov Date: Wed, 1 Oct 2025 14:45:07 +0300 Subject: [PATCH 09/16] http://jira.mfd.msk:8088/browse/BKI-3215 Added reqParams to HttpLoggingFilter --- .../rest/filters/HttpLoggingFilter.java | 70 +++++++++++-------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java b/src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java index aae7ecb..2fa0db6 100644 --- a/src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java +++ b/src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java @@ -4,6 +4,7 @@ import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.Part; import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -13,7 +14,6 @@ import org.springframework.web.util.ContentCachingRequestWrapper; import org.springframework.web.util.ContentCachingResponseWrapper; import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.util.*; import java.util.stream.Collectors; @@ -29,12 +29,12 @@ public class HttpLoggingFilter extends OncePerRequestFilter { protected boolean shouldNotFilter(HttpServletRequest request) { String path = request.getRequestURI(); return path.startsWith("/actuator/health") || path.startsWith("/swagger") - || path.startsWith("/v3/api-docs") || path.startsWith("/static/"); + || path.startsWith("/v3/api-docs") || path.startsWith("/static/") || path.equals("/"); } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) - throws ServletException, IOException { + throws ServletException, IOException { long startNs = System.nanoTime(); @@ -42,8 +42,8 @@ public class HttpLoggingFilter extends OncePerRequestFilter { ContentCachingResponseWrapper resp = new ContentCachingResponseWrapper(response); String correlationId = Optional.ofNullable(request.getHeader("X-Correlation-Id")) - .filter(StringUtils::hasText) - .orElse(UUID.randomUUID().toString()); + .filter(StringUtils::hasText) + .orElse(UUID.randomUUID().toString()); resp.setHeader("X-Correlation-Id", correlationId); logIncomingRequest(req, correlationId); @@ -53,8 +53,7 @@ public class HttpLoggingFilter extends OncePerRequestFilter { } finally { long tookMs = (System.nanoTime() - startNs) / 1_000_000; - String requestBody = readBody(req.getContentAsByteArray(), req.getCharacterEncoding()); - String responseBody = readBody(resp.getContentAsByteArray(), resp.getCharacterEncoding()); + Map reqParams = paramsMap(req); Map reqHeaders = headersMap(req); Map respHeaders = headersMap(resp); @@ -63,17 +62,16 @@ public class HttpLoggingFilter extends OncePerRequestFilter { mask(respHeaders); log.info( - "HTTP (RESPONSE) {} {}{} | status={} | took={}ms | cid={} | reqHeaders={} | reqBody={} | respHeaders={} | respBody={}", - req.getMethod(), - req.getRequestURI(), - req.getQueryString() == null ? "" : "?" + req.getQueryString(), - resp.getStatus(), - tookMs, - correlationId, - reqHeaders, - requestBody, - respHeaders, - responseBody + "HTTP (RESPONSE) {} {}{} | status={} | took={}ms | cid={} | reqHeaders={} | reqParams={} | respHeaders={}", + req.getMethod(), + req.getRequestURI(), + req.getQueryString() == null ? "" : "?" + req.getQueryString(), + resp.getStatus(), + tookMs, + correlationId, + reqHeaders, + reqParams, + respHeaders ); resp.copyBodyToResponse(); @@ -82,19 +80,19 @@ public class HttpLoggingFilter extends OncePerRequestFilter { private void logIncomingRequest(ContentCachingRequestWrapper req, String correlationId) { - String requestBody = readBody(req.getContentAsByteArray(), req.getCharacterEncoding()); + Map reqParams = paramsMap(req); Map reqHeaders = headersMap(req); mask(reqHeaders); log.info( - "HTTP (REQUEST) {} {}{} | cid={} | reqHeaders={} | reqBody={}", + "HTTP (REQUEST) {} {}{} | cid={} | reqHeaders={} | reqParams={}", req.getMethod(), req.getRequestURI(), req.getQueryString() == null ? "" : "?" + req.getQueryString(), correlationId, reqHeaders, - requestBody + reqParams ); } @@ -102,22 +100,32 @@ public class HttpLoggingFilter extends OncePerRequestFilter { return (request instanceof ContentCachingRequestWrapper c) ? c : new ContentCachingRequestWrapper(request, MAX_BODY); } - private static String readBody(byte[] buf, String encoding) { - if (buf == null || buf.length == 0) return ""; - var bytes = buf.length > MAX_BODY ? Arrays.copyOf(buf, MAX_BODY) : buf; - String body = new String(bytes, encoding != null ? java.nio.charset.Charset.forName(encoding) : StandardCharsets.UTF_8); - if (buf.length > MAX_BODY) body += "…[truncated]"; - return body; - } - private static Map headersMap(HttpServletRequest req) { return Collections.list(req.getHeaderNames()).stream() - .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 Map paramsMap(ContentCachingRequestWrapper req) { + Map paramsMap = new LinkedHashMap<>(); + req.getParameterMap().forEach((k, v) -> { + String params = String.join(", ", v); + paramsMap.put(k, params); + }); + + try { + Collection fileParts = req.getParts(); + fileParts.forEach(part -> { + paramsMap.put(part.getName(), part.getSubmittedFileName()); + }); + } catch (Exception e) { + // ignore + } + return paramsMap; } private static Map headersMap(HttpServletResponse resp) { return resp.getHeaderNames().stream() - .collect(Collectors.toMap(h -> h, resp::getHeader, (a, b) -> a, LinkedHashMap::new)); + .collect(Collectors.toMap(h -> h, resp::getHeader, (a, b) -> a, LinkedHashMap::new)); } private static void mask(Map headers) { From 6571e4d90fe8589fadae948e268f2ff1588c634e Mon Sep 17 00:00:00 2001 From: Mikhail Trofimov Date: Wed, 1 Oct 2025 15:50:46 +0300 Subject: [PATCH 10/16] http://jira.mfd.msk:8088/browse/BKI-3215 Added packageName to SignalClientException for logging it on error --- .../config/rest/GlobalExceptionHandler.java | 7 ++++++- .../exceptions/SignalClientException.java | 5 ++++- .../nbch/credit_tracker/facade/SignalFacade.java | 4 ++-- .../credit_tracker/utils/ValidationService.java | 16 +++++++++------- .../utils/error/ExceptionUtils.java | 6 +++++- 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/main/java/ru/nbch/credit_tracker/config/rest/GlobalExceptionHandler.java b/src/main/java/ru/nbch/credit_tracker/config/rest/GlobalExceptionHandler.java index b0824b1..edbbabb 100644 --- a/src/main/java/ru/nbch/credit_tracker/config/rest/GlobalExceptionHandler.java +++ b/src/main/java/ru/nbch/credit_tracker/config/rest/GlobalExceptionHandler.java @@ -55,7 +55,12 @@ public class GlobalExceptionHandler { commonError.setErrorText(errorText); if (ex instanceof SignalClientException) { - log.warn("Response error: {}", errorText); + String packageName = ((SignalClientException) ex).getPackageName(); + if(packageName != null ) { + log.warn("Response error: {}. PackageName: {}", errorText, packageName); + } else { + log.warn("Response error: {}", errorText); + } return new ResponseEntity<>(commonError, headers, HttpStatus.BAD_REQUEST); } else { Exception cause = ((SignalServerException) ex).getCause(); diff --git a/src/main/java/ru/nbch/credit_tracker/exceptions/SignalClientException.java b/src/main/java/ru/nbch/credit_tracker/exceptions/SignalClientException.java index ebf18f4..5db06c0 100644 --- a/src/main/java/ru/nbch/credit_tracker/exceptions/SignalClientException.java +++ b/src/main/java/ru/nbch/credit_tracker/exceptions/SignalClientException.java @@ -7,7 +7,10 @@ import ru.nbch.credit_tracker.enums.XmlErrorFormat; @Getter public class SignalClientException extends SignalException { - public SignalClientException(EnumKeyMessage errorMessage, XmlErrorFormat errorFormat) { + private final String packageName; + + public SignalClientException(EnumKeyMessage errorMessage, XmlErrorFormat errorFormat, String packageName) { super(errorMessage, errorFormat); + this.packageName = packageName; } } diff --git a/src/main/java/ru/nbch/credit_tracker/facade/SignalFacade.java b/src/main/java/ru/nbch/credit_tracker/facade/SignalFacade.java index 81a1802..e904779 100644 --- a/src/main/java/ru/nbch/credit_tracker/facade/SignalFacade.java +++ b/src/main/java/ru/nbch/credit_tracker/facade/SignalFacade.java @@ -156,13 +156,13 @@ public class SignalFacade { AuthorizationService.AuthResult authResult = authorizationService.findAuthInfo(monitoringRequest.getUserId(), monitoringRequest.getPassword()); if (!authResult.isSuccess()) { signalService.rejectPackage(monitoringRequest); - throw clientExcp(authResult.getError(), XmlErrorFormat.MonitoringError); + throw clientExcp(authResult.getError(), monitoringRequest.getPackageName(), XmlErrorFormat.MonitoringError); } // проверка на уникальность пакета if (signalService.isPackageNotUnique(monitoringRequest)) { signalService.rejectPackage(monitoringRequest); - throw clientExcp(SignalError.ERROR_007, XmlErrorFormat.MonitoringError); + throw clientExcp(SignalError.ERROR_007, monitoringRequest.getPackageName(), XmlErrorFormat.MonitoringError); } packageId = signalService.registerPackage(monitoringRequest); diff --git a/src/main/java/ru/nbch/credit_tracker/utils/ValidationService.java b/src/main/java/ru/nbch/credit_tracker/utils/ValidationService.java index 6273d7c..9e7875d 100644 --- a/src/main/java/ru/nbch/credit_tracker/utils/ValidationService.java +++ b/src/main/java/ru/nbch/credit_tracker/utils/ValidationService.java @@ -31,32 +31,34 @@ public class ValidationService { throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "PackageName"); } + String packageName = request.getPackageName(); + if (!validatePackageName(request.getPackageName())) { - throw clientExcp(SignalError.ERROR_008, XmlErrorFormat.MonitoringError); + throw clientExcp(SignalError.ERROR_008, packageName, XmlErrorFormat.MonitoringError); } if (request.getUserId() == null) { - throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "UserId"); + throw clientExcp(SignalError.ERROR_002, packageName, XmlErrorFormat.MonitoringError, "UserId"); } if (request.getPassword() == null) { - throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "Password"); + throw clientExcp(SignalError.ERROR_002, packageName, XmlErrorFormat.MonitoringError, "Password"); } if (request.getSubjects() == null) { - throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "Subjects"); + throw clientExcp(SignalError.ERROR_002, packageName, XmlErrorFormat.MonitoringError, "Subjects"); } if (request.getSubjects().getSubject().isEmpty()) { - throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "Subject"); + throw clientExcp(SignalError.ERROR_002, packageName, XmlErrorFormat.MonitoringError, "Subject"); } for (Subject subject : request.getSubjects().getSubject()) { if (!validateNPId(subject.getId())) { - throw clientExcp(SignalError.ERROR_010, XmlErrorFormat.MonitoringError, subject.getId()); + throw clientExcp(SignalError.ERROR_010, packageName, XmlErrorFormat.MonitoringError, subject.getId()); } if (!validatePhone(subject.getClientId())) { - throw clientExcp(SignalError.ERROR_003, XmlErrorFormat.MonitoringError, subject.getId()); + throw clientExcp(SignalError.ERROR_003, packageName, XmlErrorFormat.MonitoringError, subject.getId()); } } } diff --git a/src/main/java/ru/nbch/credit_tracker/utils/error/ExceptionUtils.java b/src/main/java/ru/nbch/credit_tracker/utils/error/ExceptionUtils.java index 2e94e78..af7969e 100644 --- a/src/main/java/ru/nbch/credit_tracker/utils/error/ExceptionUtils.java +++ b/src/main/java/ru/nbch/credit_tracker/utils/error/ExceptionUtils.java @@ -9,7 +9,11 @@ import ru.nbch.credit_tracker.exceptions.SignalServerException; public class ExceptionUtils { public static SignalClientException clientExcp(IEnumKeyCode enumKeyCode, XmlErrorFormat xmlErrorFormat, Object... args) { - return new SignalClientException(new EnumKeyMessage(enumKeyCode, args), xmlErrorFormat); + return clientExcp(enumKeyCode, null, xmlErrorFormat, args); + } + + public static SignalClientException clientExcp(IEnumKeyCode enumKeyCode, String packageName, XmlErrorFormat xmlErrorFormat, Object... args) { + return new SignalClientException(new EnumKeyMessage(enumKeyCode, args), xmlErrorFormat, packageName); } public static SignalServerException serverExcp(IEnumKeyCode enumKeyCode, XmlErrorFormat xmlErrorFormat, Exception cause, Object... args) { From 9a44d8cd5ef14601ea2bec7d40d626afe2041619 Mon Sep 17 00:00:00 2001 From: Mikhail Trofimov Date: Wed, 1 Oct 2025 15:52:46 +0300 Subject: [PATCH 11/16] Updated version to 1.16 --- docker_compose/credit_tracker_config.env | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker_compose/credit_tracker_config.env b/docker_compose/credit_tracker_config.env index 83cc49c..f21fa97 100644 --- a/docker_compose/credit_tracker_config.env +++ b/docker_compose/credit_tracker_config.env @@ -1,5 +1,5 @@ #commons -APP_VERSION=1.15 +APP_VERSION=1.16 REGISTRY_URL=rh8-vm3.nbki.msk:5000 JMX_PORT= JMX_HOSTNAME= diff --git a/pom.xml b/pom.xml index ffd17aa..e70baba 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ru.nbch credit-tracker - 1.15 + 1.16 credit_tracker Credit Tracker Application From 10180bb4713bc062bb57c62e8904804e74085ccb Mon Sep 17 00:00:00 2001 From: Mikhail Trofimov Date: Wed, 1 Oct 2025 16:24:38 +0300 Subject: [PATCH 12/16] Get rid of pluginManagement --- pom.xml | 520 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 261 insertions(+), 259 deletions(-) diff --git a/pom.xml b/pom.xml index e70baba..aa60f04 100644 --- a/pom.xml +++ b/pom.xml @@ -1,267 +1,269 @@ - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 3.4.6 - - - ru.nbch - credit-tracker - 1.16 - credit_tracker - Credit Tracker Application + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.4.6 + + + ru.nbch + credit-tracker + 1.16 + credit_tracker + Credit Tracker Application - - 17 - git_info - git.properties - rh8-vm3.nbki.msk:5000 - - + + 17 + git_info + git.properties + rh8-vm3.nbki.msk:5000 + + - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-aop - - - org.mybatis.spring.boot - mybatis-spring-boot-starter - 3.0.4 - - - org.postgresql - postgresql - runtime - - - com.ibm.db2 - jcc - 12.1.0.0 - - - org.projectlombok - lombok - true - - - org.slf4j - slf4j-api - 2.0.7 - - - ch.qos.logback - logback-classic - 1.4.12 - - - ch.qos.logback - logback-core - - - - - ch.qos.logback - logback-core - 1.5.12 - - - org.apache.commons - commons-lang3 - 3.17.0 - - - commons-io - commons-io - 2.18.0 - - - - jakarta.xml.bind - jakarta.xml.bind-api - 4.0.2 - - - - org.eclipse.persistence - org.eclipse.persistence.moxy - 4.0.2 - - - - com.sun.activation - jakarta.activation - 2.0.1 - - - co.elastic.apm - apm-agent-api - 1.43.0 - - - com.internetitem - logback-elasticsearch-appender - 1.6 - - - net.logstash.logback - logstash-logback-encoder - 7.4 - - - org.springframework.boot - spring-boot-starter-test - test - - - org.mybatis.spring.boot - mybatis-spring-boot-starter-test - 3.0.4 - test - - - org.mockito - mockito-junit-jupiter - test - - + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-aop + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 3.0.4 + + + org.postgresql + postgresql + runtime + + + com.ibm.db2 + jcc + 12.1.0.0 + + + org.projectlombok + lombok + true + + + org.slf4j + slf4j-api + 2.0.7 + + + ch.qos.logback + logback-classic + 1.4.12 + + + ch.qos.logback + logback-core + + + + + ch.qos.logback + logback-core + 1.5.12 + + + org.apache.commons + commons-lang3 + 3.17.0 + + + commons-io + commons-io + 2.18.0 + + + + jakarta.xml.bind + jakarta.xml.bind-api + 4.0.2 + + + + org.eclipse.persistence + org.eclipse.persistence.moxy + 4.0.2 + + + + com.sun.activation + jakarta.activation + 2.0.1 + + + co.elastic.apm + apm-agent-api + 1.43.0 + + + com.internetitem + logback-elasticsearch-appender + 1.6 + + + net.logstash.logback + logstash-logback-encoder + 7.4 + + + org.springframework.boot + spring-boot-starter-test + test + + + org.mybatis.spring.boot + mybatis-spring-boot-starter-test + 3.0.4 + test + + + org.mockito + mockito-junit-jupiter + test + + - - - docker-push-dev - - - - - io.fabric8 - docker-maven-plugin - 0.45.0 - - - Build and deploy docker container - install - - - push - - - - - - - ${project.artifactId}:${project.version} - ${registry.url} - - ${project.basedir}/Dockerfile - - - - - ${project.build.directory}/${project.build.finalName}.jar - . - - - ${project.basedir}/apm-agent/elastic-apm-agent-1.45.0.jar - . - - - ${project.basedir}/start-credit-tracker.sh - . - - - ${project.basedir}/credit-tracker.properties - . - - - ${project.basedir}/monitoring-request.xsd - . - - - ${project.basedir}/signal-package.xsd - . - - - - - - ${project.version} - - - - - - - - - - - - - credit-tracker - - - org.apache.maven.plugins - maven-compiler-plugin - - - - org.projectlombok - lombok - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - - - pl.project13.maven - git-commit-id-plugin - 4.9.10 - - - get-the-git-infos - - revision - - compile - - - - false - ${project.basedir}/${git.info.relative.dir} - true - - ${project.build.outputDirectory}/${git.info.filename} - - ${git.info.prefix} - - ${git.info.prefix}.commit.id - ${git.info.prefix}.branch - ${git.info.prefix}.build.version - ${git.info.prefix}.build.time - ${git.info.prefix}.closest.tag.name - - - + + + docker-push-dev + + + + io.fabric8 + docker-maven-plugin + 0.45.0 + + + Build and deploy docker container + install + + build + push + + + + + + + ${project.artifactId}:${project.version} + ${registry.url} + + ${project.basedir}/Dockerfile + + + + + + ${project.build.directory}/${project.build.finalName}.jar + + . + + + + ${project.basedir}/apm-agent/elastic-apm-agent-1.45.0.jar + + . + + + ${project.basedir}/start-credit-tracker.sh + . + + + ${project.basedir}/credit-tracker.properties + . + + + ${project.basedir}/monitoring-request.xsd + . + + + ${project.basedir}/signal-package.xsd + . + + + + + + ${project.version} + + + + + + + + + + + + credit-tracker + + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.projectlombok + lombok + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + pl.project13.maven + git-commit-id-plugin + 4.9.10 + + + get-the-git-infos + + revision + + compile + + + + false + ${project.basedir}/${git.info.relative.dir} + true + + ${project.build.outputDirectory}/${git.info.filename} + + ${git.info.prefix} + + ${git.info.prefix}.commit.id + ${git.info.prefix}.branch + ${git.info.prefix}.build.version + ${git.info.prefix}.build.time + ${git.info.prefix}.closest.tag.name + + + - - + + From 83bcea13b1ddbfa4c17a81c0e661834d50a6d9f4 Mon Sep 17 00:00:00 2001 From: Mikhail Trofimov Date: Thu, 2 Oct 2025 10:03:44 +0300 Subject: [PATCH 13/16] http://jira.mfd.msk:8088/browse/BKI-3231 Minor fix --- docker_compose/docker-compose.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker_compose/docker-compose.yml b/docker_compose/docker-compose.yml index 91f933c..7c6a16a 100644 --- a/docker_compose/docker-compose.yml +++ b/docker_compose/docker-compose.yml @@ -30,7 +30,7 @@ services: - IDLE_TIMEOUT_INDIC=${IDLE_TIMEOUT_INDIC} - MAX_LIFETIME_INDIC=${MAX_LIFETIME_INDIC} - KEEPALIVE_TIME_INDIC=${KEEPALIVE_TIME_INDIC} - - LEAK_DETECTION_THRESHOLD_INDIC=${DETECTION_THRESHOLD_INDIC} + - LEAK_DETECTION_THRESHOLD_INDIC=${LEAK_DETECTION_THRESHOLD_INDIC} - DB_URL_SIGNAL=${DB_URL_SIGNAL} - USERNAME_SIGNAL=${USERNAME_SIGNAL} - PASSWORD_SIGNAL=${PASSWORD_SIGNAL} @@ -41,7 +41,7 @@ services: - IDLE_TIMEOUT_SIGNAL=${IDLE_TIMEOUT_SIGNAL} - MAX_LIFETIME_SIGNAL=${MAX_LIFETIME_SIGNAL} - KEEPALIVE_TIME_SIGNAL=${KEEPALIVE_TIME_SIGNAL} - - LEAK_DETECTION_THRESHOLD_SIGNAL=${DETECTION_THRESHOLD_SIGNAL} + - LEAK_DETECTION_THRESHOLD_SIGNAL=${LEAK_DETECTION_THRESHOLD_SIGNAL} - DB_URL_SCORING=${DB_URL_SCORING} - USERNAME_SCORING=${USERNAME_SCORING} - PASSWORD_SCORING=${PASSWORD_SCORING} @@ -52,7 +52,7 @@ services: - IDLE_TIMEOUT_SCORING=${IDLE_TIMEOUT_SCORING} - MAX_LIFETIME_SCORING=${MAX_LIFETIME_SCORING} - KEEPALIVE_TIME_SCORING=${KEEPALIVE_TIME_SCORING} - - LEAK_DETECTION_THRESHOLD_SCORING=${DETECTION_THRESHOLD_SCORING} + - LEAK_DETECTION_THRESHOLD_SCORING=${LEAK_DETECTION_THRESHOLD_SCORING} - ACCEPTED_XML_SIZE=${ACCEPTED_XML_SIZE} - ACCEPTED_ARCHIVE_SIZE=${ACCEPTED_ARCHIVE_SIZE} - SIGNALS_ROOT_URI=${SIGNALS_ROOT_URI} From b61970a71e6688095ba058ecbd68403b4c646b43 Mon Sep 17 00:00:00 2001 From: Mikhail Trofimov Date: Thu, 2 Oct 2025 10:07:30 +0300 Subject: [PATCH 14/16] http://jira.mfd.msk:8088/browse/BKI-3215 Changed log error lvl to warn for getErrorFileName method --- .../nbch/credit_tracker/service/signal/SignalRestService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ru/nbch/credit_tracker/service/signal/SignalRestService.java b/src/main/java/ru/nbch/credit_tracker/service/signal/SignalRestService.java index 9bf608d..2d30db2 100644 --- a/src/main/java/ru/nbch/credit_tracker/service/signal/SignalRestService.java +++ b/src/main/java/ru/nbch/credit_tracker/service/signal/SignalRestService.java @@ -131,7 +131,7 @@ public class SignalRestService { SgnlReportMonitorigSetupError report = xmlProcessor.read(answer, SgnlReportMonitorigSetupError.class); if (report.getOperationReport().getErrorsForNextReport() != null) { String fileName = report.getOperationReport().getErrorsForNextReport().getFilename(); - log.error("Найдены ошибки по пакету. packCode={}, packageId={}, fileName = {}", packCode, packageId, fileName); + log.warn("Найдены ошибки по пакету. packCode={}, packageId={}, fileName = {}", packCode, packageId, fileName); return fileName; } else { log.info("Пакет был поставлен на мониторинг без ошибок. packCode={}, packageId={}", packCode, packageId); From 3b9c2eaa1515d413aaf13e227e469989bede5cfb Mon Sep 17 00:00:00 2001 From: Mikhail Trofimov Date: Mon, 6 Oct 2025 15:37:27 +0300 Subject: [PATCH 15/16] http://jira.mfd.msk:8088/browse/BKI-3215 Added CachedHttpRequestWrapper to handle request body before doFilter invocation; Added memberCode ro logs; Updated version to 1.17 --- docker_compose/credit_tracker_config.env | 2 +- pom.xml | 2 +- .../rest/filters/HttpLoggingFilter.java | 84 ++++++++++++++++--- .../wrappers/CachedHttpRequestWrapper.java | 47 +++++++++++ .../credit_tracker/config/xml/XmlConfig.java | 4 + 5 files changed, 125 insertions(+), 14 deletions(-) create mode 100644 src/main/java/ru/nbch/credit_tracker/config/rest/wrappers/CachedHttpRequestWrapper.java diff --git a/docker_compose/credit_tracker_config.env b/docker_compose/credit_tracker_config.env index f21fa97..7678f1a 100644 --- a/docker_compose/credit_tracker_config.env +++ b/docker_compose/credit_tracker_config.env @@ -1,5 +1,5 @@ #commons -APP_VERSION=1.16 +APP_VERSION=1.17 REGISTRY_URL=rh8-vm3.nbki.msk:5000 JMX_PORT= JMX_HOSTNAME= diff --git a/pom.xml b/pom.xml index aa60f04..f2f11fe 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ru.nbch credit-tracker - 1.16 + 1.17 credit_tracker Credit Tracker Application diff --git a/src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java b/src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java index 2fa0db6..7b33f68 100644 --- a/src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java +++ b/src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java @@ -3,6 +3,7 @@ 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.HttpServletRequestWrapper; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.Part; import lombok.extern.slf4j.Slf4j; @@ -12,11 +13,18 @@ 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) @@ -25,6 +33,12 @@ public class HttpLoggingFilter extends OncePerRequestFilter { private static final Set 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(); @@ -38,7 +52,7 @@ public class HttpLoggingFilter extends OncePerRequestFilter { long startNs = System.nanoTime(); - ContentCachingRequestWrapper req = wrapRequest(request); + HttpServletRequestWrapper req = wrapRequest(request); ContentCachingResponseWrapper resp = new ContentCachingResponseWrapper(response); String correlationId = Optional.ofNullable(request.getHeader("X-Correlation-Id")) @@ -46,14 +60,15 @@ public class HttpLoggingFilter extends OncePerRequestFilter { .orElse(UUID.randomUUID().toString()); resp.setHeader("X-Correlation-Id", correlationId); - logIncomingRequest(req, correlationId); + String memberCode = parseMemberCode(req); + logIncomingRequest(req, correlationId, memberCode); try { chain.doFilter(req, resp); } finally { long tookMs = (System.nanoTime() - startNs) / 1_000_000; - Map reqParams = paramsMap(req); + Map reqParams = paramsMap(req, memberCode); Map reqHeaders = headersMap(req); Map respHeaders = headersMap(resp); @@ -62,10 +77,9 @@ public class HttpLoggingFilter extends OncePerRequestFilter { mask(respHeaders); log.info( - "HTTP (RESPONSE) {} {}{} | status={} | took={}ms | cid={} | reqHeaders={} | reqParams={} | respHeaders={}", + "HTTP (RESPONSE) {} {} | status={} | took={}ms | cid={} | reqHeaders={} | reqParams={} | respHeaders={}", req.getMethod(), req.getRequestURI(), - req.getQueryString() == null ? "" : "?" + req.getQueryString(), resp.getStatus(), tookMs, correlationId, @@ -78,34 +92,75 @@ public class HttpLoggingFilter extends OncePerRequestFilter { } } + private String parseMemberCode(HttpServletRequestWrapper req) { + String memberCode = null; + if (!(req instanceof CachedHttpRequestWrapper)) { + return null; + } - private void logIncomingRequest(ContentCachingRequestWrapper req, String correlationId) { - Map reqParams = paramsMap(req); + 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 reqParams = paramsMap(req, memberCode); Map reqHeaders = headersMap(req); mask(reqHeaders); log.info( - "HTTP (REQUEST) {} {}{} | cid={} | reqHeaders={} | reqParams={}", + "HTTP (REQUEST) {} {} | cid={} | reqHeaders={} | reqParams={}", req.getMethod(), req.getRequestURI(), - req.getQueryString() == null ? "" : "?" + req.getQueryString(), correlationId, reqHeaders, reqParams ); } - private static ContentCachingRequestWrapper wrapRequest(HttpServletRequest request) { - return (request instanceof ContentCachingRequestWrapper c) ? c : new ContentCachingRequestWrapper(request, MAX_BODY); + 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 Map headersMap(HttpServletRequest req) { return Collections.list(req.getHeaderNames()).stream() .collect(Collectors.toMap(h -> h, req::getHeader, (a, b) -> a, LinkedHashMap::new)); } - private Map paramsMap(ContentCachingRequestWrapper req) { + private static Map paramsMap(HttpServletRequestWrapper req, String memberCode) { Map paramsMap = new LinkedHashMap<>(); req.getParameterMap().forEach((k, v) -> { String params = String.join(", ", v); @@ -120,6 +175,11 @@ public class HttpLoggingFilter extends OncePerRequestFilter { } catch (Exception e) { // ignore } + + if (memberCode != null) { + paramsMap.put("memberCode", memberCode); + } + return paramsMap; } diff --git a/src/main/java/ru/nbch/credit_tracker/config/rest/wrappers/CachedHttpRequestWrapper.java b/src/main/java/ru/nbch/credit_tracker/config/rest/wrappers/CachedHttpRequestWrapper.java new file mode 100644 index 0000000..bf2517a --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/config/rest/wrappers/CachedHttpRequestWrapper.java @@ -0,0 +1,47 @@ +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; + + + public CachedHttpRequestWrapper(HttpServletRequest request) throws IOException { + super(request); + body = IOUtils.toString(request.getReader()); + } + + @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) { + } + }; + } + +} diff --git a/src/main/java/ru/nbch/credit_tracker/config/xml/XmlConfig.java b/src/main/java/ru/nbch/credit_tracker/config/xml/XmlConfig.java index f9fdca5..3e6e435 100644 --- a/src/main/java/ru/nbch/credit_tracker/config/xml/XmlConfig.java +++ b/src/main/java/ru/nbch/credit_tracker/config/xml/XmlConfig.java @@ -6,6 +6,8 @@ import org.springframework.context.annotation.Configuration; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; import ru.nbch.credit_tracker.entities.external_response.monitoring_report_file.SgnlReportMonitorigSetupError; import ru.nbch.credit_tracker.entities.external_response.online_report.SgnlOnlineReport; +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.entities.user_response.errors.MonitoringError; import ru.nbch.credit_tracker.entities.user_response.success.MonitoringSetupResponse; import ru.nbch.credit_tracker.service.xml.jaxb.IXmlProcessor; @@ -26,6 +28,8 @@ public class XmlConfig { // unmarshalling classes SgnlOnlineReport.class, SgnlReportMonitorigSetupError.class, + MonitoringActivePackagesRequest.class, + MonitoringAllPackagesRequest.class, // marshalling classes MonitoringError.class, MonitoringSetupResponse.class); From f950f985367f819ab6a75284846d9f1166302288 Mon Sep 17 00:00:00 2001 From: Mikhail Trofimov Date: Mon, 6 Oct 2025 17:11:03 +0300 Subject: [PATCH 16/16] http://jira.mfd.msk:8088/browse/BKI-3215 Moved member code logging logic to MemberCodeHttpLoggingFilter; Added CachedServletInputStream; Updated CachedHttpRequestWrapper --- .../rest/filters/HttpLoggingFilter.java | 78 ++----------------- .../filters/MemberCodeHttpLoggingFilter.java | 55 +++++++++++++ .../wrappers/CachedHttpRequestWrapper.java | 28 +------ .../wrappers/CachedServletInputStream.java | 33 ++++++++ 4 files changed, 99 insertions(+), 95 deletions(-) create mode 100644 src/main/java/ru/nbch/credit_tracker/config/rest/filters/MemberCodeHttpLoggingFilter.java create mode 100644 src/main/java/ru/nbch/credit_tracker/config/rest/wrappers/CachedServletInputStream.java diff --git a/src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java b/src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java index 7b33f68..27f3fa2 100644 --- a/src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java +++ b/src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java @@ -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 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 reqParams = paramsMap(req, memberCode); + Map reqParams = paramsMap(req); Map reqHeaders = headersMap(req); Map 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 reqParams = paramsMap(req, memberCode); + private void logIncomingRequest(ContentCachingRequestWrapper req, String correlationId) { + Map reqParams = paramsMap(req); Map 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 paramsMap(HttpServletRequestWrapper req, String memberCode) { + private static Map paramsMap(HttpServletRequestWrapper req) { Map 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; } diff --git a/src/main/java/ru/nbch/credit_tracker/config/rest/filters/MemberCodeHttpLoggingFilter.java b/src/main/java/ru/nbch/credit_tracker/config/rest/filters/MemberCodeHttpLoggingFilter.java new file mode 100644 index 0000000..8e0e4ff --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/config/rest/filters/MemberCodeHttpLoggingFilter.java @@ -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("") + 8; + int endIndex = body.indexOf(""); + 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); + } +} diff --git a/src/main/java/ru/nbch/credit_tracker/config/rest/wrappers/CachedHttpRequestWrapper.java b/src/main/java/ru/nbch/credit_tracker/config/rest/wrappers/CachedHttpRequestWrapper.java index bf2517a..84d2231 100644 --- a/src/main/java/ru/nbch/credit_tracker/config/rest/wrappers/CachedHttpRequestWrapper.java +++ b/src/main/java/ru/nbch/credit_tracker/config/rest/wrappers/CachedHttpRequestWrapper.java @@ -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); } } diff --git a/src/main/java/ru/nbch/credit_tracker/config/rest/wrappers/CachedServletInputStream.java b/src/main/java/ru/nbch/credit_tracker/config/rest/wrappers/CachedServletInputStream.java new file mode 100644 index 0000000..04f718b --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/config/rest/wrappers/CachedServletInputStream.java @@ -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) { + } +}