Boost Logging多线程项目Ctrl-C终止后日志文件为空问题求助
问题分析
- Boost Log异步缓冲未刷写:Boost Log的文件sink默认采用异步队列处理日志,当程序被Ctrl-C强制终止时,队列中未处理的日志还没来得及写入磁盘,导致日志文件为空。而单线程测试中程序正常退出,Boost Log会自动完成缓冲刷写,因此日志能正常保存。
- 缺少信号处理机制:未捕获SIGINT信号,程序直接被终止,没有机会执行Boost Log的清理流程,无法完成日志的最终刷盘操作。
- 过滤器覆盖问题:
setLoggingEnabled方法中两次调用set_filter,第二次会完全覆盖第一次的过滤规则,导致LoggingEnabled的过滤条件失效,虽然这不是日志为空的直接原因,但会引发预期外的日志过滤行为。
解决方案
1. 捕获SIGINT信号,实现优雅终止
在多线程项目中添加信号处理逻辑,收到Ctrl-C时停止io_context,并显式刷新Boost Log的所有缓冲,确保日志写入磁盘。
示例代码:
#include <signal.h> #include <atomic> #include <boost/log/core.hpp> #include <boost/log/sinks.hpp> std::atomic_bool g_running = true; void signal_handler(int signum) { if (signum == SIGINT) { g_running = false; // 停止异步IO上下文 io_context.stop(); // 显式刷新所有日志sink auto core = boost::log::core::get(); core->flush(); } } int main(int argc, char* argv[]) { // 注册SIGINT信号处理函数 signal(SIGINT, signal_handler); // 初始化日志对象 FileLocalLoggerWithAttribute logger("app.log", true); // 初始化读写操作 // ... while (g_running) { try { io_context.run(); } catch (const std::exception& e) { logger.log(boost::log::trivial::error, e.what(), "Main", __func__); } } // 再次确保日志缓冲被刷新 boost::log::core::get()->flush(); return 0; }
2. 调整日志sink的刷新策略
在初始化文件sink时,设置auto_flush参数为true,让每条日志都立即刷写到磁盘,避免缓冲丢失。修改日志类构造函数:
FileLocalLoggerWithAttribute::FileLocalLoggerWithAttribute(std::string filename, bool isEnabled) : filename_(filename), logger_() { logging::add_file_log( keywords::file_name = filename_, keywords::rotation_size = 10 * 1024 * 1024, keywords::time_based_rotation = sinks::file::rotation_at_time_point(0, 0, 0), keywords::auto_flush = true, // 新增:立即刷新日志到磁盘 keywords::format = ( expr::stream << expr::format_date_time< boost::posix_time::ptime>("TimeStamp", "%Y-%m-%d %H:%M:%S") << ": <" << logging::trivial::severity << "> [src: " << expr::attr<std::string>("Who") << "] " << "[Function: " << expr::attr<std::string>("FunctionName") << "] " << expr::message ) ); setLoggingEnabled(isEnabled); }
注意:auto_flush会降低日志写入性能,适合对日志实时性要求高或程序可能被强制终止的场景。
3. 修复过滤器覆盖问题
合并两个过滤条件,避免后一次调用覆盖前一次的规则:
void FileLocalLoggerWithAttribute::setLoggingEnabled(bool enabled) { logger_.add_attribute("LoggingEnabled", attrs::constant<bool>(enabled)); // 合并过滤条件:日志启用且级别>=info logging::core::get()->set_filter( expr::attr<bool>("LoggingEnabled") == true && logging::trivial::severity >= logging::trivial::info ); }
4. 确保日志对象生命周期
将日志对象声明在main函数的最外层,保证其生命周期覆盖整个程序运行过程,避免因对象提前销毁导致日志处理中断。
内容的提问来源于stack exchange,提问作者user29207775
相关产品推荐
相关产品推荐

