# How to Use the spdlog Default Logger: Configuration, Access, and Replacement

> Learn to access and replace the spdlog default logger using spdlog::default_logger() and spdlog::set_default_logger(). Update global logging macros instantly for efficient C++ logging.

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

---

**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`](https://github.com/gabime/spdlog/blob/main/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.

```cpp
// 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`](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) 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`](https://github.com/gabime/spdlog/blob/main/include/spdlog/details/registry-inl.h), this operation performs three critical actions:

1. **Registers the new logger** in the global `loggers_` map for later retrieval by name.
2. **Updates the fast-path pointer** `default_logger_` to point to the new instance.
3. **Resets the previous default** if its name matches the one being replaced.

```cpp
// 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`](https://github.com/gabime/spdlog/blob/main/include/spdlog/logger.h). The logger constructor accepts sink iterators, allowing you to combine console, file, network, or custom sinks.

```cpp
// 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**.

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

// 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`](https://github.com/gabime/spdlog/blob/main/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()` and `SPDLOG_INFO()` calls.
- Replace it using **spdlog::set_default_logger()**, which updates the registry's `loggers_` map and the fast-path `default_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`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h).

### 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), `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`](https://github.com/gabime/spdlog/blob/main/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.