spdlog rotating_file_sink vs daily_file_sink: Key Implementation Differences
The rotating_file_sink rotates log files when they exceed a maximum size, while daily_file_sink rotates them at a scheduled time each day, with each sink using distinct file naming schemes and cleanup mechanisms.
Both sinks inherit from spdlog::sinks::base_sink<Mutex> in the gabime/spdlog repository and provide automatic file rotation, yet they differ fundamentally in trigger logic, naming conventions, and configuration options. Understanding these distinctions helps you select the right sink for high-volume logging versus time-based archival requirements.
Rotation Trigger Mechanisms
The primary distinction between these sinks lies in what triggers a rotation event.
Size-Based Rotation in rotating_file_sink
In include/spdlog/sinks/rotating_file_sink.h, the rotating_file_sink monitors the current file size through the current_size_ member. When a log message would exceed max_size, the sink invokes the rotate_() method (lines 41-48) to perform the rotation immediately. This approach ensures that no single log file grows beyond a manageable byte threshold, which is critical for storage-constrained environments.
Time-Based Rotation in daily_file_sink
Conversely, daily_file_sink implemented in include/spdlog/sinks/daily_file_sink.h uses std::chrono and log_clock to calculate the next rotation point via next_rotation_tp_(). The rotation check occurs in sink_it_() (lines 106-114), which compares the incoming message's timestamp against rotation_tp_. When the current time passes the scheduled rotation hour and minute, the sink closes the current file and creates a new one for the next day.
File Naming and Organization
Each sink generates filenames using fundamentally different strategies.
Numeric Suffixes vs Date Stamps
The rotating_file_sink uses calc_filename() (lines 29-30) to generate a chain of files with numeric suffixes: log.txt becomes log.1.txt, then log.2.txt, up to max_files. This creates a chronological sequence where higher numbers indicate older files.
The daily_file_sink employs daily_filename_calculator (lines 30-37) to embed the date directly into the filename using the pattern basename_YYYY-MM-DD.ext. An alternative daily_filename_format_calculator variant allows custom date formatting strings, making it easier to identify logs by calendar date without checking file metadata.
Configuration and Constructor Options
The constructor signatures reflect their distinct purposes:
rotating_file_sink (from rotating_file_sink.h lines 24-28):
rotating_file_sink(filename_t base_filename,
size_t max_size,
size_t max_files,
bool rotate_on_open = false, ...)
daily_file_sink (from daily_file_sink.h lines 71-78):
daily_file_sink(filename_t base_filename,
int rotation_hour,
int rotation_minute,
bool truncate = false,
uint16_t max_files = 0, ...)
Key differences include:
- Size-centric vs time-centric: The rotating variant takes
max_sizein bytes, while the daily variant takesrotation_hourandrotation_minute. - Rotate on open: Only
rotating_file_sinksupports therotate_on_openflag, which forces an immediate rotation when the sink is created—useful for "log rollover on application start" scenarios. - Truncation: Only
daily_file_sinkoffers atruncateparameter that, when true, truncates the daily file upon creation viafile_helper_.open(new_filename, truncate_).
File Management and Cleanup Strategies
Both sinks limit the total number of archived files, but implement cleanup differently.
Rename Chain Deletion
In rotating_file_sink-inl.h, the rotate_() method builds a rename chain: log.2.txt moves to log.3.txt, log.1.txt to log.2.txt, and finally the active log.txt becomes log.1.txt. After this cascade, if the file count exceeds max_files, the sink simply deletes the highest-numbered file (the oldest).
Circular Queue Tracking
In daily_file_sink-inl.h, the delete_old_() method (lines 64-82) maintains a filenames_q_—a details::circular_q structure that tracks the most recently created filenames. When rotation occurs and max_files is set, the sink calculates which file is now too old (N days prior) and removes it from disk. This circular queue approach handles date-based cleanup without needing to scan the filesystem or parse filenames.
Practical Usage Examples
Size-based rotation for application logs with high volume:
#include "spdlog/sinks/rotating_file_sink.h"
// Rotate when file exceeds 10MB, keep 5 archived files
auto rot_logger = spdlog::rotating_logger_mt(
"rot_logger", "logs/app.log", 10 * 1024 * 1024, 5);
// Optionally force rotation on startup
rot_logger->info("Application started");
Daily rotation for audit trails and daily archives:
#include "spdlog/sinks/daily_file_sink.h"
// Rotate every day at 02:00, keep last 7 days, truncate on open
auto daily_logger = spdlog::daily_logger_mt(
"daily_logger", "logs/audit.log", 2, 0, false, 7);
daily_logger->info("Daily audit log entry");
Summary
- Trigger:
rotating_file_sinkuses file size (max_size) viarotate_(), whiledaily_file_sinkuses scheduled time viasink_it_()androtation_tp_comparisons. - Naming: Rotating sink uses numeric suffixes (
calc_filename()), daily sink uses date stamps (daily_filename_calculator). - Cleanup: Rotating sink renames files in a chain and deletes the oldest; daily sink uses a
filenames_q_circular queue to track anddelete_old_()expired files. - Options: Rotating sink supports
rotate_on_open; daily sink supportstruncateand custom rotation times. - Source files: Implementation details reside in
include/spdlog/sinks/rotating_file_sink.h(and-inl.h) versusinclude/spdlog/sinks/daily_file_sink.h(and-inl.h).
Frequently Asked Questions
Can I use both rotating and daily file sinks simultaneously in spdlog?
Yes. You can attach multiple sinks to a single logger using spdlog::logger with add_sink(), or create separate loggers for different retention policies. This allows you to maintain size-limited debug logs alongside permanent daily audit trails within the same application.
How does daily_file_sink handle timezone changes or daylight saving time?
The daily_file_sink uses std::chrono and the system's log_clock, which typically represents UTC or system local time depending on your platform. As implemented in next_rotation_tp_(), the calculation uses std::tm structures. If the system clock changes (including DST transitions), the next rotation calculation adjusts accordingly, though you may experience a shorter or longer rotation period during the transition hour.
What happens if the log directory runs out of disk space with rotating_file_sink?
The rotating_file_sink does not explicitly check disk space before writing. When current_size_ approaches max_size, it attempts the rotate_() operation. If the filesystem is full, the rename operations in the rotation chain may fail, and depending on your error handler configuration, the sink may either throw an exception or drop log messages. You should monitor disk space externally or implement a custom rotating_file_sink subclass with pre-write checks.
Is there a performance difference between the two sinks?
Both sinks have minimal overhead, but rotating_file_sink performs a simple size check (current_size_ += msg_size) in sink_it_(), while daily_file_sink must convert timestamps and compare against a rotation_tp_ time point. For extremely high-throughput logging (millions of messages per second), the size check is marginally faster, though the difference is negligible for most applications. The daily sink's filenames_q_ circular queue adds minimal memory overhead regardless of file count.
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 →