diff --git a/credit-tracker.properties b/credit-tracker.properties index c9fdfd6..e8241c1 100644 --- a/credit-tracker.properties +++ b/credit-tracker.properties @@ -8,21 +8,45 @@ server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b # datasources # indic 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.100:2668/cprosd22:currentSchema=INDIC;} -ct.indic-data-source-settings.username=${USERNAME_INDIC:ros9appl} -ct.indic-data-source-settings.password=${PASSWORD_INDIC:R0s9Appl} +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=${LEAK_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=${LEAK_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=${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 b395b4f..7678f1a 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.17 REGISTRY_URL=rh8-vm3.nbki.msk:5000 JMX_PORT= JMX_HOSTNAME= @@ -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 +LEAK_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 +LEAK_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 +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 1b06547..7c6a16a 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} + - LEAK_DETECTION_THRESHOLD_INDIC=${LEAK_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} + - LEAK_DETECTION_THRESHOLD_SIGNAL=${LEAK_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} + - 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} 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); 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 5a57985..99028ac 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,17 +1,20 @@ package ru.nbch.credit_tracker.config.datasource; -import javax.sql.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 503a97b..61dc0bb 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 @@ -10,8 +10,8 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; -import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; +import ru.nbch.credit_tracker.config.settings.DataSourceSettings; import javax.sql.DataSource; import java.sql.Connection; @@ -30,15 +30,25 @@ public class IndicDataSourceConfig extends DatabaseConfig { @Bean(name = "indicDataSource") public DataSource dataSource(CreditTrackerSettings config) throws SQLException { - HikariDataSource dataSource = (HikariDataSource) createDataSource(config.getIndicDataSourceSettings()); - dataSource.setMaximumPoolSize(50); + 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 788d3e9..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,9 +1,6 @@ package ru.nbch.credit_tracker.config.datasource; import com.zaxxer.hikari.HikariDataSource; -import java.sql.Connection; -import java.sql.SQLException; -import javax.sql.DataSource; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; @@ -14,6 +11,11 @@ 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; +import java.sql.SQLException; @Slf4j @Configuration @@ -28,15 +30,25 @@ public class ScoringDataSourceConfig extends DatabaseConfig { @Bean(name = "scoringDataSource") public DataSource dataSource(CreditTrackerSettings config) throws SQLException { - HikariDataSource dataSource = (HikariDataSource) createDataSource(config.getScoringDataSourceSettings()); - dataSource.setMaximumPoolSize(10); + 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 4436560..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,13 +1,8 @@ package ru.nbch.credit_tracker.config.datasource; import com.zaxxer.hikari.HikariDataSource; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.UUID; -import javax.sql.DataSource; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.session.SqlSessionFactory; -import org.apache.ibatis.type.TypeHandlerRegistry; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Qualifier; @@ -15,8 +10,12 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; -import ru.nbch.credit_tracker.config.datasource.handlers.UUIDTypeHandler; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; +import ru.nbch.credit_tracker.config.settings.DataSourceSettings; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.SQLException; @Slf4j @Configuration @@ -30,15 +29,25 @@ public class SignalDataSourceConfig extends DatabaseConfig { @Bean(name = "signalDataSource") public DataSource dataSource(CreditTrackerSettings config) throws SQLException { - HikariDataSource dataSource = (HikariDataSource) createDataSource(config.getSignalDataSourceSettings()); - dataSource.setMaximumPoolSize(100); + 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; } @@ -47,11 +56,6 @@ public class SignalDataSourceConfig extends DatabaseConfig { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(dataSource); sqlSessionFactoryBean.setMapperLocations(resources); - - SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBean.getObject(); - TypeHandlerRegistry typeHandlerRegistry = sqlSessionFactory.getConfiguration().getTypeHandlerRegistry(); - typeHandlerRegistry.register(UUID.class, UUIDTypeHandler.class); - return sqlSessionFactoryBean.getObject(); } } 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..798f398 --- /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(setAndClearMdc.key(), request.getPackageName()); + } + } else if (obj instanceof UserPackage userPackage) { + if (userPackage.getPackageName() != null) { + putMdcValue(setAndClearMdc.key(), userPackage.getPackageName()); + } + } 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 key, String value) { + 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/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/config/rest/filters/HttpLoggingFilter.java b/src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java index bd8bd3c..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 @@ -3,17 +3,9 @@ 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 java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; -import java.util.stream.Collectors; +import jakarta.servlet.http.Part; import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -22,6 +14,10 @@ import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.util.ContentCachingRequestWrapper; import org.springframework.web.util.ContentCachingResponseWrapper; +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; + @Component @Slf4j @Order(0) @@ -34,12 +30,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(); @@ -47,17 +43,18 @@ 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); + 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 reqParams = paramsMap(req); Map reqHeaders = headersMap(req); Map respHeaders = headersMap(resp); @@ -66,43 +63,67 @@ public class HttpLoggingFilter extends OncePerRequestFilter { 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 + "HTTP (RESPONSE) {} {} | status={} | took={}ms | cid={} | reqHeaders={} | reqParams={} | respHeaders={}", + req.getMethod(), + req.getRequestURI(), + resp.getStatus(), + tookMs, + correlationId, + reqHeaders, + reqParams, + respHeaders ); resp.copyBodyToResponse(); } } - private static ContentCachingRequestWrapper wrapRequest(HttpServletRequest request) { + private void logIncomingRequest(ContentCachingRequestWrapper req, String correlationId) { + Map reqParams = paramsMap(req); + Map reqHeaders = headersMap(req); + mask(reqHeaders); + + log.info( + "HTTP (REQUEST) {} {} | cid={} | reqHeaders={} | reqParams={}", + req.getMethod(), + req.getRequestURI(), + correlationId, + reqHeaders, + reqParams + ); + } + + private static ContentCachingRequestWrapper wrapRequest(HttpServletRequest request) throws IOException { 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 static Map paramsMap(HttpServletRequestWrapper 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) { 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 new file mode 100644 index 0000000..84d2231 --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/config/rest/wrappers/CachedHttpRequestWrapper.java @@ -0,0 +1,25 @@ +package ru.nbch.credit_tracker.config.rest.wrappers; + +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequestWrapper; +import lombok.Getter; + +import java.io.IOException; + +@Getter +public class CachedHttpRequestWrapper extends HttpServletRequestWrapper { + private final byte[] body; + + + public CachedHttpRequestWrapper(HttpServletRequest request) throws IOException { + super(request); + this.body = request.getInputStream().readAllBytes(); + } + + @Override + public ServletInputStream getInputStream() { + 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) { + } +} 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 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); 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 ea6121d..e904779 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; @@ -144,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); @@ -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/SignalService.java b/src/main/java/ru/nbch/credit_tracker/service/SignalService.java index 79abbef..59e8912 100644 --- a/src/main/java/ru/nbch/credit_tracker/service/SignalService.java +++ b/src/main/java/ru/nbch/credit_tracker/service/SignalService.java @@ -334,7 +334,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..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/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); 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 65% 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..9e7875d 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); } @@ -27,32 +31,34 @@ public class ValidationUtil { 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) { diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 8fb6f4e..40d7a8c 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/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; }