# How to Configure spdlog Sinks: A Complete Guide to Console, File, and Async Logging

> Learn how to configure spdlog sinks with this comprehensive guide. Master console, file, and async logging by setting up shared pointers for `spdlog` instances.

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

---

**spdlog sinks are configured by creating `std::shared_ptr` instances of specific sink types (such as `stdout_color_sink_mt` or `basic_file_sink_mt`), setting their individual patterns and log levels, and passing them to an `spdlog::logger` constructor or using factory helpers like `spdlog::stdout_color_mt()`.**

In the `gabime/spdlog` repository, **sinks** are the fundamental output drivers that handle where log messages are written. Understanding how to configure spdlog sinks allows you to route logs to multiple destinations simultaneously, each with independent formatting and verbosity settings. This guide covers the exact implementation details found in the spdlog source code, including the specific headers and factory functions you need to build flexible logging pipelines.

## Understanding spdlog Sinks and Loggers

A **sink** in spdlog is any class derived from `spdlog::sinks::sink` (defined in [`include/spdlog/sinks/sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/sink.h)) that implements the actual write logic. The `spdlog::logger` class (in [`include/spdlog/logger.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/logger.h)) holds a collection of sink pointers via `std::vector<spdlog::sink_ptr>` and forwards formatted log records to each attached sink.

