spdlog File Sinks: Differences Between Rotating, Daily, and Hourly

spdlog provides three primary file sinks—rotating_file_sink (size-driven), daily_file_sink (calendar-driven), and hourly_file_sink (time-slot-driven)—that manage log file lifecycle by either enforcing disk space limits or triggering rotation at specific chronological boundaries.

The gabime/spdlog repository offers these distinct sink implementations to address different operational requirements for log retention and file organization. While rotating_file_sink caps individual file size to prevent unbounded growth, daily_file_sink and hourly_file_sink use absolute clock time to partition logs into predictable temporal segments.

Time-Based Rotation: Daily and Hourly Sinks

Time-driven sinks create new log files at fixed intervals, embedding timestamps directly into filenames for easy chronological identification.

Daily File Sink (daily_file_sink)

The daily sink creates a new log file at a configurable hour and minute each day (for example, 02:30 AM). In include/spdlog/sinks/daily_file_sink.h, the implementation uses daily_filename_calculator (lines 30-38) to generate filenames that incorporate the current date, producing outputs like app_2024-09-15.log.

Rotation timing is computed by next_rotation_tp_() (lines 51-62), which calculates the absolute time point for the next file creation. The constructor signature is:

daily_file_sink(base_filename, hour, minute, truncate = false, max_files = 0, ...)

Retention is handled by the optional max_files parameter. When set, the delete_old_() method (lines 64-82) automatically removes daily files older than the specified count, ensuring only the most recent N days remain on disk.

Hourly File Sink (hourly_file_sink)

The hourly sink operates as a higher-frequency variant of the daily implementation, triggering rotation every 60 minutes at the top of the hour. Found in include/spdlog/sinks/hourly_file_sink.h, this sink uses hourly_filename_calculator to embed hour-level timestamps into filenames. It shares the same retention policy and thread-safety characteristics as the daily sink, making it suitable for high-volume logging scenarios where a single day’s logs would otherwise grow too large for practical analysis.

Size-Based Rotation: Rotating File Sink (rotating_file_sink)

Unlike time-driven alternatives, rotating_file_sink monitors file size to determine when to create a new file. When the current log exceeds the configured max_size limit (for example, 10 MiB), the sink triggers a rotation.

The implementation in include/spdlog/sinks/rotating_file_sink-inl.h defines calc_filename (lines 54-64) to append numeric indices, generating sequences like app.log, app.1.log, app.2.log. The core rotation logic resides in rotate_() (lines 38-66), which renames existing files and removes the oldest when max_files is exceeded.

Size checking occurs on every write via sink_it_() (lines 13-22), which projects the new file size and calls rotate_() when the limit would be surpassed. The constructor is defined at lines 25-32:

rotating_file_sink(base_filename, max_size, max_files, rotate_on_open = false, ...)

Technical Comparison of Sink Behaviors

Aspect Daily File Sink Hourly File Sink Rotating File Sink
Rotation Trigger Specific time daily (HH:MM) Every 60 minutes (top of hour) File size exceeds max_size
Filename Pattern Date-embedded (app_YYYY-MM-DD.log) Hour-timestamp embedded Indexed suffix (app.N.log)
Retention Method delete_old_() removes oldest dated files Same as daily rotate_() shifts indices and deletes overflow
Configuration hour, minute, max_files max_files only max_size, max_files, rotate_on_open
Source Files daily_file_sink.h (lines 30-82) hourly_file_sink.h rotating_file_sink.h, rotating_file_sink-inl.h (lines 13-66)

Thread Safety and Sink Variants

All three sink types are available in multithreaded (*_mt) and single-threaded (*_st) variants, derived from base_sink<Mutex> as shown by the using declarations at the bottom of each header file. The multithreaded versions provide internal locking for concurrent access, while single-threaded variants offer lower overhead when logging from one thread.

Practical Configuration Examples

Create a daily logger that rotates at 02:30 AM and keeps the last 7 days:

#include <spdlog/sinks/daily_file_sink.h>

auto logger = spdlog::daily_logger_mt(
    "daily_logger",               // logger name
    "logs/myapp.log",             // base filename
    2, 30,                        // rotate at 02:30
    false,                        // do not truncate existing file
    7);                           // keep 7 most recent daily files
logger->info("Application started");

Create a size-based rotating logger that caps files at 5 MiB and retains 5 backups:

#include <spdlog/sinks/rotating_file_sink.h>

auto logger = spdlog::rotating_logger_mt(
    "rot_logger",                 // logger name
    "logs/myapp.log",             // base filename
    5 * 1024 * 1024,              // 5 MiB max size
    5);                           // keep 5 rotated files
logger->info("Application started");

Using the single-threaded daily variant for low-contention scenarios:

auto logger = spdlog::daily_logger_st(
    "daily_st", "logs/st_app.log", 0, 0, false, 3);

Summary

  • rotating_file_sink manages disk space by enforcing a maximum file size and maintaining a fixed number of indexed backups, suitable for environments with strict storage quotas.
  • daily_file_sink partitions logs by calendar date, creating new files at a specific time daily and optionally cleaning up old files via the max_files parameter.
  • hourly_file_sink provides the same retention benefits as the daily sink but rotates every hour, ideal for applications generating high log volumes that require granular time-based separation.
  • All sinks support optional file count limits and offer both multithreaded and single-threaded compilation modes through template specializations of base_sink.

Frequently Asked Questions

When should I use the hourly sink instead of the daily sink?

Use hourly_file_sink when a single day’s log output exceeds manageable file sizes or when operational analysis requires isolating events to specific hours. Because it generates a new file every 60 minutes using the same retention logic as the daily variant, it prevents individual log files from growing too large while maintaining chronological organization.

Can I combine size-based and time-based rotation in one sink?

spdlog does not provide a built-in sink that combines both triggers. You must choose either rotating_file_sink for size-driven rotation or daily_file_sink/hourly_file_sink for time-driven rotation. If both constraints are required, you would need to implement a custom sink inheriting from base_sink or manage log rotation externally via system tools.

What happens when the max_files limit is reached?

The oldest file is automatically deleted to maintain the specified count. In rotating_file_sink, the rotate_() method shifts indices and removes the file exceeding the limit. In daily_file_sink, the delete_old_() method scans for dated files older than the retention window and removes them from the filesystem.

Are these file sinks thread-safe?

Yes, the multithreaded variants (*_mt) are thread-safe. They inherit from base_sink<std::mutex> and use internal locking to protect concurrent writes. For single-threaded applications, use the *_st variants (inheriting from base_sink<spdlog::details::null_mutex>) to eliminate locking overhead.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →