# How to Change the Default Logger in spdlog: A Complete Guide

> Easily change the default logger in spdlog by calling spdlog::set_default_logger. This complete guide shows you how to replace the global logger for info macros.

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

---

**Call `spdlog::set_default_logger(std::shared_ptr<logger>)` to replace the global default logger used by `spdlog::info()` and `SPDLOG_INFO` macros.**

The spdlog library provides a global default logger that powers convenience functions like `spdlog::info()` and the `SPDLOG_INFO` macro. When you need to redirect all global logging output to custom sinks or silence it entirely, you must change the default logger in spdlog through its registry API. This guide explains the exact mechanism using the actual implementation from the gabime/spdlog repository.

## Understanding the spdlog Default Logger Registry

The default logger is managed internally by the `details::registry` singleton. According to the source code in [`include/spdlog/details/registry.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/details/registry.h), the registry maintains a `default_logger_` pointer that provides fast access for the default API. When you invoke global logging functions, they ultimately call `default_logger_raw()` to retrieve this pointer and dispatch messages.

The registry stores all loggers in a `loggers_` map, and the default logger is simply a specific entry that receives special treatment. The public API for swapping it is declared in [`include/spdlog/spdlog.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h) and implemented in [`include/spdlog/spdlog-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog-inl.h), which forwards calls to the registry's `set_default_logger()` method.

## How to Change the Default Logger in spdlog

To change the default logger, construct a `std::shared_ptr<spdlog::logger>` with your desired sinks and configuration, then pass it to `spdlog::set_default_logger()`. As implemented in [`include/spdlog/details/registry-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/details/registry-inl.h), this function performs three operations: it registers the new logger in the global `loggers_` map, updates the `default_logger_` pointer used by `default_logger_raw()`, and resets the previous default instance if it matches the replaced name.

Here is a complete example that creates a multi-sink logger and installs it as the new default:

```cpp
// 1. Build a custom logger (colored console + rotating file)
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
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 pattern and level
my_logger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v");
my_logger->set_level(spdlog::level::debug);

// 2. Replace the spdlog default logger
spdlog::set_default_logger(my_logger);

// 3. Global calls now use the new configuration
spdlog::info("This goes to both console and rotating file");
SPDLOG_DEBUG("Debug message via macro");

```

## Silencing Global Output with a Null Logger

To completely suppress output from global macros without modifying existing code, create a logger with a `null_sink_mt` and set it as the default. This technique effectively discards all messages sent through `spdlog::info()` or similar functions.

```cpp
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);

```

## Thread Safety Considerations

**Important:** The `set_default_logger` API is **not** thread-safe with respect to concurrent logging. Do not call `spdlog::set_default_logger` while other threads are actively using spdlog's global functions (`spdlog::info()`, `SPDLOG_INFO`, etc.). This restriction is explicitly documented in the header comments of [`include/spdlog/spdlog.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h). For thread-safe reconfiguration, ensure all logging threads are synchronized or idle before swapping the default logger.

## Key Source Files and Implementation

Understanding the internal structure helps debug issues when you change the default logger in spdlog:

- **[`include/spdlog/spdlog.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h)**: Declares the public interface including `default_logger()`, `default_logger_raw()`, and `set_default_logger()`.
- **[`include/spdlog/spdlog-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog-inl.h)**: Implements inline wrappers that forward calls to the registry singleton.
- **[`include/spdlog/details/registry.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/details/registry.h)**: Defines the registry class interface, including the `default_logger_` member pointer.
- **[`include/spdlog/details/registry-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/details/registry-inl.h)**: Contains the actual logic for storing, swapping, and resetting the default logger in the `loggers_` map.

## Summary

- The **default logger** in spdlog is stored in the internal `details::registry` and accessed via `default_logger_raw()`.
- Use **`spdlog::set_default_logger(std::shared_ptr<logger>)`** to replace it at runtime.
- The registry updates the fast-path pointer and registers the new logger automatically.
- **Thread safety warning**: Never call `set_default_logger` during concurrent logging operations.
- You can silence global logging by setting a **null sink** logger as the default.

## Frequently Asked Questions

### What happens to the old default logger when I call set_default_logger?

When you change the default logger in spdlog, the registry checks if the previous default shares the same name as the new one. If so, it resets the old instance in the `loggers_` map. The old logger's `shared_ptr` reference count decrements normally, and it is destroyed when no other references exist.

### Can I use set_default_logger with async loggers?

Yes. Since `spdlog::set_default_logger` accepts any `std::shared_ptr<spdlog::logger>`, you can pass an `async_logger` instance. The registry treats async and sync loggers identically regarding default logger assignment.

### Is spdlog::set_default_logger thread-safe?

No. According to the source code comments in [`include/spdlog/spdlog.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h), you must not call `set_default_logger` while other threads are using global logging functions. Synchronize your threads or perform the swap during application initialization before spawning worker threads.

### How do I retrieve the current default logger?

Call `spdlog::default_logger()` to get a `std::shared_ptr<logger>` copy, or `spdlog::default_logger_raw()` for a raw pointer when you need high-performance access and can guarantee the logger remains valid.