How spdlog File Rotation Works: A Complete Guide to rotating_file_sink
spdlog implements size-based file rotation through the rotating_file_sink class, which monitors current_size_ and triggers a cascading rename operation via rotate_() when logs exceed max_size, preserving only max_files backups.
The spdlog library (gabime/spdlog) provides automatic log management through its rotating_file_sink implementation. Understanding how spdlog file rotation works is essential for production deployments where disk space management is critical. The mechanism tracks write volume in real-time and automates the archival process through systematic file renaming.
The rotating_file_sink Architecture
At the core of spdlog file rotation is the rotating_file_sink class defined in include/spdlog/sinks/rotating_file_sink.h. When instantiated through factory functions like spdlog::rotating_logger_mt(), the sink accepts three critical parameters that control rotation behavior:
- max_size: The byte threshold that triggers rotation when exceeded
- max_files: The maximum number of archived files to retain (oldest files are deleted)
- rotate_on_open: Boolean flag to force immediate rotation if the target file already contains data
The sink maintains the current file size in the current_size_ member variable, initialized from file_helper_.size() during construction. This counter increments with every log message written to track when the next rotation is required.
Triggering Rotation: The sink_it_ Method
Rotation occurs during the sink_it_() method execution when the accumulated size exceeds the configured threshold. The implementation in include/spdlog/sinks/rotating_file_sink-inl.h (lines 11-17) performs the size check after formatting each log message:
// include/spdlog/sinks/rotating_file_sink-inl.h, lines 11-17
if (new_size > max_size_) {
file_helper_.flush();
if (file_helper_.size() > 0) {
rotate_(); // ← trigger rotation
new_size = formatted.size(); // reset size after rotation
}
}
The code first flushes the file helper to ensure all data is committed to disk, verifies the file contains data, then invokes the rotation routine. After rotation completes, the size counter resets to the current message size since a fresh file has been opened.
The Rotation Algorithm: Inside rotate_()
The actual file manipulation occurs in the rotate_() method (lines 38-66 of include/spdlog/sinks/rotating_file_sink-inl.h). This function implements a cascading rename strategy that shifts existing archives before creating a new active log:
- Close the current file via
file_helper_.close()to release the file handle - Iterate backwards from
max_files_down to 1, renaminglog.i.txttolog.(i+1).txt - Handle conflicts by deleting existing target files before renaming (with retry logic on Windows)
- Reopen a fresh file using
file_helper_.reopen(true)and reset the size counter
The core implementation appears as follows:
// include/spdlog/sinks/rotating_file_sink-inl.h, lines 38-66
for (auto i = max_files_; i > 0; --i) {
filename_t src = calc_filename(base_filename_, i - 1);
if (!path_exists(src)) continue;
filename_t target = calc_filename(base_filename_, i);
if (!rename_file_(src, target)) { … }
}
file_helper_.reopen(true);
The helper function calc_filename constructs indexed filenames while preserving file extensions (e.g., converting app.log to app.1.log). If max_files_ is set to 0, the rotation logic is bypassed entirely and the log file grows indefinitely until process termination.
Creating Rotating Loggers
You instantiate rotating loggers through the factory functions declared in include/spdlog/sinks/rotating_file_sink.h (lines 68-88). The multi-threaded variant provides thread-safe rotation:
// Example 1 – Basic rotating logger (multi-threaded)
auto logger = spdlog::rotating_logger_mt(
"file_logger", // logger name
"logs/app.log", // base filename
5 * 1024 * 1024, // 5 MiB max size per file
3); // keep at most 3 rotated files
logger->info("Application started");
For single-threaded applications or header-only mode, use the _st suffix and enable immediate rotation on startup:
// Example 2 – Rotate on startup, single-threaded
spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l %v");
auto logger = spdlog::rotating_logger_st(
"daily", "logs/daily.log", 10 * 1024 * 1024, 5, true);
logger->warn("Rotated because file existed from previous run");
These factories abstract the rotating_file_sink construction while exposing the same configuration parameters.
Key Source Files
The complete rotation mechanism spans four primary files in the gabime/spdlog repository:
include/spdlog/sinks/rotating_file_sink.h: Declares therotating_file_sinktemplate class and factory helpersinclude/spdlog/sinks/rotating_file_sink-inl.h: Implementsrotate_(),sink_it_(), and size tracking logicinclude/spdlog/details/file_helper.h: Provides thefile_helperclass for low-level file I/O abstractioninclude/spdlog/details/file_helper-inl.h: Contains platform-specific file operations including rename and size queries
Summary
- spdlog file rotation is implemented via the
rotating_file_sinkclass using size-based triggers - The
current_size_variable tracks cumulative bytes written, checked againstmax_size_on every log operation - When thresholds are exceeded,
rotate_()performs a cascading rename of archived files fromNtoN+1 - The system retains only
max_filesarchives, deleting older logs automatically - Factory functions
rotating_logger_mtandrotating_logger_stprovide convenient initialization for multi-threaded and single-threaded contexts
Frequently Asked Questions
What happens if max_files is set to 0 in spdlog?
When max_files is 0, spdlog disables rotation entirely. The rotate_() function will not perform any file renaming operations, allowing the log file to grow without bounds until the process terminates or the filesystem fills.
How does spdlog handle file renaming conflicts during rotation?
The rotate_() method first checks if the target filename exists using path_exists(), then deletes it via rename_file_() before performing the rename. On Windows systems where file locks may cause transient failures, the implementation includes retry logic with brief sleep intervals to handle high-frequency rotation scenarios.
What is the difference between rotating_logger_mt and rotating_logger_st?
rotating_logger_mt creates a multi-threaded logger where the sink uses mutex locking to prevent concurrent rotation operations, suitable for applications logging from multiple threads. rotating_logger_st omits locking overhead for single-threaded applications, providing better performance when thread safety is not required.
Can spdlog rotate logs based on time instead of file size?
The rotating_file_sink specifically implements size-based rotation as described. For time-based rotation (daily, hourly), spdlog provides a separate daily_file_sink class in include/spdlog/sinks/daily_file_sink.h that triggers rotation at specified time intervals rather than file size thresholds.
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 →