How to Use File Sinks with spdlog: A Complete C++ Logging Guide
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, the sink opens the file once during construction and appends messages until destruction.
#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, the constructor accepts the filename, maximum file size in bytes, and maximum number of files to retain.
#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. 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.
#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. This is useful for high-throughput applications generating large log volumes that require granular organization.
#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:
// 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:
#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,rotating_file_sink.h,daily_file_sink.h, andhourly_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 likespdlog::basic_logger_mt()for automatic registration. - Event handlers allow monitoring file open/close operations by passing a
spdlog::file_event_handlersstruct 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.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →