0

I'm using boost log and things generally seem to behave as I'd expect, except the way it flushes. I appreciate the potential value to performance from buffering and writing less frequently, but it seems like out of the box it only flushes:

  1. With a log rotation.
  2. The program completes.
  3. Every 8 K or so bytes.

Is there a way to tweak this behavior? In particular, it would be nice if it flushed after a certain timeout rather than waiting forever for that 8K boundary.

While there's a somewhat popular answer to turn off buffering via auto_flush = true (see https://stackoverflow.com/a/18036016/629530), I'd rather not turn off buffering as that seems like a possible hinderance to performance. The logs we're writing can be frequent.

Here's my current implementation (note that I used the following to get ProcessID and ThreadID logged as integers: https://stackoverflow.com/a/45013899/629530)

BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(
     logger, 
      boost::log::sources::severity_logger_mt< >);

auto logger = logging::add_file_log
(   
    keywords::file_name = "diagnostic_%N.log",
    keywords::max_files = 10, // Only keep 10 rotated files around.
    keywords::rotation_size = 10 * 1024 * 1024, // Rotate every 10 MB.
    keywords::time_based_rotation =
            sinks::file::rotation_at_time_point(3, 37, 0), //  Rotate everyday at 3:37 AM.
    keywords::target = directory,
    keywords::format =
    (   
        expr::stream
                << expr::format_date_time< boost::posix_time::ptime >(
                        "TimeStamp", "%b %d %H:%M:%S")
                << boost::phoenix::bind(
                        &get_native_process_id, process_id.or_none()) << " " 
                << boost::phoenix::bind(
                        &get_native_thread_id, thread_id.or_none()) << " " 
                << expr::message
    )   
);  
// We don't expect boost log exceptions, but if they arise discard them.
logging::core::get()->set_exception_handler(logging::make_exception_suppressor());
logging::add_common_attributes();

I then log via BOOST_LOG_TRIVIAL(info).

firebush
  • 5,180
  • 4
  • 34
  • 45

1 Answers1

0

Boost.Log doesn't start internal threads, unless you use asynchronous logging, and even if you do, the dedicated thread has no capability of deferred flushing. So, the sink cannot flush the buffered data after a delay.

What you could do is to flush all sinks periodically by calling core::flush() in your own thread.

Andrey Semashev
  • 10,046
  • 1
  • 17
  • 27
  • Can you explain how to periodically calling `core::flush` ? I used boost::asio asynchronous timer, but it is blocking because of `boost::asio::io_service.run()` and blocks the main thread. – Jafar Gh Mar 31 '20 at 20:06
  • You can start a thread and call `flush` in it. Using an Asio timer should work too. I'm not sure what is the problem you're having. You should expect the `flush` call to block for a considerable amount of time as it will wait until all buffered log records are processed. – Andrey Semashev Mar 31 '20 at 21:32