How to Flush Log Buffers in spdlog: 4 Methods Explained
spdlog provides explicit, automatic, and periodic flushing mechanisms to ensure buffered log data reaches its destination immediately.
When using the gabime/spdlog C++ logging library, controlling when buffered log entries are physically written to their destinations is essential for data integrity, especially in applications that may crash or require audit trails. This article explains how to flush log buffers in spdlog using four distinct API approaches, referencing the actual implementation in the source code.
Explicit Flush on a Single Logger
The most direct way to flush log buffers is calling flush() on a specific logger instance. According to the source code in include/spdlog/logger.h at line 299, the logger::flush() method immediately invokes the flush operation on every sink attached to that logger.
Under the hood, the implementation in include/spdlog/logger-inl.h (lines 98–102) iterates over the logger’s internal sink collection and calls sink->flush() on each one. This forces any buffered content in file sinks or other buffering sinks to write to the underlying device.
// Create a file logger and flush explicitly
auto file_logger = spdlog::basic_logger_mt("file_logger", "app.log");
file_logger->info("starting work");
// … later …
file_logger->flush(); // forces the file sink to write its buffer
Global Flush-on Level
For applications that require flushing on critical events, spdlog::flush_on() sets a global severity threshold. As implemented in include/spdlog/spdlog.h at line 81, this function configures the library to automatically call flush() on any logger that emits a message at or above the specified level.
// Automatically flush whenever error or higher is logged
spdlog::flush_on(spdlog::level::err);
spdlog::error("critical failure"); // this message triggers a flush
This approach ensures that high-severity logs are persisted immediately without manual intervention, while allowing lower-level debug or info messages to remain buffered for performance.
Periodic Background Flushing
Long-running applications can use spdlog::flush_every() to amortize the cost of I/O operations over time. Located at line 86 in include/spdlog/spdlog.h, this function starts a background thread—managed via include/spdlog/details/registry.h—that periodically calls flush() on every registered logger at the specified interval.
// Flush all loggers every 5 seconds automatically
spdlog::flush_every(std::chrono::seconds(5));
// The background thread handles flushing without further user code
This method is ideal for trading immediate durability guarantees for improved throughput, as it batches flush operations rather than executing them per log entry.
Batch Flush All Loggers Using apply_all
When you need to synchronize all loggers at once—such as during application shutdown or before a critical operation—use spdlog::apply_all(). Declared at line 103 in include/spdlog/spdlog.h, this helper iterates over the global logger registry and executes a custom lambda on each instance.
// Flush every registered logger in the application
spdlog::apply_all([](auto logger){ logger->flush(); });
Unlike flush_every, which operates on a timer, apply_all gives you precise control over exactly when the flush sweep occurs.
How Flushing Works Under the Hood
The flush mechanism relies on polymorphic sink behavior. The abstract base class in include/spdlog/sinks/sink.h declares the pure virtual flush() method, which concrete implementations like basic_file_sink and stdout_sink must override to provider-specific logic. When logger::flush() executes, it delegates to this interface, ensuring consistent behavior across file, console, and custom sinks regardless of their internal buffering strategies.
Summary
- Explicit flush: Call
logger->flush()for immediate, synchronous flushing of a specific logger’s sinks. - Automatic flush: Use
spdlog::flush_on(level)to trigger flushes automatically when logging messages at or above a specified severity. - Periodic flush: Employ
spdlog::flush_every(duration)to run a background thread that flushes all loggers at fixed intervals. - Global batch flush: Leverage
spdlog::apply_all()with a lambda to execute flush operations across every registered logger simultaneously.
Frequently Asked Questions
What is the difference between flush_on and flush_every?
According to the spdlog source code, flush_on sets a global severity level that triggers an automatic flush immediately after a message at or above that level is logged, whereas flush_every starts a background thread that calls flush() on all registered loggers at fixed time intervals regardless of what is being logged.
Do console sinks require explicit flushing?
While console sinks like stdout_sink implement the flush() interface defined in include/spdlog/sinks/sink.h, they typically write output immediately without buffering; however, calling flush() ensures consistent behavior across different platforms and sink implementations.
Is the flush operation thread-safe?
Yes, the implementation in include/spdlog/logger-inl.h (lines 98–102) safely iterates over the sink collection, and spdlog’s architecture ensures that flush() can be called concurrently from multiple threads without corrupting the log state.
Can I flush a specific sink instead of all sinks attached to a logger?
While logger->flush() calls flush() on every attached sink, you can access individual sinks through the logger’s sink collection and call sink->flush() directly on a specific instance if you need granular control over buffer persistence.
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 →