# How to Use File Sinks with spdlog: A Complete C++ Logging Guide

> Learn to use file sinks with spdlog in C++ to write log messages to disk. This guide covers instantiation, logger attachment, and registration for efficient disk logging.

- Repository: [Gabi Melman/spdlog](https://github.com/gabime/spdlog)
- Tags: how-to-guide
- Published: 2026-07-27

---

**To use file sinks with spdlog, instantiate a shared pointer to a sink class template (such as `spdlog::sinks::basic_file_sink_mt`), attach it to a `spdlog::logger`, and register the logger with `spdlog::register_logger()` to write log messages to disk.**

The gabime/spdlog library provides a robust family of file sinks that persist log output to disk with support for size-based rotation, time-based archiving, and event callbacks. All file sinks derive from `spdlog::sinks::base_sink<std::mutex>` (or the lock-free variant) and reside in the `spdlog::sinks` namespace, offering both multithreaded (`_mt`) and single-threaded (`_st`) variants for different concurrency requirements.

## Types of File Sinks in spdlog

spdlog implements four primary file sink types, each designed for specific log retention and organization strategies.

### Basic File Sink

The **basic file sink** writes all log output to a single file. This is the simplest option for applications that do not require log rotation. According to the source in [`include/spdlog/sinks/basic_file_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/basic_file_sink.h), the sink opens the file once during construction and appends messages until destruction.

```cpp
#include <spdlog/spdlog.h>
#include <spdlog/sinks/basic_file_sink.h>

int main() {
    // Create a multithreaded basic file sink
    auto sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/basic.log");
    
    // Attach to a logger and register globally
    auto logger = std::make_shared<spdlog::logger>("basic_logger", sink);
    spdlog::register_logger(logger);
    
    logger->info("Application started");
    logger->error("An error occurred");
}

```

### Rotating File Sink

The **rotating file sink** limits individual file sizes and maintains a fixed number of backup files. When the current file reaches the specified maximum size, spdlog closes it and creates a new one, preserving older files with indexed suffixes (e.g., `log.1`, `log.2`). As implemented in [`include/spdlog/sinks/rotating_file_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/rotating_file_sink.h), the constructor accepts the filename, maximum file size in bytes, and maximum number of files to retain.

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

int main() {
    // Rotate at 5 MiB, keep 3 archived files
    auto sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
        "logs/rotating.log", 5 * 1024 * 1024, 3);
    
    auto logger = std::make_shared<spdlog::logger>("rotating_logger", sink);
    spdlog::register_logger(logger);
    
    for (int i = 0; i < 10000; ++i) {
        logger->info("Log entry number {}", i);
    }
}

```

### Daily File Sink

The **daily file sink** creates a new log file at a specified time each day, defined in [`include/spdlog/sinks/daily_file_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/daily_file_sink.h). This sink accepts hour and minute parameters to determine when rotation occurs, making it ideal for applications requiring daily log separation for compliance or analysis.

```cpp
#include <spdlog/spdlog.h>
#include <spdlog/sinks/daily_file_sink.h>

int main() {
    // Rotate daily at 02:30 local time
    auto sink = std::make_shared<spdlog::sinks::daily_file_sink_mt>(
        "logs/daily.log", 2, 30);
    
    auto logger = std::make_shared<spdlog::logger>("daily_logger", sink);
    spdlog::register_logger(logger);
    
    logger->info("This message appears in today's log file");
}

```

### Hourly File Sink

