# How to Set a Custom Error Handler in spdlog: Global and Per-Logger APIs

> Learn how to set a custom error handler in spdlog globally or per logger with C++ APIs. Redirect spdlog errors to monitoring systems instead of stderr.

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

---

**You can intercept spdlog's internal error messages by installing a user-defined callback with signature `void(const std::string&)` either globally via `spdlog::set_error_handler()` or per-logger via `logger::set_error_handler()`, allowing you to redirect failures like file write errors to monitoring systems instead of stderr.**

The spdlog library provides a flexible mechanism to capture internal logging failures through custom error handlers. When operations like opening a log file or writing to a sink fail, spdlog routes these errors to a registered callback rather than silently dropping them. This article explains how to set a custom error handler in spdlog using both global and per-logger scopes, based on the actual implementation in the `gabime/spdlog` repository.

## Understanding spdlog's Error Handling Mechanism

spdlog reports internal failures—such as being unable to create a log file or write to a sink—through a dedicated error handler callback. By default, spdlog writes these messages to `stderr`, but you can override this behavior to log errors to external monitoring systems, perform cleanup, or trigger application termination.

The error handler uses the signature `void(const std::string& msg)`, receiving a descriptive message about the failure. You can register this handler at two scopes: **global** (affecting all loggers) or **per-logger** (overriding the global handler for specific instances).

## Setting a Global Custom Error Handler

The global API affects every logger in your application unless explicitly overridden. According to the spdlog source code, the global handler is declared in [`include/spdlog/spdlog.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h) at line 91 and implemented in [`include/spdlog/spdlog-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog-inl.h) at line 54.

When you call `spdlog::set_error_handler()`, the implementation updates the registry's global handler, which then propagates to newly created loggers via [`include/spdlog/details/registry.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/details/registry.h) and [`registry-inl.h`](https://github.com/gabime/spdlog/blob/main/registry-inl.h) (lines 165-168).

To set a global handler:

```cpp
#include <spdlog/spdlog.h>
#include <iostream>

void global_error_handler(const std::string& msg)
{
    std::cerr << "[Global spdlog error] " << msg << std::endl;
    // Optional: log to monitoring system or terminate
}

int main()
{
    // Install before creating loggers
    spdlog::set_error_handler(global_error_handler);
    
    auto logger = spdlog::stdout_color_mt("console");
    // Any errors in 'logger' will now call global_error_handler
}

```

## Setting a Per-Logger Custom Error Handler

Individual loggers can override the global handler using the `set_error_handler` member function. This is declared in [`include/spdlog/logger.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/logger.h) at line 310 and implemented in [`include/spdlog/logger-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/logger-inl.h) at line 112.

This approach allows different loggers to handle errors differently—for example, a file logger might attempt backup operations while a console logger simply reports to stderr.

```cpp
auto file_logger = spdlog::basic_logger_mt("file", "app.log");

// Override with lambda handler
file_logger->set_error_handler([](const std::string& msg)
{
    std::cerr << "[File logger specific error] " << msg << std::endl;
    // Perform file-specific recovery or alerting
});

```

## Complete Implementation Example

The following example demonstrates installing both global and per-logger handlers, showing how spdlog routes errors through the appropriate callback:

```cpp
#include <spdlog/spdlog.h>
#include <iostream>
#include <cstdlib>

void my_global_handler(const std::string& msg)
{
    std::cerr << "[MONITORING ALERT] Logging failure: " << msg << std::endl;
    // Could send to external service here
}

int main()
{
    // 1. Set global handler before any logger creation
    spdlog::set_error_handler(my_global_handler);
    
    // 2. Create logger using global handler
    auto console = spdlog::stdout_color_mt("console");
    
    // 3. Create file logger with specific error handling
    auto file_logger = spdlog::basic_logger_mt("file", "logs.txt");
    file_logger->set_error_handler([](const std::string& msg)
    {
        std::cerr << "[File backup initiated] Error: " << msg << std::endl;
        // Attempt recovery or alert operations team
    });
    
    // Normal usage - errors will route to appropriate handler
    console->info("Application started");
    file_logger->error("Test message");
    
    return 0;
}

```

## Key Source Files and Implementation Details

The error handler mechanism spans several files in the spdlog repository:

- **[`include/spdlog/spdlog.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h)** (line 91): Declares `spdlog::set_error_handler(void(*handler)(const std::string&))`
- **[`include/spdlog/spdlog-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog-inl.h)** (line 54): Implements the global registration function
- **[`include/spdlog/logger.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/logger.h)** (line 310): Declares `logger::set_error_handler(err_handler handler)`
- **[`include/spdlog/logger-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/logger-inl.h)** (line 112): Implements the per-logger setter
- **[`include/spdlog/details/registry.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/details/registry.h)** and **[`registry-inl.h`](https://github.com/gabime/spdlog/blob/main/registry-inl.h)** (lines 165-168): Manage propagation of the global handler to logger instances

## Summary

- **Use `spdlog::set_error_handler()`** to define a global callback that catches errors for all loggers, implemented in [`spdlog-inl.h`](https://github.com/gabime/spdlog/blob/main/spdlog-inl.h).
- **Use `logger::set_error_handler()`** to override the global handler for specific logger instances, declared in [`logger.h`](https://github.com/gabime/spdlog/blob/main/logger.h) at line 310.
- **Implement the signature `void(const std::string&)`** to receive error messages describing the failure.
- **Register global handlers before logger creation** to ensure all loggers inherit the custom handler via the registry mechanism in [`registry-inl.h`](https://github.com/gabime/spdlog/blob/main/registry-inl.h).
- **Handle errors appropriately** based on logger type—file errors might need different recovery than console errors.

## Frequently Asked Questions

### What function signature must a custom error handler have?

A custom error handler must match the signature `void(const std::string& msg)`, accepting a string parameter containing the error description. This signature is strictly enforced by the template parameters in [`spdlog.h`](https://github.com/gabime/spdlog/blob/main/spdlog.h) and [`logger.h`](https://github.com/gabime/spdlog/blob/main/logger.h).

### Does a per-logger error handler override the global handler?

Yes. When you call `set_error_handler()` on a specific logger instance, that handler replaces the global handler for that logger only. Other loggers continue to use the global handler or their own specific handlers.

### What types of errors trigger the custom handler?

The handler catches internal spdlog failures such as inability to open log files, write errors to sinks, flush failures, and other I/O operations that fail during the logging process. It does not catch application logic errors or logging API misuse.

### Can I throw exceptions from within a custom error handler?

While technically possible, throwing exceptions from within the error handler is generally discouraged because spdlog calls the handler from within its logging operations. An unhandled exception could terminate your application. Instead, log to a fallback mechanism or set a flag for later inspection.