How to Use the spdlog Default Logger: Configuration, Access, and Replacement
Access spdlog's default logger via spdlog::default_logger() or replace it globally using spdlog::set_default_logger(new_logger), which updates the internal registry and redirects all global logging macros immediately.
The gabime/spdlog library provides a global default logger that powers convenience functions like spdlog::info() and SPDLOG_INFO. Learning how to use the spdlog default logger effectively allows you to customize output destinations, formatting, and log levels while maintaining the simplicity of global logging calls throughout your application.
What Is the spdlog Default Logger?
The default logger is a standard spdlog::logger instance stored inside the internal registry (details::registry). When you call global logging functions or macros without specifying a logger name, they route through this instance via the fast-path pointer default_logger_ defined in include/spdlog/details/registry.h.
Because the default logger is a normal logger object, it supports any sink configuration, custom formatting patterns, and log level restrictions available in the spdlog API.
Accessing the Current Default Logger
Retrieve the existing default logger when you need to inspect its configuration or temporarily cache it before replacement.
// Returns a shared_ptr to the current default logger
auto current = spdlog::default_logger();
// Direct raw pointer access (fast-path, used internally by macros)
spdlog::logger* raw = spdlog::default_logger_raw();
These functions are declared in include/spdlog/spdlog.h and implemented in include/spdlog/spdlog-inl.h as thin wrappers forwarding to the registry.
Replacing the Default Logger at Runtime
You can swap the default logger at any time using spdlog::set_default_logger(). According to the source code in include/spdlog/details/registry-inl.h, this operation performs three critical actions:
- Registers the new logger in the global
loggers_map for later retrieval by name. - Updates the fast-path pointer
default_logger_to point to the new instance. - Resets the previous default if its name matches the one being replaced.
// Create a custom logger with multiple 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 max, 3 rotated files
spdlog::sinks_init_list sink_list = { console_sink, file_sink };
auto my_logger = std::make_shared<spdlog::logger>("multi_sink",
sink_list.begin(),
sink_list.end());
// Configure before installing
my_logger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] %v");
my_logger->set_level(spdlog::level::debug);
// Replace the default logger globally
spdlog::set_default_logger(my_logger);
// All subsequent global calls now use the new configuration
spdlog::info("This writes to both console and rotating file");
SPDLOG_DEBUG("Macro-based debug call uses the same sinks");
Configuring Custom Sinks and Patterns
Before calling set_default_logger(), configure your replacement logger using the standard spdlog::logger interface defined in include/spdlog/logger.h. The logger constructor accepts sink iterators, allowing you to combine console, file, network, or custom sinks.
// Example: Async logger with custom formatting
auto tp = std::make_shared<spdlog::details::thread_pool>(8192, 1);
auto async_file = std::make_shared<spdlog::sinks::basic_file_sink_mt>("async.log");
auto async_logger = std::make_shared<spdlog::async_logger>("async_default",
async_file,
tp,
spdlog::async_overflow_policy::block);
async_logger->set_level(spdlog::level::warn);
spdlog::set_default_logger(async_logger);
Silencing Output with a Null Logger
To suppress all global logging without removing macro calls, replace the default 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);
// These calls execute but produce no output
spdlog::info("This is silently discarded");
SPDLOG_ERROR("This error also goes to null");
Thread Safety Considerations
Important: The set_default_logger() API is not thread-safe with respect to concurrent logging. As documented in the header comments of include/spdlog/spdlog.h, you must not call set_default_logger while other threads are actively using spdlog's global functions. Perform logger replacement during application initialization or ensure proper synchronization before swapping the default instance at runtime.
Summary
- The default logger resides in the internal registry and handles all global
spdlog::info()andSPDLOG_INFO()calls. - Replace it using spdlog::set_default_logger(), which updates the registry's
loggers_map and the fast-pathdefault_logger_pointer. - Configure any combination of sinks and patterns before installing the logger, as the new instance becomes active immediately.
- Global replacement is not thread-safe against concurrent logging calls—initialize the default logger before spawning worker threads or guard the replacement with external synchronization.
- Use a null sink to silence output globally without modifying existing logging statements.
Frequently Asked Questions
How do I retrieve the current spdlog default logger?
Call spdlog::default_logger(), which returns a std::shared_ptr<spdlog::logger> to the current default instance. For raw pointer access without reference counting overhead (primarily for internal use), use spdlog::default_logger_raw() declared in include/spdlog/spdlog.h.
Is spdlog::set_default_logger thread-safe?
No. According to the source code comments in include/spdlog/spdlog.h, set_default_logger is not thread-safe with respect to other threads using spdlog's global functions. You must ensure no other thread is logging when you replace the default logger, typically by setting it once during application startup.
Can I use multiple sinks with the spdlog default logger?
Yes. Since the default logger is a standard spdlog::logger instance, you can initialize it with multiple sinks using the constructor that accepts iterator ranges, as implemented in include/spdlog/logger.h. Pass a sinks_init_list or vector of sink pointers when creating the logger before calling set_default_logger().
How do I silence spdlog globally without removing macro calls?
Create a logger with a null_sink_mt or null_sink_st and install it as the default. This effectively discards all logging output while keeping the binary compatible with existing SPDLOG_INFO and spdlog::info() calls throughout your codebase.
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 →