Configuring Periodic Flush with spdlog flush_every(): A Complete Guide
Use spdlog::flush_every(std::chrono::duration) to enable a background thread that automatically flushes all registered loggers at regular intervals, ensuring buffered logs are written to disk without manual intervention.
The gabime/spdlog library provides a robust mechanism for periodic log flushing through the flush_every() function. This feature is essential when working with buffered sinks—such as file or rotating file sinks—where you want to guarantee data persistence without calling logger->flush() after every log statement. Configuring periodic flush with spdlog flush_every() offloads this responsibility to a dedicated background thread managed by the library's internal registry.
How spdlog::flush_every() Works
The periodic flush mechanism operates through a cooperation between the public API and the internal registry singleton.
The Public API Interface
The entry point for this feature is the inline helper function defined in [include/spdlog/spdlog.h](https://github.com/gabime/spdlog/blob/v1.x/include/spdlog/spdlog.h):
template<typename Rep, typename Period>
inline void flush_every(std::chrono::duration<Rep, Period> interval) {
details::registry::instance().flush_every(interval);
}
This template accepts any std::chrono::duration type, allowing you to specify intervals using std::chrono::seconds, std::chrono::minutes, or other duration units.
Registry Singleton and Thread Management
When you invoke flush_every(), the call forwards to details::registry::instance(), which lives in [src/spdlog.cpp](https://github.com/gabime/spdlog/blob/v1.x/src/spdlog.cpp). The registry maintains a background thread that:
- Waits for the specified interval using a condition variable
- Iterates over all registered loggers via
spdlog::apply_all([](auto& l){ l->flush(); }) - Calls each logger's
flush()method, which propagates to individual sink implementations
If the interval is non-zero, the registry starts (or restarts) this thread. Passing a zero-duration (std::chrono::seconds(0)) stops the thread entirely, disabling automatic flushing.
Implementation Details in the Source Code
The periodic flush implementation spans several key files in the repository:
include/spdlog/spdlog.h: Declares the publicflush_every()template functionsrc/spdlog.cpp: Contains theregistryclass implementation that manages the background flusher thread lifecycle (creation, joining on shutdown, and restart logic)include/spdlog/logger.h: Defineslogger::flush(), which forwards the flush command to each sink'sflush_()methodinclude/spdlog/sinks/*_sink.h: Sink-specific implementations (e.g.,rotating_file_sink::flush_()writes the file buffer to disk)
The thread ensures that all registered logger instances—whether synchronous or asynchronous—receive flush commands uniformly.
Practical Code Examples
Basic Periodic Flush Configuration
The following example demonstrates configuring a 2-second flush interval for a file logger:
#include <spdlog/spdlog.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <chrono>
#include <thread>
int main()
{
// Create a logger that writes to a file
auto file_logger = spdlog::basic_logger_mt("file_logger", "example.log");
// Enable periodic flushing every 2 seconds
spdlog::flush_every(std::chrono::seconds(2));
// Log messages - they will be flushed automatically in the background
for (int i = 0; i < 10; ++i) {
file_logger->info("message {}", i);
std::this_thread::sleep_for(std::chrono::milliseconds(300));
}
// Cleanup: Stop the periodic flusher before exit
spdlog::flush_every(std::chrono::seconds(0));
}
Test-Driven Usage Pattern
The spdlog test suite in [tests/test_misc.cpp](https://github.com/gabime/spdlog/blob/v1.x/tests/test_misc.cpp) provides a concrete validation example:
auto logger = spdlog::create<test_sink_mt>("periodic_flush");
spdlog::flush_every(std::chrono::seconds(1));
// Allow time for the background thread to trigger
std::this_thread::sleep_for(std::chrono::milliseconds(1200));
// Verify flush occurred
REQUIRE(test_sink->flush_counter() == 1);
// Disable periodic flushing
spdlog::flush_every(std::chrono::seconds(0));
This pattern demonstrates that the background thread wakes up after the specified interval and invokes flush() on all loggers.
Disabling the Periodic Flusher
To stop the background flush thread, call flush_every() with a zero duration:
spdlog::flush_every(std::chrono::seconds(0));
According to the registry implementation in src/spdlog.cpp, this signals the background thread to exit its loop and join. After disabling, you must manually call logger->flush() if you require immediate buffer persistence.
Summary
spdlog::flush_every()creates a background thread that flushes all loggers at regular intervals defined by astd::chrono::durationparameter.- The function is defined in
include/spdlog/spdlog.hand delegates todetails::registry::instance().flush_every()implemented insrc/spdlog.cpp. - Passing
std::chrono::seconds(0)stops the periodic flusher thread. - This mechanism works uniformly for both synchronous and asynchronous loggers (
spdlog::async_logger) because the registry manages all logger types through the sameapply_allinterface. - Periodic flushing prevents data loss in buffered sinks while avoiding the performance penalty of flushing on every log write.
Frequently Asked Questions
What is the difference between flush_every() and flush_on()?
flush_on() sets the log level that triggers an immediate flush after each log statement of that level or higher (e.g., spdlog::flush_on(spdlog::level::warn) flushes automatically when logging warnings or errors). In contrast, flush_every() operates on a time interval independent of log levels, flushing all buffered messages periodically regardless of their severity.
Does flush_every() work with asynchronous loggers?
Yes. The periodic flush mechanism works with asynchronous loggers (spdlog::async_logger) because the registry's apply_all() method iterates over all registered loggers uniformly. When the background thread triggers, it calls flush() on each logger, which for async loggers ensures the underlying thread pool processes any remaining messages in the queue before the sinks flush.
How do I stop the periodic flush thread?
Call spdlog::flush_every(std::chrono::seconds(0)) or pass any zero-duration value. According to the implementation in src/spdlog.cpp, this stops the internal condition variable loop and joins the background thread. This is useful when you want to manually control flushing or during application shutdown to ensure proper cleanup.
What happens to unflushed logs when the application crashes?
If the application crashes between automatic flush intervals, any log messages buffered in memory but not yet written to disk will be lost. To minimize this risk, configure a shorter flush interval for critical applications, or use flush_on(spdlog::level::err) to ensure immediate persistence of high-priority error messages while maintaining periodic flushing for lower-level debug logs.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →