LogSearchService.java 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. package com.demo.seecanalysisbackend.service;
  2. import com.demo.seecanalysisbackend.dto.LogSearchRequest;
  3. import com.demo.seecanalysisbackend.dto.LogSearchResponse;
  4. import com.demo.seecanalysisbackend.model.LogEntry;
  5. import com.demo.seecanalysisbackend.repository.LogEntryRepository;
  6. import lombok.RequiredArgsConstructor;
  7. import lombok.extern.slf4j.Slf4j;
  8. import org.springframework.data.domain.Page;
  9. import org.springframework.data.domain.PageRequest;
  10. import org.springframework.data.domain.Pageable;
  11. import org.springframework.data.domain.Sort;
  12. import org.springframework.stereotype.Service;
  13. import java.time.LocalDateTime;
  14. import java.time.format.DateTimeFormatter;
  15. import java.util.HashMap;
  16. import java.util.HashSet;
  17. import java.util.List;
  18. import java.util.Map;
  19. import java.util.Set;
  20. import java.util.stream.Collectors;
  21. @Service
  22. @RequiredArgsConstructor
  23. @Slf4j
  24. public class LogSearchService {
  25. private final LogEntryRepository logEntryRepository;
  26. private static final Map<String, String> SORT_FIELD_MAPPING = createSortFieldMapping();
  27. private static final Set<String> ALLOWED_SORT_PROPERTIES = Set.of(
  28. "timestamp", "level", "serviceName", "traceId", "spanId", "bizName",
  29. "className", "methodName", "thread", "application", "rawMessage"
  30. );
  31. public LogSearchResponse searchLogs(LogSearchRequest request) {
  32. log.info("Searching logs with criteria: {}", request);
  33. Pageable pageable = createPageable(request);
  34. Page<LogEntry> logPage = performSearch(request, pageable);
  35. List<LogSearchResponse.LogEntryDto> logDtos = logPage.getContent().stream()
  36. .map(this::convertToDto)
  37. .collect(Collectors.toList());
  38. return LogSearchResponse.builder()
  39. .logs(logDtos)
  40. .totalCount(logPage.getTotalElements())
  41. .currentPage(logPage.getNumber())
  42. .pageSize(logPage.getSize())
  43. .totalPages(logPage.getTotalPages())
  44. .hasNext(logPage.hasNext())
  45. .hasPrevious(logPage.hasPrevious())
  46. .build();
  47. }
  48. private Page<LogEntry> performSearch(LogSearchRequest request, Pageable pageable) {
  49. if (request.getSearchText() != null && !request.getSearchText().trim().isEmpty()) {
  50. return logEntryRepository.findByTimestampBetweenAndMessage(
  51. request.getStartTime(), request.getEndTime(),
  52. request.getSearchText(), pageable);
  53. }
  54. if (request.getBizNames() != null && !request.getBizNames().isEmpty()) {
  55. return logEntryRepository.findByTimestampBetweenAndBizNameIn(
  56. request.getStartTime(), request.getEndTime(),
  57. request.getBizNames(), pageable);
  58. }
  59. if (request.getServices() != null && !request.getServices().isEmpty()) {
  60. String serviceName = request.getServices().getFirst();
  61. return logEntryRepository.findByTimestampBetweenAndServiceName(
  62. request.getStartTime(), request.getEndTime(),
  63. serviceName, pageable);
  64. }
  65. if (request.getTraceId() != null && !request.getTraceId().trim().isEmpty()) {
  66. return logEntryRepository.findByTimestampBetweenAndTraceId(
  67. request.getStartTime(), request.getEndTime(),
  68. request.getTraceId(), pageable);
  69. }
  70. if (request.getLevels() != null && !request.getLevels().isEmpty()) {
  71. return logEntryRepository.findByTimestampBetweenAndLevelIn(
  72. request.getStartTime(), request.getEndTime(),
  73. request.getLevels(), pageable);
  74. }
  75. if (request.getApplications() != null && !request.getApplications().isEmpty()) {
  76. return logEntryRepository.findByTimestampBetweenAndApplicationIn(
  77. request.getStartTime(), request.getEndTime(),
  78. request.getApplications(), pageable);
  79. }
  80. return logEntryRepository.findByTimestampBetween(
  81. request.getStartTime(), request.getEndTime(), pageable);
  82. }
  83. private Pageable createPageable(LogSearchRequest request) {
  84. Sort.Direction direction = "asc".equalsIgnoreCase(request.getSortDirection()) ?
  85. Sort.Direction.ASC : Sort.Direction.DESC;
  86. String requestedSortBy = request.getSortBy() == null ? "timestamp" : request.getSortBy();
  87. String normalizedSortProperty = SORT_FIELD_MAPPING.getOrDefault(requestedSortBy, requestedSortBy);
  88. String actualSortField = ALLOWED_SORT_PROPERTIES.contains(normalizedSortProperty)
  89. ? normalizedSortProperty
  90. : "timestamp";
  91. return PageRequest.of(request.getPage(), request.getSize(),
  92. Sort.by(direction, actualSortField));
  93. }
  94. private static Map<String, String> createSortFieldMapping() {
  95. Map<String, String> mapping = new HashMap<>();
  96. // Accept external ES field names and normalize them to entity property names.
  97. mapping.put("@timestamp", "timestamp");
  98. mapping.put("log_level", "level");
  99. mapping.put("service_name", "serviceName");
  100. mapping.put("trace_id", "traceId");
  101. mapping.put("span_id", "spanId");
  102. mapping.put("biz_name", "bizName");
  103. mapping.put("bizName", "bizName");
  104. mapping.put("timestamp", "timestamp");
  105. mapping.put("level", "level");
  106. mapping.put("serviceName", "serviceName");
  107. mapping.put("traceId", "traceId");
  108. mapping.put("spanId", "spanId");
  109. return mapping;
  110. }
  111. private LogSearchResponse.LogEntryDto convertToDto(LogEntry logEntry) {
  112. return LogSearchResponse.LogEntryDto.builder()
  113. .id(logEntry.getId())
  114. .timestamp(logEntry.getTimestamp() != null ?
  115. logEntry.getTimestamp().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) : null)
  116. .rawMessage(logEntry.getRawMessage())
  117. .serviceName(logEntry.getServiceName())
  118. .thread(logEntry.getThread())
  119. .level(logEntry.getLevel())
  120. .className(logEntry.getClassName())
  121. .methodName(logEntry.getMethodName())
  122. .traceId(logEntry.getTraceId())
  123. .spanId(logEntry.getSpanId())
  124. .bizName(logEntry.getBizName())
  125. .context(logEntry.getContext())
  126. .build();
  127. }
  128. }