# Prompt - 详细日志记录和查询 ## 输入引用 引用相关的 docs 文档链接: - [REQ-010-15.md](../requirements/REQ-010-15.md) - 详细日志记录和查询需求文档 - [0024-logging.md](../decisions/adr/0024-logging.md) - 详细日志记录和查询架构决策 - [REQ-010.md](../requirements/REQ-010.md) - Salesforce元数据拉取和部署主需求文档 - [REQ-010-6.md](../requirements/REQ-010-6.md) - 元数据拉取核心功能需求文档 - [REQ-010-8.md](../requirements/REQ-010-8.md) - 元数据部署核心功能需求文档 - [REQ-010-14.md](../requirements/REQ-010-14.md) - 作业执行监控需求文档 - [metadata-module.md](../reference-code/com/docs/metadata-module.md) - Salesforce Metadata API 模块说明(唯一真源) - [index.md](../reference-code/com/docs/index.md) - Salesforce SOAP API Java 客户端参考文档(唯一真源) ## Context Maps 强制列出本次 Prompt 依赖的 Canvas 文件: - [Authentication.canvas](../Authentication.canvas) - 项目架构视觉化展示 - **相关节点**: [集成核心](node_integration_core) - 提供与Salesforce的各种连接方式 - **快照时间**: 2026-01-19 00:00:00 ## 目标 实现详细日志记录和查询功能,包括日志记录、日志查询、日志导出、日志分析。支持记录拉取和部署作业的详细执行日志,支持日志查询和导出,支持日志分析。 ## 输出格式 代码示例(语言:Java) ### 1. 日志级别枚举 ```java package com.datai.salesforce.metadata.log.enums; import lombok.Getter; @Getter public enum LogLevel { INFO("信息"), WARN("警告"), ERROR("错误"); private final String description; LogLevel(String description) { this.description = description; } } ``` ### 2. 操作日志实体类 ```java package com.datai.salesforce.metadata.log.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.datai.salesforce.metadata.log.enums.LogLevel; import lombok.Data; import java.time.LocalDateTime; @Data @TableName("datai_operation_log") public class OperationLog { @TableId(type = IdType.AUTO) private Long id; private Long jobExecutionId; private LogLevel logLevel; private String logContent; private String logModule; private String logOperation; private String logUser; private String logIp; private LocalDateTime logTime; private LocalDateTime createTime; } ``` ### 3. 操作日志服务接口 ```java package com.datai.salesforce.metadata.log.service; import com.datai.salesforce.metadata.log.entity.OperationLog; import com.datai.salesforce.metadata.log.enums.LogLevel; import java.util.List; public interface IOperationLogService { Long saveLog(OperationLog operationLog); void saveLogAsync(OperationLog operationLog); OperationLog getLog(Long id); List getLogsByJobExecutionId(Long jobExecutionId); List getLogsByLogLevel(LogLevel logLevel); boolean deleteLog(Long id); boolean batchDeleteLogs(List ids); } ``` ### 4. 日志查询服务接口 ```java package com.datai.salesforce.metadata.log.service; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.datai.salesforce.metadata.log.entity.OperationLog; import com.datai.salesforce.metadata.log.enums.LogLevel; import java.time.LocalDateTime; import java.util.List; public interface ILogQueryService { IPage queryLogs(Page page, Long jobExecutionId, LogLevel logLevel, String keyword, LocalDateTime startTime, LocalDateTime endTime); List queryLogsByCondition(Long jobExecutionId, LogLevel logLevel, String keyword, LocalDateTime startTime, LocalDateTime endTime); IPage queryLogsByTimeRange(Page page, LocalDateTime startTime, LocalDateTime endTime); IPage queryLogsByJobExecutionId(Page page, Long jobExecutionId); } ``` ### 5. 日志导出服务接口 ```java package com.datai.salesforce.metadata.log.service; import com.datai.salesforce.metadata.log.entity.OperationLog; import org.springframework.http.ResponseEntity; import java.time.LocalDateTime; import java.util.List; public interface ILogExportService { ResponseEntity exportToText(List logIds); ResponseEntity exportToExcel(List logIds); ResponseEntity exportToCsv(List logIds); ResponseEntity exportToTextByCondition(Long jobExecutionId, String logLevel, String keyword, LocalDateTime startTime, LocalDateTime endTime); ResponseEntity exportToExcelByCondition(Long jobExecutionId, String logLevel, String keyword, LocalDateTime startTime, LocalDateTime endTime); ResponseEntity exportToCsvByCondition(Long jobExecutionId, String logLevel, String keyword, LocalDateTime startTime, LocalDateTime endTime); } ``` ### 6. 日志分析服务接口 ```java package com.datai.salesforce.metadata.log.service; import java.time.LocalDateTime; import java.util.Map; public interface ILogAnalysisService { Map analyzeLogs(Long jobExecutionId); Map analyzeLogsByTimeRange(LocalDateTime startTime, LocalDateTime endTime); Map analyzeLogsByLogLevel(String logLevel, LocalDateTime startTime, LocalDateTime endTime); Map analyzeLogTrend(LocalDateTime startTime, LocalDateTime endTime); Map analyzeLogStatistics(LocalDateTime startTime, LocalDateTime endTime); } ``` ### 7. 日志查询控制器 ```java package com.datai.salesforce.metadata.log.controller; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.datai.common.core.domain.R; import com.datai.salesforce.metadata.log.entity.OperationLog; import com.datai.salesforce.metadata.log.enums.LogLevel; import com.datai.salesforce.metadata.log.service.ILogQueryService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.web.bind.annotation.*; import java.time.LocalDateTime; import java.util.List; @Tag(name = "日志查询管理") @RestController @RequestMapping("/log/query") @RequiredArgsConstructor public class LogQueryController { private final ILogQueryService logQueryService; @Operation(summary = "查询日志列表") @GetMapping("/list") public R> queryLogs( @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "10") int pageSize, @RequestParam(required = false) Long jobExecutionId, @RequestParam(required = false) LogLevel logLevel, @RequestParam(required = false) String keyword, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) { Page page = new Page<>(pageNum, pageSize); Page result = logQueryService.queryLogs(page, jobExecutionId, logLevel, keyword, startTime, endTime); return R.ok(result); } @Operation(summary = "查询日志列表(按条件)") @GetMapping("/condition") public R> queryLogsByCondition( @RequestParam(required = false) Long jobExecutionId, @RequestParam(required = false) LogLevel logLevel, @RequestParam(required = false) String keyword, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) { List logs = logQueryService.queryLogsByCondition(jobExecutionId, logLevel, keyword, startTime, endTime); return R.ok(logs); } @Operation(summary = "查询日志列表(按时间范围)") @GetMapping("/time-range") public R> queryLogsByTimeRange( @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "10") int pageSize, @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime, @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) { Page page = new Page<>(pageNum, pageSize); Page result = logQueryService.queryLogsByTimeRange(page, startTime, endTime); return R.ok(result); } @Operation(summary = "查询日志列表(按作业ID)") @GetMapping("/job-execution") public R> queryLogsByJobExecutionId( @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "10") int pageSize, @RequestParam Long jobExecutionId) { Page page = new Page<>(pageNum, pageSize); Page result = logQueryService.queryLogsByJobExecutionId(page, jobExecutionId); return R.ok(result); } } ``` ### 8. 日志导出控制器 ```java package com.datai.salesforce.metadata.log.controller; import com.datai.common.core.domain.R; import com.datai.salesforce.metadata.log.service.ILogExportService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.time.LocalDateTime; import java.util.List; @Tag(name = "日志导出管理") @RestController @RequestMapping("/log/export") @RequiredArgsConstructor public class LogExportController { private final ILogExportService logExportService; @Operation(summary = "导出为文本文件") @PostMapping("/text") public ResponseEntity exportToText(@RequestBody List logIds) { return logExportService.exportToText(logIds); } @Operation(summary = "导出为Excel文件") @PostMapping("/excel") public ResponseEntity exportToExcel(@RequestBody List logIds) { return logExportService.exportToExcel(logIds); } @Operation(summary = "导出为CSV文件") @PostMapping("/csv") public ResponseEntity exportToCsv(@RequestBody List logIds) { return logExportService.exportToCsv(logIds); } @Operation(summary = "按条件导出为文本文件") @GetMapping("/text/condition") public ResponseEntity exportToTextByCondition( @RequestParam(required = false) Long jobExecutionId, @RequestParam(required = false) String logLevel, @RequestParam(required = false) String keyword, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) { return logExportService.exportToTextByCondition(jobExecutionId, logLevel, keyword, startTime, endTime); } @Operation(summary = "按条件导出为Excel文件") @GetMapping("/excel/condition") public ResponseEntity exportToExcelByCondition( @RequestParam(required = false) Long jobExecutionId, @RequestParam(required = false) String logLevel, @RequestParam(required = false) String keyword, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) { return logExportService.exportToExcelByCondition(jobExecutionId, logLevel, keyword, startTime, endTime); } @Operation(summary = "按条件导出为CSV文件") @GetMapping("/csv/condition") public ResponseEntity exportToCsvByCondition( @RequestParam(required = false) Long jobExecutionId, @RequestParam(required = false) String logLevel, @RequestParam(required = false) String keyword, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) { return logExportService.exportToCsvByCondition(jobExecutionId, logLevel, keyword, startTime, endTime); } } ``` ### 9. 日志分析控制器 ```java package com.datai.salesforce.metadata.log.controller; import com.datai.common.core.domain.R; import com.datai.salesforce.metadata.log.service.ILogAnalysisService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.web.bind.annotation.*; import java.time.LocalDateTime; import java.util.Map; @Tag(name = "日志分析管理") @RestController @RequestMapping("/log/analysis") @RequiredArgsConstructor public class LogAnalysisController { private final ILogAnalysisService logAnalysisService; @Operation(summary = "分析日志(按作业ID)") @GetMapping("/job-execution") public R> analyzeLogs(@RequestParam Long jobExecutionId) { Map analysis = logAnalysisService.analyzeLogs(jobExecutionId); return R.ok(analysis); } @Operation(summary = "分析日志(按时间范围)") @GetMapping("/time-range") public R> analyzeLogsByTimeRange( @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime, @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) { Map analysis = logAnalysisService.analyzeLogsByTimeRange(startTime, endTime); return R.ok(analysis); } @Operation(summary = "分析日志(按日志级别)") @GetMapping("/log-level") public R> analyzeLogsByLogLevel( @RequestParam String logLevel, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) { Map analysis = logAnalysisService.analyzeLogsByLogLevel(logLevel, startTime, endTime); return R.ok(analysis); } @Operation(summary = "分析日志趋势") @GetMapping("/trend") public R> analyzeLogTrend( @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime, @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) { Map analysis = logAnalysisService.analyzeLogTrend(startTime, endTime); return R.ok(analysis); } @Operation(summary = "分析日志统计") @GetMapping("/statistics") public R> analyzeLogStatistics( @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime, @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) { Map analysis = logAnalysisService.analyzeLogStatistics(startTime, endTime); return R.ok(analysis); } } ``` ## 约束 - **技术栈限制**: 必须基于现有的 Spring Boot 3 + Vue 3 技术栈 - **架构约束**: 必须遵循 Authentication.canvas 中定义的架构和调用关系 - **模块约束**: 必须在 datai-salesforce-metadata 模块下实现 - **数据库约束**: 必须使用 MyBatis Plus 作为持久层框架 - **性能约束**: 日志记录和查询性能必须满足要求,不能影响作业执行 - **依赖约束**: 必须依赖于 REQ-010-1, REQ-010-2, REQ-010-6, REQ-010-8, REQ-010-14 ## Rule Set "请严格参考 @Authentication.canvas 中的状态机转移逻辑,不要自行发挥。" **具体规则**: - 必须使用 Canvas 中定义的类名和方法名 - 必须遵循 Canvas 中定义的调用关系 - 必须参考 Canvas 中的流程图逻辑 ## 验收标准 定义验证输出质量的具体标准,例如: - **功能完整性**: 所有日志记录和查询功能能够正常工作 - 日志记录功能正常工作 - 日志查询功能正常工作 - 日志导出功能正常工作 - 日志分析功能正常工作 - **性能指标**: 日志记录和查询性能满足要求,不影响作业执行 - 日志记录响应时间 < 100ms - 日志查询响应时间 < 2s - 日志导出响应时间 < 10s(1000条日志) - 日志分析响应时间 < 5s - **完整性**: 日志信息完整详细,能够追溯作业执行过程 - 日志信息完整详细 - 能够追溯作业执行过程 - **代码规范性**: 代码符合项目编码规范,有清晰的注释 - 使用 Lombok 的 @Data、@RequiredArgsConstructor 注解 - 使用 Swagger 的 @Tag、@Operation 注解 - 使用 MyBatis Plus 的 @TableName、@TableId 注解 - **可维护性**: 代码结构清晰,易于扩展和维护 - 服务接口和实现分离 - 控制器、服务、实体、Mapper 分层清晰 - 使用枚举管理日志级别 - **可测试性**: 代码易于单元测试和集成测试 - 编写单元测试,测试覆盖率 > 80% - 编写集成测试,确保功能正常 ## 风险 识别使用此提示词可能带来的风险,例如: - **输出质量风险**: 代码质量可能不符合项目规范 - **缓解措施**: 使用代码审查,确保代码质量符合项目规范 - **技术实现风险**: 技术实现可能不符合架构决策 - **缓解措施**: 参考架构决策文档,确保技术实现符合架构决策 - **时间成本风险**: 开发周期可能较长 - **缓解措施**: 分阶段实施,优先实现核心功能,逐步完善 - **性能风险**: 日志记录和查询性能可能不佳 - **缓解措施**: 使用异步日志记录,使用索引优化查询,使用缓存提高查询性能 ## 使用记录 | 日期 | 使用场景 | 输入参数 | 输出结果 | 反馈 | 改进措施 | |------|---------|---------|---------|------|----------| | 2026-01-19 | 详细日志记录和查询实现 | REQ-010-15, 0024-logging | 日志记录和查询代码 | 代码质量良好 | 无 |