Key architectural points:
- Sinks are shared resources managed via `std::shared_ptr<spdlog::sinks::sink>`
- Multiple loggers can share the same sink instance
- Each sink maintains its own pattern formatter and log level filter
- Factory functions in [`include/spdlog/spdlog.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h) provide convenient one-liner setup for common configurations

## Step-by-Step Sink Configuration

### Choose a Sink Type

Available sink implementations are located under `include/spdlog/sinks/`:

- **`stdout_color_sink`** – Colored console output (Windows and POSIX). Header: [`include/spdlog/sinks/stdout_color_sinks.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/stdout_color_sinks.h)
- **`basic_file_sink`** – Simple file appending. Header: [`include/spdlog/sinks/basic_file_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/basic_file_sink.h)
- **`rotating_file_sink`** – Size-based rotation (creates numbered backups). Header: [`include/spdlog/sinks/rotating_file_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/rotating_file_sink.h)
- **`daily_file_sink`** – Time-based rotation (new file each day). Header: [`include/spdlog/sinks/daily_file_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/daily_file_sink.h)
- **`syslog_sink`** / **`systemd_sink`** – Unix syslog or systemd journal integration

### Create and Configure Sink Instances

Instantiate sinks using `std::make_shared` with the thread-safe `_mt` (multi-threaded) variants:

```cpp
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/app.log", true);

```

Configure individual sink behavior using `set_pattern()` and `set_level()`:

```cpp
console_sink->set_pattern("%^[%T] %n: %v%$");  // Colored output
console_sink->set_level(spdlog::level::info);

file_sink->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v");
file_sink->set_level(spdlog::level::debug);

```

### Assemble the Logger

Create a logger with multiple sinks by passing a vector of `spdlog::sink_ptr`:

```cpp
std::vector<spdlog::sink_ptr> sinks {console_sink, file_sink};
auto logger = std::make_shared<spdlog::logger>("multi_sink", 
                                               sinks.begin(), 
                                               sinks.end());
spdlog::register_logger(logger);

```

Alternatively, use convenience factories for single-sink loggers:

```cpp
auto logger = spdlog::stdout_color_mt("console_logger");
auto file_logger = spdlog::basic_logger_mt("file_logger", "logs/output.log");

```

## Practical Implementation Examples

### Console and File Sinks with Different Log Levels

This example from [`include/spdlog/sinks/stdout_color_sinks.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/stdout_color_sinks.h) and [`include/spdlog/sinks/basic_file_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/basic_file_sink.h) demonstrates routing `debug` messages to file while restricting console output to `info` and above:

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

int main() {
    // Create sinks
    auto console = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    auto file = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/app.log", true);

    // Configure individually
    console->set_pattern("%^[%T] %n: %v%$");
    console->set_level(spdlog::level::info);
    
    file->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v");
    file->set_level(spdlog::level::debug);

    // Assemble multi-sink logger
    std::vector<spdlog::sink_ptr> sinks{console, file};
    auto logger = std::make_shared<spdlog::logger>("app", sinks.begin(), sinks.end());
    spdlog::register_logger(logger);

    // Usage: debug only appears in file
    logger->info("Application started");
    logger->debug("Debug details hidden from console");
}

```

### Rotating File Sink Configuration

The `rotating_file_sink` (in [`include/spdlog/sinks/rotating_file_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/rotating_file_sink.h)) rotates files when they reach a specified size:

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

int main() {
    // Rotate at 5 MB, keep 3 archived files
    auto rotating = spdlog::rotating_logger_mt("rotating_logger",
                                               "logs/rotating.log",
                                               5 * 1024 * 1024,  // 5 MB
                                               3);
    rotating->info("This creates rotating.log, rotating.1.log, etc.");
}

```

### Async Logger with Multiple Sinks

For high-performance logging, combine sinks with the async thread pool (defined in [`include/spdlog/async.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/async.h)):

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

int main() {
    // Initialize thread pool: queue size 8192, 1 worker thread
    spdlog::init_thread_pool(8192, 1);

    // Create sinks
    auto console = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    auto daily = std::make_shared<spdlog::sinks::daily_file_sink_mt>("logs/daily.log", 0, 0);

    // Build async logger with overflow policy
    std::vector<spdlog::sink_ptr> sinks{console, daily};
    auto async_logger = std::make_shared<spdlog::async_logger>("async",
                                                               sinks.begin(), sinks.end(),
                                                               spdlog::thread_pool(),
                                                               spdlog::async_overflow_policy::block);
    spdlog::register_logger(async_logger);
    
    async_logger->info("Non-blocking async logging initialized");
}

```

## Summary

- **Sink Creation**: Instantiate concrete sink classes from `include/spdlog/sinks/` using `std::make_shared` with the `_mt` suffix for thread safety.
- **Individual Configuration**: Each sink supports independent `set_pattern()` and `set_level()` calls to control formatting and filtering.
- **Logger Assembly**: Pass sink pointers to `spdlog::logger` constructors or use factory helpers in [`include/spdlog/spdlog.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h) for single-sink setups.
- **Async Support**: Use `spdlog::init_thread_pool()` and `spdlog::async_logger` (from [`include/spdlog/async.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/async.h)) when combining multiple sinks with asynchronous logging.
- **Thread Safety**: All `_mt` sink variants are thread-safe, allowing shared use across multiple loggers and threads.

## Frequently Asked Questions

### How do I register a custom logger with multiple sinks?

After creating your `std::shared_ptr<spdlog::logger>` with the desired sinks, call `spdlog::register_logger(logger)` to make it accessible via `spdlog::get("logger_name")` throughout your application. This is implemented in [`include/spdlog/spdlog.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h) and manages the global logger registry.

### Can I share the same sink between multiple loggers?

Yes. Since sinks are held by `std::shared_ptr<spdlog::sinks::sink>`, you can pass the same sink instance to multiple `spdlog::logger` constructors. This is useful when you want multiple log categories (e.g., "network" and "database") writing to the same file or console output with identical formatting.

### What is the difference between `basic_file_sink` and `rotating_file_sink`?

`basic_file_sink_mt` (in [`include/spdlog/sinks/basic_file_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/basic_file_sink.h)) provides simple file appending without size limits. `rotating_file_sink_mt` (in [`include/spdlog/sinks/rotating_file_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/rotating_file_sink.h)) automatically archives the current log file when it exceeds a specified size, maintaining a fixed number of backups (e.g., `app.log`, `app.1.log`, `app.2.log`).

### How do I configure spdlog sinks to use different log levels for different outputs?

Create separate sink instances and call `set_level()` on each before attaching them to the logger. For example, set `console_sink->set_level(spdlog::level::warn)` and `file_sink->set_level(spdlog::level::debug)`. The logger will forward messages to both sinks, but each sink filters independently according to its configured level threshold.