Search code examples
c++loggingboostrotationboost-log

Boost log 'text_file_backend' - rotate file on demand


I want to cover the cases when my process crashes or just does not shutdown properly and the logs are not rotated.

2 specific cases:

  • if I use a fixed name for my log file (e.g. keywords::file_name = "app.log") and the process did not manged to rotate the log on shutdown (let's say it crashed), then when it gets restarted, it will override my app.log from the instance that crashed. This is bad as that log is particularly interesting.
  • if I use a custom name for my log file (e.g. keywords::file_name = "app_%Y%m%d_%H%M%S_%5N.log") and the process did not manage to rotate the log on shutdown, then when it gets restarted it will create a new app_YMD_HMS_5N.log while leaving the previous log file in the same folder (~/logs) instead of moving it to history (bl::keywords::target = "~/logs/history"). This is also bad because the logs folder gets messy and because only the rotation folder e.i. target (logs/history) is monitored for max_size constraints, so the logs folder could grow uncontrollably.

After looking into it I came to the conclusion that I would do the following:

  • have a fixed name for the log file (e.g. keywords::file_name = "app.log")
  • have a custom name with date and index for the rotated log files to be able to have multiple of them (e.g. keywords::target_file_name = "app_%Y%m%d_%H%M%S_%5N.log".
  • open the log file for append (keywords::open_mode = std::ios_base::app).
  • immediately after opening the log file, call rotate_file() on the text_file_backend in order to rotate a non empty app.log (if the previous app instance didn't manage to properly shutdown the logger).

The problem is that rotate_file() has no effect. The log file is not rotated when I call it.
Am I doing something wrong?

Here is how I setup the file sync:

// File log
auto file_sink = bl::add_file_log(bl::keywords::target          = "history",
                                  bl::keywords::file_name       = "app.log"),
                                  bl::keywords::target_file_name= "app_%Y%m%d_%H%M%S_%5N.log"),
                                  bl::keywords::rotation_size   = 25 * 1024 * 1024,
                                  bl::keywords::max_size        = 250 * 1024 * 1024,
                                  bl::keywords::auto_flush      = true,
                                  bl::keywords::open_mode       = std::ios_base::app,
                                  bl::keywords::max_files       = 10);

file_sink->set_formatter(log_fmt);
file_sink->set_filter(bl::trivial::severity >= level);

// In case the previous log was not rotated on shutdown (it's not empty), rotate it now
file_sink->locked_backend()->rotate_file(); // NOT DOING ANYTHING!

For consistency, I was thinking to also disable rotation on shutdown (keywords::enable_final_rotation = false) in order to only rotate log file on startup, regardless of how my app terminated (crash, kill -9, proper shutdown...) but to get to this I first need to be able to rotate logs on startup.


Solution

  • As Andrey Semashev mentioned, in order for rotate_file() to work, you first need to log something so the log file is actually opened.

    Taking this into account I do the following during logger init (on app startup):

    • disable rotation on shutdown (keywords::enable_final_rotation = false) - this is so for the cases where we don't have a crash, we don't do an extra empty file rotation (in all cases rotation is done on startup or on hitting the collector limits).
    • open the file for append (bl::keywords::open_mode = std::ios_base::app)
    • log something like "Rotating logger on demand"
    • call rotate_file() - this will do the rotation now that log file is opened.

    Here is how it looks:

     // File log
    auto file_sink
        = bl::add_file_log(bl::keywords::target                = "history",
                           bl::keywords::file_name             = "app.log",
                           bl::keywords::target_file_name      = "app_%Y%m%d_%H%M%S_%5N.log",
                           bl::keywords::rotation_size         = 10 * 1024 * 1024,
                           bl::keywords::open_mode             = std::ios_base::app, // Open for append and immediately rotate
                           bl::keywords::enable_final_rotation = false // Rotate only on startup to cover also the crash / kill cases
        );
    
    // Log something so the logger opens the file
    BOOST_LOG_TRIVIAL(info) << "Rotating logs on startup";
    
    // Do the rotation on demand
    file_sink->locked_backend()->rotate_file();