The **hourly file sink** functions similarly to the daily variant but rotates files every hour, as defined in [`include/spdlog/sinks/hourly_file_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/hourly_file_sink.h). This is useful for high-throughput applications generating large log volumes that require granular organization.

```cpp
#include <spdlog/spdlog.h>
#include <spdlog/sinks/hourly_file_sink.h>

int main() {
    // Create new file at the beginning of each hour
    auto sink = std::make_shared<spdlog::sinks::hourly_file_sink_mt>("logs/hourly.log");
    
    auto logger = std::make_shared<spdlog::logger>("hourly_logger", sink);
    spdlog::register_logger(logger);
    
    logger->info("Current hour's log message");
}

```

## Creating Loggers with File Sinks

You can attach file sinks to loggers using two primary approaches: manual construction for full control, or factory helpers for convenience.

### Manual Construction

Manually construct the sink and logger when you need to configure multiple sinks or custom settings. The `spdlog::logger` constructor accepts a name and one or more sinks, after which you must register the logger using `spdlog::register_logger()` to access it globally via `spdlog::get()`.

### Factory Helper Functions

For single-sink loggers, use the factory helpers `spdlog::basic_logger_mt`, `spdlog::rotating_logger_mt`, `spdlog::daily_logger_mt`, and `spdlog::hourly_logger_mt`. These functions instantiate the appropriate sink and register the logger in the global registry in a single call:

```cpp
// Equivalent to the manual rotating sink example above
auto logger = spdlog::rotating_logger_mt("rotating_logger", 
    "logs/rotating.log", 5 * 1024 * 1024, 3);
logger->info("Created via factory helper");

```

## Monitoring File Operations with Event Handlers

All file sinks support **file event handlers** via the `spdlog::file_event_handlers` struct, allowing you to register callbacks when files open or close. This feature is useful for metrics collection, resource tracking, or triggering external processes when logs rotate.

The handlers struct provides `on_open` and `on_close` callbacks that receive the filename as a parameter:

```cpp
#include <spdlog/spdlog.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <iostream>

int main() {
    spdlog::file_event_handlers handlers;
    handlers.on_open = [](const spdlog::filename_t& fname) {
        std::cout << "Log file opened: " << fname << std::endl;
    };
    handlers.on_close = [](const spdlog::filename_t& fname) {
        std::cout << "Log file closed: " << fname << std::endl;
    };

    // Constructor signature: (filename, truncate, handlers)
    auto sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(
        "logs/monitored.log", true, handlers);

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

    logger->info("File event handlers are active");
}

```

## Summary

- **File sinks** in spdlog write log messages to disk and are defined in headers such as [`basic_file_sink.h`](https://github.com/gabime/spdlog/blob/main/basic_file_sink.h), [`rotating_file_sink.h`](https://github.com/gabime/spdlog/blob/main/rotating_file_sink.h), [`daily_file_sink.h`](https://github.com/gabime/spdlog/blob/main/daily_file_sink.h), and [`hourly_file_sink.h`](https://github.com/gabime/spdlog/blob/main/hourly_file_sink.h).
- **Sink variants** use the `_mt` (multithreaded) or `_st` (single-threaded) suffix to control thread-safety via mutex locking.
- **Rotation strategies** include size-based limits (`rotating_file_sink`), daily time points (`daily_file_sink`), and hourly intervals (`hourly_file_sink`).
- **Registration** requires calling `spdlog::register_logger()` after creating a logger manually, or using factory helpers like `spdlog::basic_logger_mt()` for automatic registration.
- **Event handlers** allow monitoring file open/close operations by passing a `spdlog::file_event_handlers` struct to the sink constructor.

## Frequently Asked Questions

### What is the difference between `_mt` and `_st` file sinks?

The `_mt` suffix creates a multithreaded sink that inherits from `spdlog::sinks::base_sink<std::mutex>`, protecting file operations with a mutex for thread safety. The `_st` variant uses `spdlog::sinks::base_sink<spdlog::details::null_mutex>` for single-threaded contexts, offering better performance when you do not need concurrent access.

### How do I rotate log files when they reach a specific size?

Use `spdlog::sinks::rotating_file_sink_mt` (or `_st`) and specify the maximum file size in bytes and the maximum number of archived files. For example, `rotating_file_sink_mt("app.log", 10485760, 5)` rotates when the file exceeds 10 MB and keeps 5 backups.

### Can I attach multiple file sinks to a single logger?

Yes. The `spdlog::logger` constructor accepts a vector of sink pointers or an initializer list, allowing you to simultaneously write to a basic file, a rotating file, and the console. Each sink processes the same log message independently.

### How do I detect when spdlog opens or closes a log file?

Pass a `spdlog::file_event_handlers` structure to the sink constructor with `on_open` and `on_close` lambda functions or function objects. These callbacks execute synchronously during file operations, receiving the filename as their parameter.