datai/docs/archive/prompts/025-logging.md

524 lines
20 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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
- 日志导出响应时间 < 10s1000条日志
- 日志分析响应时间 < 5s
- **完整性**: 日志信息完整详细能够追溯作业执行过程
- 日志信息完整详细
- 能够追溯作业执行过程
- **代码规范性**: 代码符合项目编码规范有清晰的注释
- 使用 Lombok @Data、@RequiredArgsConstructor 注解
- 使用 Swagger @Tag、@Operation 注解
- 使用 MyBatis Plus @TableName、@TableId 注解
- **可维护性**: 代码结构清晰易于扩展和维护
- 服务接口和实现分离
- 控制器服务实体Mapper 分层清晰
- 使用枚举管理日志级别
- **可测试性**: 代码易于单元测试和集成测试
- 编写单元测试测试覆盖率 > 80%
- 编写集成测试,确保功能正常
## 风险
识别使用此提示词可能带来的风险,例如:
- **输出质量风险**: 代码质量可能不符合项目规范
- **缓解措施**: 使用代码审查,确保代码质量符合项目规范
- **技术实现风险**: 技术实现可能不符合架构决策
- **缓解措施**: 参考架构决策文档,确保技术实现符合架构决策
- **时间成本风险**: 开发周期可能较长
- **缓解措施**: 分阶段实施,优先实现核心功能,逐步完善
- **性能风险**: 日志记录和查询性能可能不佳
- **缓解措施**: 使用异步日志记录,使用索引优化查询,使用缓存提高查询性能
## 使用记录
| 日期 | 使用场景 | 输入参数 | 输出结果 | 反馈 | 改进措施 |
|------|---------|---------|---------|------|----------|
| 2026-01-19 | 详细日志记录和查询实现 | REQ-010-15, 0024-logging | 日志记录和查询代码 | 代码质量良好 | 无 |