524 lines
20 KiB
Markdown
524 lines
20 KiB
Markdown
# 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<OperationLog> getLogsByJobExecutionId(Long jobExecutionId);
|
||
|
||
List<OperationLog> getLogsByLogLevel(LogLevel logLevel);
|
||
|
||
boolean deleteLog(Long id);
|
||
|
||
boolean batchDeleteLogs(List<Long> 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<OperationLog> queryLogs(Page<OperationLog> page,
|
||
Long jobExecutionId,
|
||
LogLevel logLevel,
|
||
String keyword,
|
||
LocalDateTime startTime,
|
||
LocalDateTime endTime);
|
||
|
||
List<OperationLog> queryLogsByCondition(Long jobExecutionId,
|
||
LogLevel logLevel,
|
||
String keyword,
|
||
LocalDateTime startTime,
|
||
LocalDateTime endTime);
|
||
|
||
IPage<OperationLog> queryLogsByTimeRange(Page<OperationLog> page,
|
||
LocalDateTime startTime,
|
||
LocalDateTime endTime);
|
||
|
||
IPage<OperationLog> queryLogsByJobExecutionId(Page<OperationLog> 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<byte[]> exportToText(List<Long> logIds);
|
||
|
||
ResponseEntity<byte[]> exportToExcel(List<Long> logIds);
|
||
|
||
ResponseEntity<byte[]> exportToCsv(List<Long> logIds);
|
||
|
||
ResponseEntity<byte[]> exportToTextByCondition(Long jobExecutionId,
|
||
String logLevel,
|
||
String keyword,
|
||
LocalDateTime startTime,
|
||
LocalDateTime endTime);
|
||
|
||
ResponseEntity<byte[]> exportToExcelByCondition(Long jobExecutionId,
|
||
String logLevel,
|
||
String keyword,
|
||
LocalDateTime startTime,
|
||
LocalDateTime endTime);
|
||
|
||
ResponseEntity<byte[]> 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<String, Object> analyzeLogs(Long jobExecutionId);
|
||
|
||
Map<String, Object> analyzeLogsByTimeRange(LocalDateTime startTime,
|
||
LocalDateTime endTime);
|
||
|
||
Map<String, Object> analyzeLogsByLogLevel(String logLevel,
|
||
LocalDateTime startTime,
|
||
LocalDateTime endTime);
|
||
|
||
Map<String, Object> analyzeLogTrend(LocalDateTime startTime,
|
||
LocalDateTime endTime);
|
||
|
||
Map<String, Object> 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<Page<OperationLog>> 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<OperationLog> page = new Page<>(pageNum, pageSize);
|
||
Page<OperationLog> result = logQueryService.queryLogs(page, jobExecutionId, logLevel, keyword, startTime, endTime);
|
||
return R.ok(result);
|
||
}
|
||
|
||
@Operation(summary = "查询日志列表(按条件)")
|
||
@GetMapping("/condition")
|
||
public R<List<OperationLog>> 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<OperationLog> logs = logQueryService.queryLogsByCondition(jobExecutionId, logLevel, keyword, startTime, endTime);
|
||
return R.ok(logs);
|
||
}
|
||
|
||
@Operation(summary = "查询日志列表(按时间范围)")
|
||
@GetMapping("/time-range")
|
||
public R<Page<OperationLog>> 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<OperationLog> page = new Page<>(pageNum, pageSize);
|
||
Page<OperationLog> result = logQueryService.queryLogsByTimeRange(page, startTime, endTime);
|
||
return R.ok(result);
|
||
}
|
||
|
||
@Operation(summary = "查询日志列表(按作业ID)")
|
||
@GetMapping("/job-execution")
|
||
public R<Page<OperationLog>> queryLogsByJobExecutionId(
|
||
@RequestParam(defaultValue = "1") int pageNum,
|
||
@RequestParam(defaultValue = "10") int pageSize,
|
||
@RequestParam Long jobExecutionId) {
|
||
Page<OperationLog> page = new Page<>(pageNum, pageSize);
|
||
Page<OperationLog> 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<byte[]> exportToText(@RequestBody List<Long> logIds) {
|
||
return logExportService.exportToText(logIds);
|
||
}
|
||
|
||
@Operation(summary = "导出为Excel文件")
|
||
@PostMapping("/excel")
|
||
public ResponseEntity<byte[]> exportToExcel(@RequestBody List<Long> logIds) {
|
||
return logExportService.exportToExcel(logIds);
|
||
}
|
||
|
||
@Operation(summary = "导出为CSV文件")
|
||
@PostMapping("/csv")
|
||
public ResponseEntity<byte[]> exportToCsv(@RequestBody List<Long> logIds) {
|
||
return logExportService.exportToCsv(logIds);
|
||
}
|
||
|
||
@Operation(summary = "按条件导出为文本文件")
|
||
@GetMapping("/text/condition")
|
||
public ResponseEntity<byte[]> 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<byte[]> 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<byte[]> 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<Map<String, Object>> analyzeLogs(@RequestParam Long jobExecutionId) {
|
||
Map<String, Object> analysis = logAnalysisService.analyzeLogs(jobExecutionId);
|
||
return R.ok(analysis);
|
||
}
|
||
|
||
@Operation(summary = "分析日志(按时间范围)")
|
||
@GetMapping("/time-range")
|
||
public R<Map<String, Object>> analyzeLogsByTimeRange(
|
||
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime,
|
||
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) {
|
||
Map<String, Object> analysis = logAnalysisService.analyzeLogsByTimeRange(startTime, endTime);
|
||
return R.ok(analysis);
|
||
}
|
||
|
||
@Operation(summary = "分析日志(按日志级别)")
|
||
@GetMapping("/log-level")
|
||
public R<Map<String, Object>> 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<String, Object> analysis = logAnalysisService.analyzeLogsByLogLevel(logLevel, startTime, endTime);
|
||
return R.ok(analysis);
|
||
}
|
||
|
||
@Operation(summary = "分析日志趋势")
|
||
@GetMapping("/trend")
|
||
public R<Map<String, Object>> analyzeLogTrend(
|
||
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime,
|
||
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) {
|
||
Map<String, Object> analysis = logAnalysisService.analyzeLogTrend(startTime, endTime);
|
||
return R.ok(analysis);
|
||
}
|
||
|
||
@Operation(summary = "分析日志统计")
|
||
@GetMapping("/statistics")
|
||
public R<Map<String, Object>> analyzeLogStatistics(
|
||
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime,
|
||
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) {
|
||
Map<String, Object> 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 | 日志记录和查询代码 | 代码质量良好 | 无 |
|