update 22

This commit is contained in:
2026-01-07 01:14:51 +09:00
parent 57c3eea429
commit 66e8e21302
220 changed files with 2911 additions and 700 deletions

View File

@@ -7,10 +7,16 @@ import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import research.loghunter.dto.ErrorLogDto;
import research.loghunter.dto.FileTreeDto;
import research.loghunter.entity.ErrorLog;
import research.loghunter.entity.Server;
import research.loghunter.repository.ErrorLogRepository;
import research.loghunter.repository.ScannedFileRepository;
import research.loghunter.repository.ServerRepository;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
@@ -18,11 +24,14 @@ import java.time.LocalDateTime;
public class ErrorLogService {
private final ErrorLogRepository errorLogRepository;
private final ScannedFileRepository scannedFileRepository;
private final ServerRepository serverRepository;
public Page<ErrorLogDto> search(
Long serverId,
Long patternId,
String severity,
String filePath,
LocalDateTime startDate,
LocalDateTime endDate,
String keyword,
@@ -31,7 +40,7 @@ public class ErrorLogService {
) {
Pageable pageable = PageRequest.of(page, size);
Page<ErrorLog> errorLogs = errorLogRepository.searchErrors(
serverId, patternId, severity, startDate, endDate, keyword, pageable);
serverId, patternId, severity, filePath, startDate, endDate, keyword, pageable);
return errorLogs.map(this::toDto);
}
@@ -48,6 +57,125 @@ public class ErrorLogService {
.orElseThrow(() -> new RuntimeException("ErrorLog not found: " + id));
}
/**
* 트리 구조 데이터 조회
*/
public List<FileTreeDto.ServerNode> getFileTree() {
// 파일별 에러 통계 조회
List<Object[]> stats = errorLogRepository.getFileErrorStats();
// 서버별로 그룹핑
Map<Long, List<Object[]>> serverGroups = new LinkedHashMap<>();
for (Object[] stat : stats) {
Long serverId = ((Number) stat[0]).longValue();
serverGroups.computeIfAbsent(serverId, k -> new ArrayList<>()).add(stat);
}
List<FileTreeDto.ServerNode> result = new ArrayList<>();
for (Map.Entry<Long, List<Object[]>> entry : serverGroups.entrySet()) {
Long serverId = entry.getKey();
List<Object[]> serverStats = entry.getValue();
String serverName = (String) serverStats.get(0)[1];
// 경로별로 그룹핑
Map<String, List<FileTreeDto.FileNode>> pathGroups = new LinkedHashMap<>();
int serverTotalErrors = 0;
for (Object[] stat : serverStats) {
String filePath = (String) stat[2];
int errorCount = ((Number) stat[3]).intValue();
int criticalCount = ((Number) stat[4]).intValue();
int errorLevelCount = ((Number) stat[5]).intValue();
int warnCount = ((Number) stat[6]).intValue();
// 경로와 파일명 분리
int lastSlash = filePath.lastIndexOf('/');
String path = lastSlash > 0 ? filePath.substring(0, lastSlash) : "/";
String fileName = lastSlash > 0 ? filePath.substring(lastSlash + 1) : filePath;
FileTreeDto.FileNode fileNode = FileTreeDto.FileNode.builder()
.filePath(filePath)
.fileName(fileName)
.errorCount(errorCount)
.criticalCount(criticalCount)
.errorLevelCount(errorLevelCount)
.warnCount(warnCount)
.build();
pathGroups.computeIfAbsent(path, k -> new ArrayList<>()).add(fileNode);
serverTotalErrors += errorCount;
}
// PathNode 생성
List<FileTreeDto.PathNode> pathNodes = new ArrayList<>();
for (Map.Entry<String, List<FileTreeDto.FileNode>> pathEntry : pathGroups.entrySet()) {
List<FileTreeDto.FileNode> files = pathEntry.getValue();
int pathTotalErrors = files.stream().mapToInt(FileTreeDto.FileNode::getErrorCount).sum();
pathNodes.add(FileTreeDto.PathNode.builder()
.path(pathEntry.getKey())
.totalErrorCount(pathTotalErrors)
.files(files)
.build());
}
result.add(FileTreeDto.ServerNode.builder()
.serverId(serverId)
.serverName(serverName)
.totalErrorCount(serverTotalErrors)
.paths(pathNodes)
.build());
}
return result;
}
/**
* 서버별 파일 목록 조회
*/
public List<String> getFilesByServer(Long serverId) {
if (serverId == null) {
return errorLogRepository.findDistinctFilePaths();
}
return errorLogRepository.findDistinctFilePathsByServerId(serverId);
}
/**
* 선택한 ID들의 에러 삭제
*/
@Transactional
public int deleteByIds(List<Long> ids) {
if (ids == null || ids.isEmpty()) {
return 0;
}
return errorLogRepository.deleteByIdIn(ids);
}
/**
* 파일 삭제 (에러로그 + 스캔기록)
*/
@Transactional
public Map<String, Object> deleteFileAndErrors(Long serverId, String filePath) {
int deletedErrors = errorLogRepository.deleteByServerIdAndFilePath(serverId, filePath);
int deletedFiles = scannedFileRepository.deleteByServerIdAndFilePath(serverId, filePath);
return Map.of(
"success", true,
"deletedErrors", deletedErrors,
"deletedScannedFiles", deletedFiles
);
}
/**
* 서버+파일 기준 에러 삭제
*/
@Transactional
public int deleteByServerAndFile(Long serverId, String filePath) {
return errorLogRepository.deleteByServerIdAndFilePath(serverId, filePath);
}
private ErrorLogDto toDto(ErrorLog errorLog) {
return ErrorLogDto.builder()
.id(errorLog.getId())