diff --git a/frontend/src/pages/RecollectDetail.tsx b/frontend/src/pages/RecollectDetail.tsx
index ebacec1..3412a1e 100644
--- a/frontend/src/pages/RecollectDetail.tsx
+++ b/frontend/src/pages/RecollectDetail.tsx
@@ -36,6 +36,49 @@ function StatCard({ label, value, gradient, icon }: StatCardProps) {
);
}
+function CopyButton({ text }: { text: string }) {
+ const [copied, setCopied] = useState(false);
+
+ const handleCopy = async (e: React.MouseEvent) => {
+ e.stopPropagation();
+ try {
+ await navigator.clipboard.writeText(text);
+ setCopied(true);
+ setTimeout(() => setCopied(false), 1500);
+ } catch {
+ const textarea = document.createElement('textarea');
+ textarea.value = text;
+ textarea.style.position = 'fixed';
+ textarea.style.opacity = '0';
+ document.body.appendChild(textarea);
+ textarea.select();
+ document.execCommand('copy');
+ document.body.removeChild(textarea);
+ setCopied(true);
+ setTimeout(() => setCopied(false), 1500);
+ }
+ };
+
+ return (
+
+ );
+}
+
function StepCard({ step }: { step: StepExecutionDto }) {
const [logsOpen, setLogsOpen] = useState(false);
@@ -164,8 +207,13 @@ function StepCard({ step }: { step: StepExecutionDto }) {
className={isError ? 'bg-red-50' : 'bg-white hover:bg-blue-50'}
>
{idx + 1} |
-
- {log.requestUri}
+ |
+
+
+ {log.requestUri}
+
+
+
|
{log.httpMethod} |
diff --git a/src/main/java/com/snp/batch/service/BatchService.java b/src/main/java/com/snp/batch/service/BatchService.java
index c380cc5..a82f9e9 100644
--- a/src/main/java/com/snp/batch/service/BatchService.java
+++ b/src/main/java/com/snp/batch/service/BatchService.java
@@ -2,6 +2,8 @@ package com.snp.batch.service;
import com.snp.batch.common.batch.listener.RecollectionJobExecutionListener;
import com.snp.batch.global.dto.*;
+import com.snp.batch.global.model.BatchApiLog;
+import com.snp.batch.global.repository.BatchApiLogRepository;
import com.snp.batch.global.repository.TimelineRepository;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
@@ -35,6 +37,7 @@ public class BatchService {
private final ScheduleService scheduleService;
private final TimelineRepository timelineRepository;
private final RecollectionJobExecutionListener recollectionJobExecutionListener;
+ private final BatchApiLogRepository apiLogRepository;
@Autowired
public BatchService(JobLauncher jobLauncher,
@@ -43,7 +46,8 @@ public class BatchService {
Map jobMap,
@Lazy ScheduleService scheduleService,
TimelineRepository timelineRepository,
- RecollectionJobExecutionListener recollectionJobExecutionListener) {
+ RecollectionJobExecutionListener recollectionJobExecutionListener,
+ BatchApiLogRepository apiLogRepository) {
this.jobLauncher = jobLauncher;
this.jobExplorer = jobExplorer;
this.jobOperator = jobOperator;
@@ -51,6 +55,7 @@ public class BatchService {
this.scheduleService = scheduleService;
this.timelineRepository = timelineRepository;
this.recollectionJobExecutionListener = recollectionJobExecutionListener;
+ this.apiLogRepository = apiLogRepository;
}
/**
@@ -227,6 +232,10 @@ public class BatchService {
// StepExecutionContext에서 API 정보 추출
com.snp.batch.global.dto.JobExecutionDetailDto.ApiCallInfo apiCallInfo = extractApiCallInfo(stepExecution);
+ // batch_api_log 테이블에서 Step별 API 로그 집계 + 개별 로그 조회
+ com.snp.batch.global.dto.JobExecutionDetailDto.StepApiLogSummary apiLogSummary =
+ buildStepApiLogSummary(stepExecution.getId());
+
return com.snp.batch.global.dto.JobExecutionDetailDto.StepExecutionDto.builder()
.stepExecutionId(stepExecution.getId())
.stepName(stepExecution.getStepName())
@@ -244,7 +253,8 @@ public class BatchService {
.exitCode(stepExecution.getExitStatus().getExitCode())
.exitMessage(stepExecution.getExitStatus().getExitDescription())
.duration(duration)
- .apiCallInfo(apiCallInfo) // API 정보 추가
+ .apiCallInfo(apiCallInfo)
+ .apiLogSummary(apiLogSummary)
.build();
}
@@ -290,6 +300,46 @@ public class BatchService {
.build();
}
+ /**
+ * Step별 batch_api_log 집계 + 개별 로그 목록 조회
+ */
+ private com.snp.batch.global.dto.JobExecutionDetailDto.StepApiLogSummary buildStepApiLogSummary(Long stepExecutionId) {
+ List |