How to Create Rotating File Sinks in spdlog: A Complete Guide

To create rotating file sinks in spdlog, use the rotating_file_sink_mt or rotating_file_sink_st templates, or the convenience factory functions spdlog::rotating_logger_mt() and spdlog::rotating_logger_st(), which automatically roll over log files when they reach a specified size limit.

The gabime/spdlog library provides a high-performance, header-only C++ logging framework with built-in support for log rotation. When you create rotating file sinks in spdlog, the library handles automatic file rollover, ensuring that log archives remain manageable while preserving historical data according to configurable retention policies.

How Rotating File Sinks Work in spdlog

The rotating file sink implementation resides in include/spdlog/sinks/rotating_file_sink.h with inline definitions in include/spdlog/sinks/rotating_file_sink-inl.h. The class template spdlog::sinks::rotating_file_sink<Mutex> inherits from base_sink<Mutex> and encapsulates a details::file_helper for low-level file operations.

When a log message arrives, the sink_it_ method formats the message and estimates the resulting file size. If the size would exceed the configured max_size_, the sink flushes the current file and invokes rotate_() before writing the new entry. The rotation algorithm iterates backwards from max_files_ down to 1, renaming each existing file to the next index (e.g., log.1.txt becomes log.2.txt), then opens a fresh file for continued logging.

Creating a Rotating File Logger

Using the Factory Helper (Multi-Threaded)

The simplest way to create a rotating logger is through the spdlog::rotating_logger_mt() factory function defined in include/spdlog/sinks/rotating_file_sink.h.

#include <spdlog/spdlog.h>
#include <spdlog/sinks/rotating_file_sink.h>

int main() {
    // Create a logger that rotates after 5 MiB, keeping up to 3 files
    auto logger = spdlog::rotating_logger_mt(
        "my_logger",               // logger name
        "logs/app.log",            // base filename
        5 * 1024 * 1024,           // 5 MiB max size per file
        3);                        // keep 3 rotated files

    logger->info("Application started");
}

This function internally instantiates rotating_file_sink_mt (the mutex-synchronized variant) through synchronous_factory::create.

Explicit Sink Construction (Single-Threaded)

For single-threaded applications where synchronization overhead is unnecessary, use rotating_file_sink_st with a null_mutex:

#include <spdlog/spdlog.h>
#include <spdlog/sinks/rotating_file_sink.h>

int main() {
    using sink_t = spdlog::sinks::rotating_file_sink_st;
    auto sink = std::make_shared<sink_t>(
        "logs/server.log",          // base filename
        10 * 1024 * 1024,           // 10 MiB max size
        5,                          // keep 5 rotated files
        false);                     // do not rotate on open

    auto logger = std::make_shared<spdlog::logger>("server", sink);
    spdlog::register_logger(logger);

    logger->warn("Server listening on port {}", 8080);
}

Understanding the Rotation Algorithm

The rotation logic in include/spdlog/sinks/rotating_file_sink-inl.h follows a specific naming convention and renaming strategy:

  • Filename calculation: The calc_filename() method generates names like log.txt, log.1.txt, through log.N.txt by splitting the base filename and inserting rotation indices.
  • Validation: The constructor enforces that max_size must be greater than 0 and max_files cannot exceed 200,000 (MaxFiles constant).
  • Atomic renaming: The rotate_() method closes the current file, then iterates from max_files_ down to 1, renaming each existing file to the next higher index using rename_file_(), which removes existing targets before invoking the OS rename primitive.

Thread Safety Considerations

spdlog provides two type aliases for different concurrency requirements:

  • rotating_file_sink_mt: Uses std::mutex for thread-safe access from multiple threads.
  • rotating_file_sink_st: Uses spdlog::details::null_mutex (no-op) for single-threaded scenarios, eliminating synchronization overhead.

Choose the appropriate variant based on your application's threading model to optimize performance.

Manual Rotation and Advanced Usage

You can force immediate rotation programmatically using the rotate_now() method:

logger->flush();          // ensure all data is written
auto sink = std::static_pointer_cast<spdlog::sinks::rotating_file_sink_mt>(logger->sinks()[0]);
sink->rotate_now();       // immediate rotation

This acquires the sink's mutex and invokes the internal rotate_() logic directly, useful for log rotation triggered by external signals or time-based policies.

Summary

  • Create rotating file sinks in spdlog using rotating_logger_mt()/rotating_logger_st() factory functions or direct template instantiation of rotating_file_sink_mt/st.
  • The implementation resides in include/spdlog/sinks/rotating_file_sink.h with rotation logic in the -inl.h header.
  • Configure maximum file size and retention count (up to 200,000 files) via constructor parameters.
  • Select rotating_file_sink_mt for multi-threaded applications or rotating_file_sink_st for single-threaded performance.
  • Use rotate_now() to trigger manual rotation when needed.

Frequently Asked Questions

What is the maximum number of rotated files supported?

According to the source code in include/spdlog/sinks/rotating_file_sink-inl.h, spdlog enforces a hard limit of 200,000 rotated files (MaxFiles constant). The constructor validates that the max_files parameter is greater than 0 and does not exceed this upper bound.

How does spdlog handle file naming during rotation?

The calc_filename() function in include/spdlog/sinks/rotating_file_sink-inl.h splits the base filename into stem and extension, then inserts the rotation index between them. This produces sequences like app.log, app.1.log, app.2.log, etc., ensuring chronological ordering by index.

Can I force a log rotation manually?

Yes. Obtain a pointer to the sink (casting from logger->sinks()), then call rotate_now(). This method locks the mutex and executes the same rotate_() algorithm used during automatic size-based rotation, closing the current file and cycling archived files immediately.

What is the difference between rotating_file_sink_mt and rotating_file_sink_st?

rotating_file_sink_mt instantiates the template with std::mutex, providing thread-safe logging for concurrent access. rotating_file_sink_st uses null_mutex, which performs no locking and offers better performance for single-threaded contexts where synchronization is unnecessary.

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 →