【问题标题】:Boost.Log asynchronous logging invoke flush() periodicallyBoost.Log 异步日志调用 flush() 定期
【发布时间】:2020-03-31 18:34:15
【问题描述】:

我正在 Boost.Log 之上实现一个包装器。在异步日志中,记录器不会立即写入日志消息,而是创建一个消息队列。当调用core.get()->flush() 方法时,消息将被写入文件。

但显然在每条消息之后调用 flush() 效率不高。这样异步日志记录没有任何好处。而且在程序结束时调用它一次也不是一个好主意。 (可能程序在服务器上运行了很长时间)

我想编写一个代码来定期调用 flush()(例如每 10 毫秒)。

有了这个examplethis 的问题,我使用Boost.asio 编写了一个异步计时器,但它没有将消息写入文件。实际上 logger 不会创建任何 .log 文件。可能是因为在没有发生日志记录时必须调用 flush() 方法。

typedef sinks::asynchronous_sink<
    sinks::text_file_backend,
    sinks::unbounded_ordering_queue<
        logging::attribute_value_ordering< unsigned int, std::less< unsigned int > >
    >
> Async_file_sink;

void do_flush(const boost::system::error_code& /*e*/,
    boost::asio::deadline_timer* t)
{
    logging::core::get()->flush();

    t->expires_at(t->expires_at() + boost::posix_time::milliseconds(10));
    t->async_wait(boost::bind(do_flush,
          boost::asio::placeholders::error, t));
}

struct PerodicTimer{
    PerodicTimer(boost::asio::deadline_timer &timer) : t(timer) {
        t.async_wait(boost::bind(do_flush,
                    boost::asio::placeholders::error, &t));
   }
   boost::asio::deadline_timer& t;
};

void init_flushing()
{
    boost::asio::io_service io;
    boost::asio::deadline_timer t(io, boost::posix_time::milliseconds(10));

    PerodicTimer m(t);
        std::thread th([&]{
        // std::cout << "inside thread" << std::endl;
        io.run();
    });

    th.detach();
}

static void init_logging() 
{
    logging::add_common_attributes();
    boost::shared_ptr< Async_file_sink > sink(new Async_file_sink(
        boost::make_shared< sinks::text_file_backend >(),
        keywords::file_name = "sample_%N.log",
        keywords::rotation_size = 1024 * 1024,
        // We'll apply record ordering to ensure that records from different threads go sequentially in the file
        keywords::order = logging::make_attr_ordering("LineID", std::less< unsigned int >())
    ));

    // Set up where the rotated files will be stored
    init_file_collecting(sink);
    sink->set_formatter(&my_formatter);
    sink->locked_backend()->scan_for_files();
    logging::core::get()->add_sink(sink);
    init_flushing();  // Starting Timer
} 

int main()
{
    init_logging();

    ADD_LOG("SOME MESSAGE");
}

我认为问题出在调用()flush()时,同时异步记录器正在记录消息。我无法在同一个线程中运行异步计时器,因为 io.run() 正在阻塞。

什么是最小解决方案?

【问题讨论】:

    标签: c++ asynchronous logging boost boost-asio


    【解决方案1】:

    init_flushing 中,您在生成线程后立即退出并在线程运行时销毁io_service iodeadline_timer t 对象。这是未定义的行为,因此可以解释为什么代码的行为不符合您的预期。

    iot 在线程运行时都必须保持活动状态。但是,由于除了等待计时器之外,您没有将io 用于其他任何事情,因此只需一个调用std::this_thread::sleep_for 等待的循环和一个终止循环的原子标志就会简单得多。

    std::thread flushing_thread;
    std::atomic<bool> terminate_flushing_thread{ false };
    
    void init_flushing()
    {
        assert(!flushing_thread.joinable());
    
        flushing_thread = std::thread([]()
        {
            while (!terminate_flushing_thread.load(std::memory_order_relaxed))
            {
                std::this_thread::sleep_for(std::chrono::milliseconds(10));
                logging::core::get()->flush();
            }
        });
    }
    
    void stop_flushing()
    {
        if (flushing_thread.joinable())
        {
            terminate_flushing_thread.store(true, std::memory_order_relaxed);
            flushing_thread.join();
        }
    }
    

    【讨论】:

    • 谢谢,它正在工作。我想你的意思是std::this_thread::sleep_for()
    • 另外,在flushing_thread 内的while 循环之后,调用core::flush() 是必要的。因为也许通过调用stop_flushing() 仍然没有将一些日志消息发送到文件。
    • > 我想你的意思是std::this_thread::sleep_for() ? -- 对,我已经更正了答案。
    • > 另外,在flushing_thread 内的while 循环之后,调用core::flush() 听起来是必要的。因为也许通过调用 stop_flushing() 仍然没有将一些日志消息发送到文件。 - 并不真地。当您的应用程序仍在运行并且可以生成日志记录时,您不应该调用stop_flushing。当它被调用时,你正在关闭。此外,flushing_thread 在退出前调用 flush,除非您在生成后立即终止它。
    • 我觉得我在这里遗漏了一些东西。我刚开始玩异步前端,所以我真的很想了解。像这样不断在另一个线程中运行的刷新有什么意义?冲洗时,所有水槽都会阻塞。如果每 10 毫秒你的异步接收器将处于阻塞任何日志记录的状态,直到所有未完成的日志记录被刷新,那么让它异步有什么意义?我一定是误会了什么……
    猜你喜欢
    • 2020-07-06
    • 2016-03-12
    • 1970-01-01
    • 2023-01-19
    • 1970-01-01
    • 2012-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多