日志轮转按业务重要性权重保留文件,用std::map映射路径前缀或后缀到权重值,优先删除低权文件,同权按时间淘汰;权重为0则跳过。

日志轮转时如何按权重决定保留哪些文件
权重不是指文件大小或时间戳的简单排序,而是你定义的“业务重要性”——比如 error.log 权重 10,access.log 权重 5,debug.log 权重 1。系统清理时优先删低权重文件,同权重再按时间淘汰。
关键在设计一个可扩展的权重映射逻辑,而不是硬编码 if-else 判断文件名:
- 用
std::map<:string int></:string>存储后缀或路径前缀到权重的映射(如".error"→ 10,"api/"→ 8) - 解析日志文件名时,按顺序匹配最长前缀或最具体后缀,避免
"debug"匹配到所有含 debug 的名字 - 权重为 0 的文件不参与轮转,直接跳过(适合临时调试日志)
- 注意:权重不解决单个大日志爆炸问题,需配合
max_file_size单独控制
std::filesystem 遍历 + std::chrono 排序的坑在哪
用 std::filesystem::directory_iterator 扫目录看似干净,但实际容易踩三个隐性坑:
- Windows 下 NTFS 时间精度只有 100ns,但
last_write_time()返回的是file_time_type,直接转system_clock::time_point可能截断,导致同秒内多个日志排序错乱 —— 建议统一用file_time_type比较,别强转 -
std::filesystem::is_regular_file()必须显式调用,否则符号链接、socket 文件会混入,file_size()对它们可能抛std::filesystem::filesystem_error - 遍历时没加异常捕获,遇到权限拒绝(如某些 systemd 日志目录)会导致整个轮转中断 —— 应用
std::filesystem::status_known()先探活,失败则跳过并记录警告
示例排序片段:
std::vector<std::pair<std::filesystem::path, std::filesystem::file_time_type>> files;
for (const auto& entry : std::filesystem::directory_iterator(log_dir)) {
if (!entry.is_regular_file()) continue;
try {
files.emplace_back(entry.path(), entry.last_write_time());
} catch (...) { /* 跳过不可读项 */ }
}
std::sort(files.begin(), files.end(), [](const auto& a, const auto& b) {
return a.second < b.second; // 用原生 file_time_type 比较
});
清理策略触发时机选 on_write 还是 on_startup
两种触发方式本质是权衡实时性与启动开销:
立即学习“C++免费学习笔记(深入)”;
-
on_write:每次写日志前检查总大小/文件数,超阈值立即清理 —— 适合写入频率低、但单次日志价值高的场景(如金融交易流水),但高频写入(>100Hz)下反复 stat + sort 会拖慢性能 -
on_startup:只在服务启动时做一次全量清理 —— 启动变慢,但运行期零开销;适合容器化部署(Pod 重启即清)、或日志由外部 agent 收集的场景 - 更稳的做法是「双触发」:启动时轻量扫描(只读取 mtime + size,不排序),写入时仅检查是否超过硬上限(如磁盘使用率 >90%),再触发完整清理
- 注意:
on_write清理不能阻塞主日志线程,必须异步丢进线程池,否则日志卡住会导致业务超时
跨平台路径处理和权限问题怎么绕过去
Linux 下 /var/log/myapp/ 可能被 root 创建,普通用户进程无法删除;Windows 下 C:Program Files 默认禁止写入。硬扛权限不如换路径策略:
- 默认回退到用户可写位置:
std::filesystem::temp_directory_path() / "myapp_logs"(Linux/macOS)或std::filesystem::current_path() / "logs"(Windows portable 模式) - 用
std::filesystem::permissions()检查目标目录是否可写,不可写时自动降级,不报错退出 - Windows 上避免用
\?扩展路径做日志路径(虽然支持长路径),因为std::filesystem实现对其支持不一,容易在 MinGW 或旧 MSVC 版本崩溃 - 清理时不要用
remove_all()直接删整个目录 —— 若目录被其他进程占用(如 tail -f),会失败;改用逐个remove()+sleep(1ms)重试最多 3 次
事情说清了就结束。权重逻辑和清理时机这两个点,最容易在压测或上线后才暴露,建议早期就在 CI 中加入多权重混合日志生成+清理验证用例。



















