You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Boost Logging多线程项目Ctrl-C终止后日志文件为空问题求助

问题分析
  1. Boost Log异步缓冲未刷写:Boost Log的文件sink默认采用异步队列处理日志,当程序被Ctrl-C强制终止时,队列中未处理的日志还没来得及写入磁盘,导致日志文件为空。而单线程测试中程序正常退出,Boost Log会自动完成缓冲刷写,因此日志能正常保存。
  2. 缺少信号处理机制:未捕获SIGINT信号,程序直接被终止,没有机会执行Boost Log的清理流程,无法完成日志的最终刷盘操作。
  3. 过滤器覆盖问题: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 02:10:08