diff --git a/pom.xml b/pom.xml
index f876eb6..efc39bf 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
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/controller/SignalController.java b/src/main/java/ru/nbch/credit_tracker/controller/SignalController.java
index cb7037b..401a9da 100644
--- a/src/main/java/ru/nbch/credit_tracker/controller/SignalController.java
+++ b/src/main/java/ru/nbch/credit_tracker/controller/SignalController.java
@@ -1,5 +1,6 @@
package ru.nbch.credit_tracker.controller;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
@@ -14,6 +15,7 @@ import ru.nbch.credit_tracker.entities.user_response.success.MonitoringReportLis
import ru.nbch.credit_tracker.entities.user_response.success.MonitoringSetupResponse;
import ru.nbch.credit_tracker.facade.SignalFacade;
+@Slf4j
@RestController
@RequestMapping("/api/v1/signal")
public class SignalController {
@@ -26,31 +28,37 @@ public class SignalController {
@PostMapping(value = "/set", produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity setupMonitoring(@RequestParam("file") MultipartFile file) {
+ log.info("Processing /api/v1/signal/set");
return signalFacade.setupMonitoring(file);
}
@PostMapping(value = "/active_packages", consumes = MediaType.APPLICATION_XML_VALUE, produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity findActivePackages(@RequestBody MonitoringActivePackagesRequest activePackagesRequest) {
+ log.info("Processing /api/v1/signal/active_packages. UserId: {}", activePackagesRequest.getUserId());
return signalFacade.findActivePackages(activePackagesRequest);
}
@PostMapping(value = "/all_packages", consumes = MediaType.APPLICATION_XML_VALUE, produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity findAllPackages(@RequestBody MonitoringAllPackagesRequest allPackagesRequest) {
+ log.info("Processing /api/v1/signal/all_packages. UserId: {}", allPackagesRequest.getUserId());
return signalFacade.findAllPackages(allPackagesRequest);
}
@PostMapping(value = "/delete", params = {"username", "packageName"}, produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity deletePackage(@RequestParam("username") String username, @RequestParam("packageName") String packageName) {
+ log.info("Processing /api/v1/signal/delete. UserName: {}", username);
return signalFacade.deletePackage(username, packageName);
}
@GetMapping(value = "/report_list", params = {"username", "packageName"}, produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity getReportList(@RequestParam("username") String username, @RequestParam("packageName") String packageName) {
+ log.info("Processing /api/v1/signal/report_list. UserName: {}, PackageName: {}", username, packageName);
return signalFacade.getReportList(username, packageName);
}
@GetMapping(value = "/download", params = "file", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity downloadFile(@RequestParam("file") String file) {
+ log.info("Processing /api/v1/signal/download. FileName: {}", file);
return signalFacade.downloadFile(file);
}
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/facade/SignalFacade.java b/src/main/java/ru/nbch/credit_tracker/facade/SignalFacade.java
index 218a1c8..855692c 100644
--- a/src/main/java/ru/nbch/credit_tracker/facade/SignalFacade.java
+++ b/src/main/java/ru/nbch/credit_tracker/facade/SignalFacade.java
@@ -7,6 +7,7 @@ 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;
@@ -33,6 +34,7 @@ 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.ZipUtils;
+import ru.nbch.credit_tracker.utils.error.SimpleMessageResolver;
import javax.xml.stream.XMLStreamException;
import java.io.BufferedInputStream;
@@ -61,6 +63,7 @@ public class SignalFacade {
private final SignalRestService signalRestService;
private final MonitoringErrorProcesingService monitoringErrorProcesingService;
private final StaxXmlProcessor staxXmlProcessor;
+ private final SimpleMessageResolver messageResolver;
private final ExecutorService executor;
private final long maxXmlFileSize;
@@ -81,12 +84,16 @@ public class SignalFacade {
this.staxXmlProcessor = staxXmlProcessor;
this.executor = executor;
this.maxXmlFileSize = config.getMaxXmlFileSize() * 1024 * 1024;
+ this.messageResolver = new SimpleMessageResolver();
}
public ResponseEntity setupMonitoring(MultipartFile file) {
// первичные валидации
if (file.isEmpty() || !isZipFile(file)) {
- throw clientExcp(SignalError.ERROR_001, XmlErrorFormat.MonitoringError);
+ SignalClientException e = clientExcp(SignalError.ERROR_001, XmlErrorFormat.MonitoringError);
+ String errorReason = messageResolver.resolve(e.getErrorMessage());
+ log.warn("/api/v1/signal/set failed. Reason: {}. File is empty or don't match the type.", errorReason);
+ throw e;
}
// Валидация Архива на количетсво файлов, размер и расширение
@@ -114,6 +121,8 @@ public class SignalFacade {
}
} catch (Exception e) {
if (e instanceof SignalClientException) {
+ String errorReason = messageResolver.resolve(((SignalClientException) e).getErrorMessage());
+ log.warn("/api/v1/signal/set failed on unzipping archive. Reason: {}", errorReason);
throw (SignalClientException) e;
}
log.error(e.getMessage(), e);
@@ -135,9 +144,12 @@ public class SignalFacade {
} catch (Exception e) {
CTUtil.removeFile(filePath);
if (e.getCause() instanceof XMLStreamException) {
+ log.warn("/api/v1/signal/set failed on reading xml. Reason: {}", e.getMessage());
throw clientExcp(SignalError.ERROR_011, XmlErrorFormat.MonitoringError);
}
if (e instanceof SignalClientException) {
+ String errorReason = messageResolver.resolve(((SignalClientException) e).getErrorMessage());
+ log.warn("/api/v1/signal/set failed on validation. Reason: {}", errorReason);
throw (SignalClientException) e;
}
log.error(e.getMessage(), e);
@@ -159,10 +171,12 @@ public class SignalFacade {
}
packageId = signalService.registerPackage(monitoringRequest);
- log.info("Package registered. PackageId {}. Status: {}", packageId, Status.PROCESSING.name());
+ log.info("Package registered. PackageId {}. PackageName: {}. Status: {}", packageId, monitoringRequest.getPackageName(), Status.PROCESSING.name());
} catch (Exception e) {
CTUtil.removeFile(filePath);
if (e instanceof SignalClientException) {
+ String errorReason = messageResolver.resolve(((SignalClientException) e).getErrorMessage());
+ log.warn("/api/v1/signal/set rejected. PackageName: {}. Reason: {}", monitoringRequest.getPackageName(), errorReason);
throw (SignalClientException) e;
}
log.error(e.getMessage(), e);
@@ -172,6 +186,7 @@ public class SignalFacade {
// в отдельном потоке запускаем регистрацию субъектов, поиск фидов и расчет флагов просрочек
registerFidsAndDebts(packageId, monitoringRequest.getPackageName(), filePath);
+ log.info("/api/v1/signal/set processed successfully. PackageName: {}", monitoringRequest.getPackageName());
return ResponseEntity.ok().body(new MonitoringSetupResponse());
}
@@ -220,6 +235,7 @@ public class SignalFacade {
}
}
+ @SetAndClearMdc(argIndex = 1)
private void registerFidsAndDebts(Integer packageId, String packageName, String filePath) {
executor.execute(() -> {
try {
@@ -273,12 +289,15 @@ public class SignalFacade {
packages.getPackages().add(pack);
});
response.setPackages(packages);
+ log.info("/api/v1/signal/active_packages processed successfully. UserId: {}", activePackagesRequest.getUserId());
return ResponseEntity.ok(response);
} else {
throw clientExcp(SignalError.ERROR_015, XmlErrorFormat.MonitoringActivePackagesError);
}
} catch (Exception e) {
if (e instanceof SignalClientException) {
+ String errorReason = messageResolver.resolve(((SignalClientException) e).getErrorMessage());
+ log.warn("/api/v1/signal/active_packages failed. UserId: {}. Reason: {}", activePackagesRequest.getUserId(), errorReason);
throw (SignalClientException) e;
}
log.error(e.getMessage(), e);
@@ -310,12 +329,15 @@ public class SignalFacade {
packages.getPackages().add(pack);
});
response.setPackages(packages);
+ log.info("/api/v1/signal/all_packages processed successfully. UserId: {}", allPackagesRequest.getUserId());
return ResponseEntity.ok(response);
} else {
throw clientExcp(SignalError.ERROR_019, XmlErrorFormat.MonitoringActivePackagesError);
}
} catch (Exception e) {
if (e instanceof SignalClientException) {
+ String errorReason = messageResolver.resolve(((SignalClientException) e).getErrorMessage());
+ log.warn("/api/v1/signal/all_packages failed. UserId: {}. Reason: {}", allPackagesRequest.getUserId(), errorReason);
throw (SignalClientException) e;
}
log.error(e.getMessage(), e);
@@ -339,9 +361,12 @@ public class SignalFacade {
signalRestService.deletePackage(username, packageName);
log.info("Package {} deleted", packageName);
+ log.info("/api/v1/signal/delete processed successfully. UserName: {}, PackageName: {}", username, packageName);
return ResponseEntity.ok(response);
} catch (Exception e) {
if (e instanceof SignalClientException) {
+ String errorReason = messageResolver.resolve(((SignalClientException) e).getErrorMessage());
+ log.warn("/api/v1/signal/delete failed. UserName: {}, PackageName: {}, Reason: {}", username, packageName, errorReason);
throw (SignalClientException) e;
}
log.error(e.getMessage(), e);
@@ -386,9 +411,12 @@ public class SignalFacade {
MonitoringReportListResponse response = new MonitoringReportListResponse();
response.setPackageName(packageName);
response.setReports(reports);
+ log.info("/api/v1/signal/report_list processes successfully. UserName: {}, PackageName: {}", username, packageName);
return ResponseEntity.ok(response);
} catch (Exception e) {
if (e instanceof SignalClientException) {
+ String errorReason = messageResolver.resolve(((SignalClientException) e).getErrorMessage());
+ log.warn("/api/v1/signal/report_list failed. UserName: {}, PackageName: {}. Reason: {}", username, packageName, errorReason);
throw (SignalClientException) e;
}
log.error(e.getMessage(), e);
@@ -408,6 +436,7 @@ public class SignalFacade {
if (folder.exists() && folder.isDirectory()) {
File file = new File(dirPath + File.separator + fileName);
if (file.exists() && file.isFile()) {
+ log.info("/api/v1/signal/download processed successfully. FileName: {}", fileName);
return ResponseEntity.ok().body(new FileUrlResource(file.getPath()));
}
} else {
@@ -416,6 +445,8 @@ public class SignalFacade {
throw clientExcp(SignalError.ERROR_014, XmlErrorFormat.MonitoringDownloadError, fileName);
} catch (Exception e) {
if (e instanceof SignalClientException) {
+ String errorReason = messageResolver.resolve(((SignalClientException) e).getErrorMessage());
+ log.warn("/api/v1/signal/download failed. FileName: {}. Reason: {}", fileName, errorReason);
throw (SignalClientException) e;
}
log.error(e.getMessage(), e);
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..00edfbc 100644
--- a/src/main/java/ru/nbch/credit_tracker/service/MonitoringErrorProcesingService.java
+++ b/src/main/java/ru/nbch/credit_tracker/service/MonitoringErrorProcesingService.java
@@ -3,6 +3,7 @@ package ru.nbch.credit_tracker.service;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
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;
@@ -21,6 +22,11 @@ public class MonitoringErrorProcesingService {
public void findErrors(Integer packageId) {
UserPackage userPackage = signalService.findPackage(packageId);
+ processPackage(userPackage, packageId);
+ }
+
+ @SetAndClearMdc
+ private void processPackage(UserPackage userPackage, Integer packageId) {
if (userPackage != null) {
String packCode = userPackage.getUserId().substring(0, 6) + "_" + userPackage.getPackageName();
log.info("Проверка на ошибки при постановке на мониторинг. packCode={}, packageId={}", packCode, packageId);
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..e6598a4 100644
--- a/src/main/java/ru/nbch/credit_tracker/service/MonitoringService.java
+++ b/src/main/java/ru/nbch/credit_tracker/service/MonitoringService.java
@@ -4,6 +4,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.stereotype.Service;
+import ru.nbch.credit_tracker.config.mdc.SetAndClearMdc;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.entities.dto.Hit;
import ru.nbch.credit_tracker.entities.dto.PhoneFidMap;
@@ -69,83 +70,88 @@ 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);
- }
- }
+ processPackage(userPackage);
}
log.info("Finish monitoring");
}
+ @SetAndClearMdc
+ 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 +303,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/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/java/ru/nbch/credit_tracker/service/UpdateProcessingPackagesService.java b/src/main/java/ru/nbch/credit_tracker/service/UpdateProcessingPackagesService.java
index 2888c82..4c03fc3 100644
--- a/src/main/java/ru/nbch/credit_tracker/service/UpdateProcessingPackagesService.java
+++ b/src/main/java/ru/nbch/credit_tracker/service/UpdateProcessingPackagesService.java
@@ -2,6 +2,7 @@ package ru.nbch.credit_tracker.service;
import lombok.extern.slf4j.Slf4j;
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;
@@ -38,6 +39,7 @@ public class UpdateProcessingPackagesService {
log.info("Finish updating processing packages");
}
+ @SetAndClearMdc(argIndex = 1)
private void process(Integer packageId, String packageName) {
try {
SignalService.UpdateResult updateResult = signalService.updateSubjects(packageId, null);
@@ -56,7 +58,7 @@ public class UpdateProcessingPackagesService {
}
} catch (Exception e) {
signalService.updatePackageStatus(packageId, Status.ERROR);
- log.error("Ошибка при поиске фидов или расчете флагов просрочек. Package_id {}", packageId, e);
+ log.error("Ошибка при поиске фидов или расчете флагов просрочек. Package_id {}, PackageName: {}", packageId, packageName, e);
}
}
}
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..d6a7664 100644
--- a/src/main/java/ru/nbch/credit_tracker/service/UpdatingFlagsService.java
+++ b/src/main/java/ru/nbch/credit_tracker/service/UpdatingFlagsService.java
@@ -3,6 +3,7 @@ package ru.nbch.credit_tracker.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.stereotype.Service;
+import ru.nbch.credit_tracker.config.mdc.SetAndClearMdc;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.entities.dto.PhoneFidMap;
import ru.nbch.credit_tracker.entities.dto.UserPackage;
@@ -57,6 +58,7 @@ public class UpdatingFlagsService {
log.info("Finish updating flags");
}
+ @SetAndClearMdc(argIndex = 1)
private void updateFlags(Integer packageId, String packageName) {
try {
signalService.updatePackageStatus(packageId, Status.PROCESSING);
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..240c3a6 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,7 @@
package ru.nbch.credit_tracker.utils;
+import lombok.extern.slf4j.Slf4j;
+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;
@@ -10,47 +12,58 @@ 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}$";
+ @SetAndClearMdc
public static void validateMonitoringRequest(MonitoringRequest request) throws SignalClientException {
if (request == null) {
+ log.warn("Ошибка при валидации пакета. Получен невалидный XML");
throw clientExcp(SignalError.ERROR_011, XmlErrorFormat.MonitoringError);
}
- if (request.getUserId() == null) {
- throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "UserId");
- }
-
if (request.getPackageName() == null) {
+ log.warn("Ошибка при валидации пакета. Отсутствует обязательный элемент: PackageName");
throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "PackageName");
}
+ if (!validatePackageName(request.getPackageName())) {
+ log.error("Ошибка при валидации пакета. PackageName не соответствует допустимому формату");
+ throw clientExcp(SignalError.ERROR_008, XmlErrorFormat.MonitoringError);
+ }
+
+ if (request.getUserId() == null) {
+ log.warn("Ошибка при валидации пакета.Отсутствует обязательный элемент: UserId");
+ throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "UserId");
+ }
+
if (request.getPassword() == null) {
+ log.warn("Ошибка при валидации пакета.Отсутствует обязательный элемент: Password");
throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "Password");
}
if (request.getSubjects() == null) {
+ log.warn("Ошибка при валидации пакета.Отсутствует обязательный элемент: Subjects");
throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "Subjects");
}
if (request.getSubjects().getSubject().isEmpty()) {
+ log.warn("Ошибка при валидации пакета.Отсутствует обязательный элемент: Subject");
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);
+ log.warn("Ошибка при валидации пакета.Идентификатор субъекта (Id) не соответствует допустимому формату: {}.", subject.getId());
+ throw clientExcp(SignalError.ERROR_010, XmlErrorFormat.MonitoringError, subject.getId());
+ }
+ if (!validatePhone(subject.getClientId())) {
+ log.warn("Ошибка при валидации пакета.Элемент ClientId не соответствует формату XXXXXXXXX: {}", subject.getClientId());
+ throw clientExcp(SignalError.ERROR_003, XmlErrorFormat.MonitoringError, subject.getId());
}
}
}
diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml
index 0825d76..e56b9a9 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} [%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} [%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[]{"#####"}
)
);
}