From 13bd7859c7b237d59b1a12526aee2f15dda0819a Mon Sep 17 00:00:00 2001 From: root Date: Sun, 14 Dec 2025 21:34:42 +0500 Subject: [PATCH] . --- .../konturai/parser/config/MongoConfig.java | 81 ++++++++++++++++--- .../service/MarketingAnalysisService.java | 32 ++++++-- 2 files changed, 98 insertions(+), 15 deletions(-) diff --git a/src/main/java/kz/konturai/parser/config/MongoConfig.java b/src/main/java/kz/konturai/parser/config/MongoConfig.java index 0f58c5d..2e5ace0 100644 --- a/src/main/java/kz/konturai/parser/config/MongoConfig.java +++ b/src/main/java/kz/konturai/parser/config/MongoConfig.java @@ -40,7 +40,10 @@ public class MongoConfig { public static class StringToMapConverter implements Converter> { @Override public Map convert(String source) { - logger.debug("StringToMapConverter: Converting string to Map: {}", source); + long startTime = System.currentTimeMillis(); + int sourceLength = source != null ? source.length() : 0; + logger.info("StringToMapConverter: Starting conversion. Source length: {} chars", sourceLength); + if (source == null || source.trim().isEmpty()) { logger.debug("StringToMapConverter: Source is null or empty, returning empty Map"); return new HashMap<>(); @@ -49,17 +52,44 @@ public class MongoConfig { try { // Если это уже JSON строка, парсим её if (source.trim().startsWith("{") || source.trim().startsWith("[")) { + logger.debug("StringToMapConverter: Parsing JSON string (starts with {} or [)", + source.trim().charAt(0)); + long parseStartTime = System.currentTimeMillis(); + Map result = objectMapper.readValue(source, new TypeReference>() { }); - logger.debug("StringToMapConverter: Successfully parsed JSON string to Map"); + + long parseDuration = System.currentTimeMillis() - parseStartTime; + int resultSize = result != null ? result.size() : 0; + + logger.info("StringToMapConverter: Successfully parsed JSON string to Map. " + + "Source length: {} chars, Result size: {} keys, Parse duration: {} ms", + sourceLength, resultSize, parseDuration); + + if (parseDuration > 1000) { + logger.warn("StringToMapConverter: Parse took {} ms, which is longer than expected", + parseDuration); + } + + if (sourceLength > 100000) { + logger.warn( + "StringToMapConverter: Parsed very large JSON ({} chars). This may cause performance issues.", + sourceLength); + } + + long totalDuration = System.currentTimeMillis() - startTime; + logger.debug("StringToMapConverter: Conversion completed. Total duration: {} ms", totalDuration); + return result; } // Если это простая строка, создаём пустой Map logger.warn("StringToMapConverter: target_audience is a plain string, not JSON: {}", source); return new HashMap<>(); } catch (Exception e) { - logger.error("StringToMapConverter: Error converting string to Map for target_audience: {}", source, e); + logger.error("StringToMapConverter: Error converting string to Map. Source length: {} chars", + sourceLength, e); + logger.error("StringToMapConverter: Stack trace: ", e); return new HashMap<>(); } } @@ -71,32 +101,65 @@ public class MongoConfig { */ @ReadingConverter public static class DocumentToMapConverter implements Converter> { + private static final int MAX_RECURSION_DEPTH = 50; + @Override public Map convert(Document source) { - logger.debug("DocumentToMapConverter: Converting Document to Map"); + return convert(source, 0); + } + + private Map convert(Document source, int depth) { + logger.debug("DocumentToMapConverter: Converting Document to Map (depth: {})", depth); + if (source == null) { logger.debug("DocumentToMapConverter: Source is null, returning empty Map"); return new HashMap<>(); } + if (depth > MAX_RECURSION_DEPTH) { + logger.error( + "DocumentToMapConverter: Maximum recursion depth ({}) exceeded. Possible circular reference!", + MAX_RECURSION_DEPTH); + return new HashMap<>(); + } + long startTime = System.currentTimeMillis(); + int keyCount = source.keySet().size(); + logger.debug("DocumentToMapConverter: Processing Document with {} keys at depth {}", keyCount, depth); + Map result = new HashMap<>(); + int nestedCount = 0; + for (String key : source.keySet()) { Object value = source.get(key); // Рекурсивно конвертируем вложенные Document if (value instanceof Document) { - logger.debug("DocumentToMapConverter: Found nested Document for key: {}", key); - result.put(key, convert((Document) value)); + nestedCount++; + logger.debug("DocumentToMapConverter: Found nested Document for key: {} at depth {}", key, depth); + result.put(key, convert((Document) value, depth + 1)); + } else if (value instanceof org.bson.types.BSONTimestamp || + value instanceof org.bson.types.ObjectId || + value instanceof java.util.Date) { + // Сохраняем специальные типы BSON как строки + result.put(key, value.toString()); } else { result.put(key, value); } } + long duration = System.currentTimeMillis() - startTime; - logger.debug("DocumentToMapConverter: Successfully converted Document to Map with {} keys. Duration: {} ms", - result.size(), duration); + logger.info("DocumentToMapConverter: Successfully converted Document to Map. " + + "Keys: {}, Nested documents: {}, Depth: {}, Duration: {} ms", + result.size(), nestedCount, depth, duration); if (duration > 1000) { - logger.warn("DocumentToMapConverter: Conversion took {} ms, which is longer than expected", duration); + logger.warn("DocumentToMapConverter: Conversion took {} ms at depth {}, which is longer than expected", + duration, depth); + } + + if (keyCount > 100) { + logger.warn("DocumentToMapConverter: Converted Document with {} keys, which is unusually large", + keyCount); } return result; diff --git a/src/main/java/kz/konturai/parser/service/MarketingAnalysisService.java b/src/main/java/kz/konturai/parser/service/MarketingAnalysisService.java index ad7e0d7..3c1cffe 100644 --- a/src/main/java/kz/konturai/parser/service/MarketingAnalysisService.java +++ b/src/main/java/kz/konturai/parser/service/MarketingAnalysisService.java @@ -154,13 +154,33 @@ public class MarketingAnalysisService { "processAnalysis: About to save analysis to MongoDB for ID: {}. This may take time for large reportData...", analysisId); long saveStartTime = System.currentTimeMillis(); - repository.save(analysis); - long saveDuration = System.currentTimeMillis() - saveStartTime; - logger.info("processAnalysis: Analysis saved successfully to MongoDB for ID: {}. Save duration: {} ms", - analysisId, saveDuration); - if (saveDuration > 10000) { - logger.warn("processAnalysis: Save operation took {} ms, which is longer than expected", saveDuration); + try { + logger.debug("processAnalysis: Calling repository.save() for ID: {}", analysisId); + MarketingAnalysis savedAnalysis = repository.save(analysis); + long saveDuration = System.currentTimeMillis() - saveStartTime; + logger.info("processAnalysis: repository.save() completed for ID: {}. Save duration: {} ms", + analysisId, saveDuration); + + if (saveDuration > 10000) { + logger.warn("processAnalysis: Save operation took {} ms, which is longer than expected", + saveDuration); + } + + // Логируем, что произошло после save + logger.debug( + "processAnalysis: After save, checking if Spring Data MongoDB is reading back the document..."); + if (savedAnalysis != null && savedAnalysis.getReportData() != null) { + logger.debug("processAnalysis: Saved analysis has reportData with {} keys", + savedAnalysis.getReportData().keySet().size()); + } + + } catch (Exception saveException) { + long saveDuration = System.currentTimeMillis() - saveStartTime; + logger.error( + "processAnalysis: Exception during repository.save() for ID: {}. Duration before exception: {} ms", + analysisId, saveDuration, saveException); + throw saveException; } logger.info("processAnalysis: Marketing analysis completed successfully for ID: {}", analysisId);