# Difference Between daily_file_sink and rotating_file_sink in spdlog: Complete Guide

> Understand the difference between daily_file_sink and rotating_file_sink in spdlog. Learn when to use daily sinks for time-based rotation and rotating sinks for size-based logging.

- Repository: [Gabi Melman/spdlog](https://github.com/gabime/spdlog)
- Tags: deep-dive
- Published: 2026-07-14

---

**The `daily_file_sink` rotates log files based on calendar time (creating a new file each day at a specific hour), while `rotating_file_sink` rotates based on file size (creating a new file when the current one exceeds a configurable limit).**

Both sinks are part of the [gabime/spdlog](https://github.com/gabime/spdlog) library and provide automatic log file management, but they serve different operational needs. Understanding the difference between `daily_file_sink` and `rotating_file_sink` in spdlog ensures you choose the right rotation strategy for your logging requirements.

## Rotation Trigger: Time vs. Size

The fundamental distinction lies in what triggers the creation of a new log file.

**`daily_file_sink`** uses absolute clock time. According to the implementation in [`include/spdlog/sinks/daily_file_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/daily_file_sink.h), the sink calculates the next rotation point using `next_rotation_tp_()` (lines 51–62). When the current time passes the configured hour and minute (e.g., 02:30 AM), it closes the current file and opens a new one with the current date appended.

**`rotating_file_sink`** monitors file size. In [`include/spdlog/sinks/rotating_file_sink-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/rotating_file_sink-inl.h), every call to `sink_it_()` checks if writing the next log message would exceed `max_size_` (lines 13–22). When the threshold is reached, the sink triggers `rotate_()` to close the current file and create a new one.

## Filename Generation and Format

Each sink uses a distinct naming convention that reflects its rotation strategy.

**Daily files** embed the date in the filename. The `daily_filename_calculator` (or `daily_filename_format_calculator`) in [`daily_file_sink.h`](https://github.com/gabime/spdlog/blob/main/daily_file_sink.h) (lines 30–38) generates names like `app_2024-09-15.log`. This makes it trivial to locate logs for a specific calendar date.

**Rotated files** use numeric indices. The `calc_filename()` method in [`rotating_file_sink-inl.h`](https://github.com/gabime/spdlog/blob/main/rotating_file_sink-inl.h) (lines 54–64) appends an index to the base name, producing sequences like `app.log`, `app.1.log`, `app.2.log`. When rotation occurs, existing files are renamed incrementally (e.g., `app.1.log` becomes `app.2.log`).

## Retention and Cleanup Policies

Both sinks support automatic cleanup through an optional `max_files` parameter, but the semantics differ based on the rotation trigger.

**Daily sink retention** keeps the most recent *N* daily files. The `delete_old_()` method in [`daily_file_sink.h`](https://github.com/gabime/spdlog/blob/main/daily_file_sink.h) (lines 64–82) scans the log directory and removes files older than the configured retention count. This is ideal for compliance policies requiring "last 30 days of logs."

**Rotating sink retention** maintains a fixed number of backup files. The `rotate_()` method in [`rotating_file_sink-inl.h`](https://github.com/gabime/spdlog/blob/main/rotating_file_sink-inl.h) (lines 38–66) ensures that if `max_files` is 5, you will have `app.log` (current) plus `app.1.log` through `app.4.log`. If a new rotation occurs, the oldest file is deleted before renaming the others.

## Thread Safety Variants

Both sinks inherit from `base_sink<Mutex>` and provide thread-safe and single-threaded variants. You can instantiate either:

- **`daily_logger_mt`** / **`rotating_logger_mt`**: Multithreaded versions using mutex locking (suitable for concurrent logging from multiple threads).
- **`daily_logger_st`** / **`rotating_logger_st`**: Single-threaded versions without locking overhead (optimal when only one thread writes to the logger).

## Constructor Signatures and Configuration

Understanding the parameter differences helps when configuring your logger:

**Daily File Sink:**

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

```

- `hour` and `minute`: Specify the rotation time (24-hour format).
- `truncate`: If true, overwrites existing files on startup.
- `max_files`: Number of daily files to retain (0 = unlimited).

See the constructor implementation in [`daily_file_sink.h`](https://github.com/gabime/spdlog/blob/main/daily_file_sink.h) (lines 71–78).

**Rotating File Sink:**

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

```

- `max_size`: Maximum file size in bytes before rotation.
- `max_files`: Number of rotated files to keep (not counting the current file).
- `rotate_on_open`: If true, rotates immediately when opening the file.

See the constructor in [`rotating_file_sink-inl.h`](https://github.com/gabime/spdlog/blob/main/rotating_file_sink-inl.h) (lines 25–32).

## Practical Code Examples

### Daily Rotation at 02:30 AM with 7-Day Retention

```cpp
#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");

```

### Size-Based Rotation (5 MiB max, 5 backups)

```cpp
#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");

```

### Single-Threaded Variants

For low-contention scenarios where thread safety is unnecessary, use the `_st` variants to reduce lock overhead:

```cpp
// Daily single-threaded
auto daily_st = spdlog::daily_logger_st(
    "daily_st", "logs/st_app.log", 0, 0, false, 3);

// Rotating single-threaded  
auto rot_st = spdlog::rotating_logger_st(
    "rot_st", "logs/st_app.log", 10 * 1024 * 1024, 10);

```

## When to Use Which Sink

Choose **`daily_file_sink`** when:
- You need to analyze logs by calendar date (e.g., "show me yesterday's errors").
- Compliance requirements mandate daily log separation.
- Log volume is predictable and you prefer time-based archiving.

Choose **`rotating_file_sink`** when:
- Disk space is constrained and you must enforce a hard size limit per file.
- You need to ensure individual log files remain small enough to open in text editors or email.
- You want a predictable number of backup files regardless of how much data is logged.

## Summary

- **`daily_file_sink`** rotates at a specific time each day (configurable hour/minute) and embeds dates in filenames.
- **`rotating_file_sink`** rotates when files exceed a size limit (bytes) and uses numeric indices for backups.
- Both support `max_files` retention, but `daily_file_sink` deletes old files by date while `rotating_file_sink` manages a fixed-size rolling window.
- Both offer multithreaded (`*_mt`) and single-threaded (`*_st`) variants implemented in [`daily_file_sink.h`](https://github.com/gabime/spdlog/blob/main/daily_file_sink.h) and [`rotating_file_sink-inl.h`](https://github.com/gabime/spdlog/blob/main/rotating_file_sink-inl.h).

## Frequently Asked Questions

### Can I use both daily and rotating file sinks simultaneously?

Yes. You can attach multiple sinks to a single logger or create separate loggers. For example, you might use `daily_file_sink` for audit trails and `rotating_file_sink` for verbose debug output. Combine them using `spdlog::sinks_init_list` or the `spdlog::logger` constructor that accepts a vector of sinks.

### Which sink has better performance?

Both sinks inherit from `base_sink<Mutex>` and have similar overhead for the actual logging operation. However, `rotating_file_sink` checks file size on every log message (in `sink_it_()`), while `daily_file_sink` only checks the current time against the next rotation timestamp. For extremely high-throughput logging (millions of messages per second), `daily_file_sink` may have marginally lower overhead since it avoids size calculations.

### How do I configure the exact rotation time for daily files?

Pass the hour (0–23) and minute (0–59) to the constructor or factory function. For example, to rotate at midnight, use `0, 0`. To rotate at 6:45 PM, use `18, 45`. The sink uses the local system time by default. If the application is not running at the scheduled rotation time, it will rotate immediately upon the next log message once the time has passed.

### What happens when the maximum number of files is reached?

When `max_files` is exceeded, both sinks automatically delete the oldest file. For `rotating_file_sink`, this happens during the `rotate_()` operation where the oldest indexed file is removed before renaming others. For `daily_file_sink`, the `delete_old_()` method scans the directory and removes files with older dates once the count exceeds `max_files`. If `max_files` is 0 (default), no automatic deletion occurs and files accumulate indefinitely.