fix(ccdi-project): remove local upload log files
This commit is contained in:
@@ -1,110 +0,0 @@
|
|||||||
package com.ruoyi.ccdi.project.log;
|
|
||||||
|
|
||||||
import ch.qos.logback.classic.LoggerContext;
|
|
||||||
import ch.qos.logback.classic.PatternLayout;
|
|
||||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
|
||||||
import ch.qos.logback.core.FileAppender;
|
|
||||||
import ch.qos.logback.core.UnsynchronizedAppenderBase;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.slf4j.ILoggerFactory;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* File upload batch log appender.
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
public class FileUploadLogAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {
|
|
||||||
|
|
||||||
private static final ThreadLocal<FileAppender<ILoggingEvent>> currentAppender = new ThreadLocal<>();
|
|
||||||
|
|
||||||
private PatternLayout layout;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void start() {
|
|
||||||
LoggerContext loggerContext = resolveLoggerContext();
|
|
||||||
setContext(loggerContext);
|
|
||||||
|
|
||||||
this.layout = new PatternLayout();
|
|
||||||
this.layout.setPattern("%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n");
|
|
||||||
this.layout.setContext(loggerContext);
|
|
||||||
this.layout.start();
|
|
||||||
|
|
||||||
super.start();
|
|
||||||
log.info("【文件上传日志】FileUploadLogAppender已启动");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void append(ILoggingEvent event) {
|
|
||||||
FileAppender<ILoggingEvent> appender = currentAppender.get();
|
|
||||||
if (appender != null) {
|
|
||||||
appender.doAppend(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a dedicated batch log file.
|
|
||||||
*
|
|
||||||
* @param uploadPath upload root path from ruoyi.profile
|
|
||||||
* @param projectId project id
|
|
||||||
* @param batchId batch id
|
|
||||||
*/
|
|
||||||
public static void createBatchLogFile(String uploadPath, Long projectId, String batchId) {
|
|
||||||
try {
|
|
||||||
LoggerContext loggerContext = resolveLoggerContext();
|
|
||||||
|
|
||||||
String timestamp = new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date());
|
|
||||||
String logDirPath = uploadPath + File.separator + "logs" + File.separator
|
|
||||||
+ "file-upload" + File.separator + projectId;
|
|
||||||
|
|
||||||
File logDir = new File(logDirPath);
|
|
||||||
if (!logDir.exists() && !logDir.mkdirs()) {
|
|
||||||
throw new IllegalStateException("无法创建批次日志目录: " + logDirPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
String logFilePath = logDirPath + File.separator + timestamp + ".log";
|
|
||||||
|
|
||||||
FileAppender<ILoggingEvent> appender = new FileAppender<>();
|
|
||||||
appender.setContext(loggerContext);
|
|
||||||
appender.setFile(logFilePath);
|
|
||||||
|
|
||||||
PatternLayout layout = new PatternLayout();
|
|
||||||
layout.setPattern("%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n");
|
|
||||||
layout.setContext(loggerContext);
|
|
||||||
layout.start();
|
|
||||||
|
|
||||||
appender.setLayout(layout);
|
|
||||||
appender.setAppend(true);
|
|
||||||
appender.start();
|
|
||||||
|
|
||||||
currentAppender.set(appender);
|
|
||||||
|
|
||||||
log.info("【文件上传日志】创建批次日志文件成功: path={}, batchId={}", logFilePath, batchId);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("【文件上传日志】创建批次日志文件失败: projectId={}, batchId={}", projectId, batchId, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the current batch log file.
|
|
||||||
*/
|
|
||||||
public static void closeBatchLogFile() {
|
|
||||||
FileAppender<ILoggingEvent> appender = currentAppender.get();
|
|
||||||
if (appender != null) {
|
|
||||||
appender.stop();
|
|
||||||
currentAppender.remove();
|
|
||||||
log.info("【文件上传日志】关闭批次日志文件");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static LoggerContext resolveLoggerContext() {
|
|
||||||
ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory();
|
|
||||||
if (loggerFactory instanceof LoggerContext loggerContext) {
|
|
||||||
return loggerContext;
|
|
||||||
}
|
|
||||||
throw new IllegalStateException("SLF4J logger factory is not a Logback LoggerContext");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,6 @@ import com.ruoyi.ccdi.project.domain.dto.CcdiFileUploadQueryDTO;
|
|||||||
import com.ruoyi.ccdi.project.domain.entity.CcdiBankStatement;
|
import com.ruoyi.ccdi.project.domain.entity.CcdiBankStatement;
|
||||||
import com.ruoyi.ccdi.project.domain.entity.CcdiFileUploadRecord;
|
import com.ruoyi.ccdi.project.domain.entity.CcdiFileUploadRecord;
|
||||||
import com.ruoyi.ccdi.project.domain.vo.CcdiFileUploadStatisticsVO;
|
import com.ruoyi.ccdi.project.domain.vo.CcdiFileUploadStatisticsVO;
|
||||||
import com.ruoyi.ccdi.project.log.FileUploadLogAppender;
|
|
||||||
import com.ruoyi.ccdi.project.mapper.CcdiBankStatementMapper;
|
import com.ruoyi.ccdi.project.mapper.CcdiBankStatementMapper;
|
||||||
import com.ruoyi.ccdi.project.mapper.CcdiFileUploadRecordMapper;
|
import com.ruoyi.ccdi.project.mapper.CcdiFileUploadRecordMapper;
|
||||||
import com.ruoyi.ccdi.project.mapper.CcdiProjectMapper;
|
import com.ruoyi.ccdi.project.mapper.CcdiProjectMapper;
|
||||||
@@ -269,10 +268,6 @@ public class CcdiFileUploadServiceImpl implements ICcdiFileUploadService {
|
|||||||
String batchId) {
|
String batchId) {
|
||||||
log.info("【文件上传】调度线程启动: projectId={}, batchId={}", projectId, batchId);
|
log.info("【文件上传】调度线程启动: projectId={}, batchId={}", projectId, batchId);
|
||||||
|
|
||||||
// 创建批次日志文件
|
|
||||||
FileUploadLogAppender.createBatchLogFile(uploadPath, projectId, batchId);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 循环提交任务
|
// 循环提交任务
|
||||||
for (int i = 0; i < tempFilePaths.size(); i++) {
|
for (int i = 0; i < tempFilePaths.size(); i++) {
|
||||||
// Critical Fix #6: 检查线程中断状态
|
// Critical Fix #6: 检查线程中断状态
|
||||||
@@ -319,10 +314,6 @@ public class CcdiFileUploadServiceImpl implements ICcdiFileUploadService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.info("【文件上传】调度线程完成: projectId={}, batchId={}", projectId, batchId);
|
log.info("【文件上传】调度线程完成: projectId={}, batchId={}", projectId, batchId);
|
||||||
} finally {
|
|
||||||
// 关闭批次日志文件
|
|
||||||
FileUploadLogAppender.closeBatchLogFile();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
package com.ruoyi.ccdi.project.log;
|
|
||||||
|
|
||||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
|
||||||
import ch.qos.logback.core.FileAppender;
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.io.TempDir;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
class FileUploadLogAppenderTest {
|
|
||||||
|
|
||||||
@TempDir
|
|
||||||
Path tempDir;
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
void tearDown() {
|
|
||||||
FileUploadLogAppender.closeBatchLogFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void createBatchLogFile_shouldInitializeAppenderWithLoggerContext() throws Exception {
|
|
||||||
FileUploadLogAppender.createBatchLogFile(tempDir.toString(), 32L, "batch-1");
|
|
||||||
|
|
||||||
FileAppender<ILoggingEvent> appender = currentAppender();
|
|
||||||
|
|
||||||
assertNotNull(appender);
|
|
||||||
assertNotNull(appender.getContext());
|
|
||||||
assertTrue(appender.isStarted());
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private FileAppender<ILoggingEvent> currentAppender() throws Exception {
|
|
||||||
Field field = FileUploadLogAppender.class.getDeclaredField("currentAppender");
|
|
||||||
field.setAccessible(true);
|
|
||||||
ThreadLocal<FileAppender<ILoggingEvent>> threadLocal =
|
|
||||||
(ThreadLocal<FileAppender<ILoggingEvent>>) field.get(null);
|
|
||||||
return threadLocal.get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -18,10 +18,13 @@ import org.mockito.Mock;
|
|||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
@@ -56,9 +59,25 @@ class CcdiFileUploadServiceImplTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private CcdiBankStatementMapper bankStatementMapper;
|
private CcdiBankStatementMapper bankStatementMapper;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Executor fileUploadExecutor;
|
||||||
|
|
||||||
@TempDir
|
@TempDir
|
||||||
Path tempDir;
|
Path tempDir;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void submitTasksAsync_shouldNotCreateLocalBatchLogFiles() throws Exception {
|
||||||
|
setField("uploadPath", tempDir.toString());
|
||||||
|
|
||||||
|
Path tempFile = createTempFile();
|
||||||
|
CcdiFileUploadRecord record = buildRecord();
|
||||||
|
|
||||||
|
invokeSubmitTasksAsync(List.of(tempFile.toString()), List.of(record), "batch-1");
|
||||||
|
|
||||||
|
Path batchLogDir = tempDir.resolve("logs").resolve("file-upload").resolve(String.valueOf(PROJECT_ID));
|
||||||
|
assertFalse(Files.exists(batchLogDir));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void processFileAsync_shouldKeepParsingUntilBankStatementsSaved() throws IOException {
|
void processFileAsync_shouldKeepParsingUntilBankStatementsSaved() throws IOException {
|
||||||
List<String> events = new ArrayList<>();
|
List<String> events = new ArrayList<>();
|
||||||
@@ -279,6 +298,21 @@ class CcdiFileUploadServiceImplTest {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void invokeSubmitTasksAsync(List<String> tempFilePaths,
|
||||||
|
List<CcdiFileUploadRecord> records,
|
||||||
|
String batchId) throws Exception {
|
||||||
|
Method method = CcdiFileUploadServiceImpl.class.getDeclaredMethod("submitTasksAsync",
|
||||||
|
Long.class, Integer.class, List.class, List.class, String.class);
|
||||||
|
method.setAccessible(true);
|
||||||
|
method.invoke(service, PROJECT_ID, LSFX_PROJECT_ID, tempFilePaths, records, batchId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setField(String fieldName, Object value) throws Exception {
|
||||||
|
Field field = CcdiFileUploadServiceImpl.class.getDeclaredField(fieldName);
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(service, value);
|
||||||
|
}
|
||||||
|
|
||||||
private int findEventIndex(List<String> events, String suffix) {
|
private int findEventIndex(List<String> events, String suffix) {
|
||||||
for (int i = 0; i < events.size(); i++) {
|
for (int i = 0; i < events.size(); i++) {
|
||||||
if (events.get(i).endsWith(suffix)) {
|
if (events.get(i).endsWith(suffix)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user