# How to Implement Custom Error Handlers in spdlog: A Complete Guide

> Learn to implement custom error handlers in spdlog. This guide shows how to set global or per-logger callbacks to manage logging failures effectively. Maximize control over your application's error reporting.

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

---

**You can implement custom error handlers in spdlog by installing a callback function with the signature `void(const std::string&)` using `spdlog::set_error_handler()` for global coverage or `logger::set_error_handler()` for per-logger interception of internal logging failures.**

The gabime/spdlog library routes internal failure notifications—such as file permission errors or sink initialization failures—through a configurable callback mechanism rather than silently dropping errors. Implementing custom error handlers in spdlog enables you to redirect diagnostics to monitoring systems, trigger application alerts, or execute recovery logic when the logging infrastructure encounters problems.

## Understanding Error Handling Levels

spdlog implements a two-tier error handling architecture that operates at different scopes within the logging hierarchy. The system distinguishes between **global handlers** that apply to all loggers and **per-logger handlers** that override the global behavior for specific instances.

When no custom handler is registered, spdlog defaults to writing error messages to `stderr`. According to the source in [`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), the registry propagates global handlers to newly created loggers during initialization.

### Global Error Handler API

The global interface declared in [`include/spdlog/spdlog.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h) (line 91) and implemented in [`include/spdlog/spdlog-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog-inl.h) (line 54) provides application-wide error interception.

```cpp
spdlog::set_error_handler(void(*handler)(const std::string& msg));

```

### Per-Logger Error Handler API

Individual logger instances override global behavior using the member function declared in [`include/spdlog/logger.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/logger.h) (line 310) and implemented in [`include/spdlog/logger-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/logger-inl.h) (line 112).

```cpp
logger::set_error_handler(err_handler handler);

```

## Implementing a Global Custom Error Handler

To capture all spdlog errors application-wide, define a function matching the required signature and register it before creating any loggers. This ensures the registry propagates your handler to all subsequent logger instances.

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

void global_error_handler(const std::string& msg)
{
    std::cerr << "[CRITICAL LOG FAILURE] " << msg << std::endl;
    // Integration point: send to monitoring APIs or metrics collection
}

int main()
{
    // Install before any logger creation
    spdlog::set_error_handler(global_error_handler);
    
    // This logger inherits the global error handler
    auto console = spdlog::stdout_color_mt("console");
    console->info("Application started");
}

```

## Configuring Per-Logger Error Handlers

For granular control over specific output destinations, override the error handler on individual logger instances. This approach is essential when file sinks require specialized failure handling distinct from console outputs.

```cpp
auto file_logger = spdlog::basic_logger_mt("file", "/var/log/application.txt");

file_logger->set_error_handler([](const std::string& msg) {
    // Specialized handling for disk-full or permission errors
    std::cerr << "[File Logger Alert] " << msg << std::endl;
    // Could trigger alerts or roll over to fallback storage
});

```

## Complete Implementation Example

The following example demonstrates both global and per-logger error handling strategies, including handler installation, logger creation, and error propagation through the registry.

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

// Global handler with external system integration
void my_error_handler(const std::string& msg)
{
    std::cerr << "[spdlog error] " << msg << std::endl;
    // Optional: monitoring_api::alert("logging_failure", msg);
}

int main()
{
    // 1. Register global handler via registry
    spdlog::set_error_handler(my_error_handler);
    
    // 2. Create logger using global handler
    auto console = spdlog::stdout_color_mt("console");
    console->info("Console initialized with global handler");
    
    // 3. Override for specific logger
    auto file_logger = spdlog::basic_logger_mt("file", "logs.txt");
    file_logger->set_error_handler([](const std::string& msg) {
        std::cerr << "[file-specific] " << msg << std::endl;
    });
    
    // 4. Errors in file_logger trigger per-logger handler
    // Errors in console trigger my_error_handler
    
    return 0;
}

```

## Summary

- **Global Registration**: Use `spdlog::set_error_handler()` (declared in [`spdlog.h`](https://github.com/gabime/spdlog/blob/main/spdlog.h), line 91) to intercept all logging errors application-wide via the registry mechanism.
- **Per-Logger Override**: Call `logger::set_error_handler()` (declared in [`logger.h`](https://github.com/gabime/spdlog/blob/main/logger.h), line 310) to implement specialized error processing for individual logger instances.
- **Implementation Details**: Global handlers reside in [`spdlog-inl.h`](https://github.com/gabime/spdlog/blob/main/spdlog-inl.h) (line 54), per-logger implementations in [`logger-inl.h`](https://github.com/gabime/spdlog/blob/main/logger-inl.h) (line 112), and registry propagation logic in [`registry-inl.h`](https://github.com/gabime/spdlog/blob/main/registry-inl.h) (lines 165-168).
- **Signature Requirement**: Handlers must conform to `void(const std::string&)` to receive error descriptions from spdlog's internal failure detection.
- **Default Behavior**: Without custom handlers, spdlog writes error messages to `stderr` using its internal default callback.

## Frequently Asked Questions

### What function signature is required for spdlog custom error handlers?

Custom error handlers must implement the signature `void(const std::string& msg)`. The spdlog library passes a descriptive error message string to your callback when internal failures occur, such as file permission errors or sink write failures, as defined in the handler type aliases within [`logger.h`](https://github.com/gabime/spdlog/blob/main/logger.h).

### Can I throw exceptions inside a custom error handler?

While the source code in [`logger-inl.h`](https://github.com/gabime/spdlog/blob/main/logger-inl.h) permits throwing exceptions within custom error handlers, doing so will immediately terminate the current logging operation and propagate the exception up the call stack. Because handlers are invoked synchronously during log writes, exceptions should only be thrown if your application architecture safely tolerates interruptions during logging operations.

### How do I reset the error handler to default spdlog behavior?

To restore the default `stderr` output, invoke `spdlog::set_error_handler(nullptr)` or pass a default-constructed handler. The registry implementation in [`registry-inl.h`](https://github.com/gabime/spdlog/blob/main/registry-inl.h) automatically falls back to the internal default handler that writes to standard error when no custom handler is registered.

### Are custom error handlers thread-safe in spdlog?

Error handler registration is thread-safe according to the implementation in [`registry.h`](https://github.com/gabime/spdlog/blob/main/registry.h) and [`registry-inl.h`](https://github.com/gabime/spdlog/blob/main/registry-inl.h), which uses internal synchronization to propagate global handlers across threads. However, your custom handler implementation must be thread-safe if multiple loggers might invoke it concurrently from different threads.