How to Replace the Default Logger in spdlog: A Complete Guide
Call spdlog::set_default_logger(my_logger) to swap the internal default logger used by global macros like spdlog::info() and SPDLOG_INFO().
The spdlog library provides a convenient default logger that powers global logging functions, but production applications often need to redirect output to multiple sinks or custom formats. Replacing the default logger in spdlog requires interacting with the internal details::registry class through the public API, allowing you to install a fully configured spdlog::logger instance that handles all subsequent global log calls.
Understanding the Internal Registry
The default logger is held inside the internal registry (details::registry), which maintains a fast-path pointer named default_logger_ used by default_logger_raw(). According to the implementation in include/spdlog/details/registry-inl.h, when you call spdlog::set_default_logger(), the registry performs three critical operations:
- Registers the new logger in the global
loggers_map so it can be retrieved later viaregistry::get(). - Updates the fast-path pointer
default_logger_used by the default API. - Optionally removes the previous default if it was the one being replaced (the old instance is reset when the name matches).
The default logger itself is a regular spdlog::logger instance, so you can create it with any sink configuration before installing it.
How to Replace the Default Logger in spdlog
Step 1: Create a Custom Logger
Build a logger with your desired sinks, pattern, and level. For example, combining a colored console output with a rotating file sink:
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/rotating_file_sink.h>
// Create sinks
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
"logs/app.log", 1048576 * 5, 3); // 5 MiB, 3 files
// Initialize logger with sink list
spdlog::sinks_init_list sink_list = { console_sink, file_sink };
auto my_logger = std::make_shared<spdlog::logger>("my_default",
sink_list.begin(),
sink_list.end());
// Configure formatting
my_logger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v");
my_logger->set_level(spdlog::level::debug);
Step 2: Install the New Default Logger
Pass your configured logger to the registry via the public API declared in include/spdlog/spdlog.h:
spdlog::set_default_logger(my_logger);
// Now all global calls use the new logger
spdlog::info("This goes to both console and rotating file");
SPDLOG_DEBUG("Debug message via macro");
As implemented in include/spdlog/details/registry-inl.h, this call immediately updates the internal pointer so subsequent global macros route to your custom sinks.
Silencing Global Output with a Null Logger
To completely disable output from global logging calls without removing the code, replace the default logger with a null sink:
auto null_sink = std::make_shared<spdlog::sinks::null_sink_mt>();
auto silent_logger = std::make_shared<spdlog::logger>("silent", null_sink);
spdlog::set_default_logger(silent_logger);
All subsequent spdlog::info() and SPDLOG_INFO() calls will execute but discard messages, effectively silencing the default output stream.
Critical Thread Safety Warning
spdlog::set_default_logger is not thread-safe with respect to other threads using spdlog’s global functions. As documented in the header comments in include/spdlog/spdlog.h, you must not call set_default_logger while other threads are actively logging via spdlog::info(), SPDLOG_INFO(), or other global macros. Ensure all logging activity has stopped or synchronize access before swapping the default logger at runtime.
Key Implementation Files
Understanding these source files helps when tracing the behavior of the default logger:
include/spdlog/spdlog.h– Declares the public functionsdefault_logger(),default_logger_raw(), andset_default_logger().include/spdlog/spdlog-inl.h– Implements the inline wrappers that forward to the registry.include/spdlog/details/registry.h– Defines the registry interface, including thedefault_logger()andset_default_logger()methods.include/spdlog/details/registry-inl.h– Contains the actual logic for storing, swapping, and resetting the default logger in theloggers_map.include/spdlog/logger.h– Shows how a logger is constructed and how sinks are attached when building a replacement.
Summary
- The default logger is stored in the internal
details::registryand accessed via a fast-path pointer. - Use
spdlog::set_default_logger(my_logger)to replace it, which updates the registry'sloggers_map anddefault_logger_pointer. - The replacement can be any
spdlog::loggerinstance, including multi-sink configurations or null loggers. - The operation is not thread-safe—do not call
set_default_loggerconcurrently with active logging threads. - Global macros like
spdlog::info()andSPDLOG_INFO()immediately reflect the new logger after the call returns.
Frequently Asked Questions
Can I replace the default logger at runtime?
Yes. You can call spdlog::set_default_logger() at any point during application execution to redirect global logging output. However, as noted in include/spdlog/spdlog.h, you must ensure no other threads are calling global logging functions during the swap.
Is spdlog::set_default_logger thread-safe?
No. The registry does not synchronize access to set_default_logger. While spdlog's logging operations are generally thread-safe, changing the default logger itself requires external synchronization to prevent race conditions with active logging threads.
What happens to the old default logger after replacement?
The previous default logger is removed from the registry's internal loggers_ map if its name matches the default, and its shared pointer is reset. If you maintain other shared_ptr references to the old logger, it will continue to exist independently but will no longer receive global log traffic.
Can I use multiple sinks with the default logger?
Yes. Since the default logger is just a standard spdlog::logger instance, you can construct it with multiple sinks (such as console and file sinks) using spdlog::sinks_init_list before calling set_default_logger(), as shown in the multi-sink example above.
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 →