# 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 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 秒),自动清理旧数据。