Boost.Log异步日志记录会定期调用flush()

时间:2020-03-31 18:34:15

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

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

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

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

关于这个examplethis问题,我使用Boost.asio编写了一个异步计时器,但它没有将消息写入文件。实际上,记录器不会创建任何.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()正在阻止。

什么是最小解决方案?

1 个答案:

答案 0 :(得分: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();
    }
}