You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

143 lines
4.6 KiB
Markdown

# Redis 日志管理功能优化
## 问题描述
原始代码的日志管理逻辑存在问题:
- 只处理包含 `%` 的日志行,导致其他重要日志被忽略
- 对于进度日志的处理逻辑不清晰
- 没有正确实现"记录所有日志,但进度日志只保留最新"的需求
## 新的实现逻辑
### 核心需求
1. **记录所有日志**:不只是包含 `%` 的日志,所有训练日志都应该记录
2. **进度日志去重**:当遇到包含 `%` 的进度日志时,删除之前的进度日志,只保留最新的
3. **容量控制**:最多保存 50 条日志,超过时删除最旧的
4. **过期时间**:所有日志保存 5 天
### 修改后的方法
#### `manageTrainingLogInRedis`
```java
private void manageTrainingLogInRedis(Integer trainId, String logLine) {
try {
if (logLine == null || logLine.trim().isEmpty()) {
return;
}
String redisKey = "yolo:training_log:" + trainId;
boolean isProgressLog = logLine.contains("%");
if (isProgressLog) {
// 如果是进度日志(包含%),先删除之前的进度日志
removeProgressLogs(redisKey);
}
// 添加新的日志行到列表末尾
redisUtil.lSet(redisKey, logLine, 5 * 24 * 60 * 60); // 5天过期时间
// 检查列表长度如果超过50条删除第一条
long newSize = redisUtil.lGetListSize(redisKey);
if (newSize > 50) {
redisUtil.lRemove(redisKey, 1, redisUtil.lGetIndex(redisKey, 0));
}
log.debug("训练日志已存储到Redis - 训练ID: {}, 日志类型: {}, 当前日志数量: {}",
trainId, isProgressLog ? "进度日志" : "普通日志", redisUtil.lGetListSize(redisKey));
} catch (Exception e) {
log.error("管理训练日志Redis操作失败 - 训练ID: {}", trainId, e);
}
}
```
#### `removeProgressLogs`
新增的辅助方法,专门用于删除所有进度日志:
```java
private void removeProgressLogs(String redisKey) {
try {
// 获取所有日志
java.util.List<Object> allLogs = redisUtil.lGet(redisKey, 0, -1);
// 找出并删除所有包含%的日志
for (int i = allLogs.size() - 1; i >= 0; i--) {
Object logObj = allLogs.get(i);
if (logObj != null) {
String logStr = logObj.toString();
if (logStr.contains("%")) {
redisUtil.lRemove(redisKey, 1, logStr);
log.debug("删除旧的进度日志: {}", logStr);
}
}
}
} catch (Exception e) {
log.error("删除进度日志时出错 - Redis键: {}", redisKey, e);
}
}
```
## 工作流程示例
### 场景1普通日志
```
输入: "YOLO训练开始"
处理: 直接添加到Redis列表
结果: Redis列表: ["YOLO训练开始"]
```
### 场景2进度日志第一次
```
输入: "Epoch 1/100: 50%|█████ | 100/200 [00:30<00:30]"
处理: 添加到Redis列表
结果: Redis列表: ["YOLO训练开始", "Epoch 1/100: 50%|█████ | 100/200 [00:30<00:30]"]
```
### 场景3进度日志更新
```
输入: "Epoch 1/100: 75%|███████▌ | 150/200 [00:45<00:15]"
处理: 1. 删除之前的进度日志 2. 添加新的进度日志
结果: Redis列表: ["YOLO训练开始", "Epoch 1/100: 75%|███████▌ | 150/200 [00:45<00:15]"]
```
### 场景4混合日志
```
输入序列:
1. "模型加载完成" -> 普通日志,直接添加
2. "Epoch 1/100: 25%|██▌ | 50/200 [00:15<00:45]" -> 进度日志,添加
3. "数据预处理完成" -> 普通日志,直接添加
4. "Epoch 1/100: 50%|█████ | 100/200 [00:30<00:30]" -> 进度日志,删除之前的进度日志并添加
最终Redis列表:
["模型加载完成", "数据预处理完成", "Epoch 1/100: 50%|█████ | 100/200 [00:30<00:30]"]
```
## 优势
1. **完整性**:所有重要日志都被保存,不会遗漏
2. **效率性**:进度日志只保留最新状态,避免重复
3. **可控性**最多50条日志防止Redis占用过多内存
4. **可维护性**:清晰的日志类型区分和调试信息
## 日志类型
- **普通日志**:训练开始、模型加载、错误信息等
- **进度日志**:包含 `%` 的进度条信息,如训练进度
## Redis 键格式
```
yolo:training_log:{trainId}
```
例如:
```
yolo:training_log:12345
```
## 过期时间
所有日志条目设置 5 天过期时间432,000 秒),自动清理旧数据。