# Setting Up Custom Error Handlers in spdlog: Global and Per-Logger Configuration

> Easily set up custom spdlog error handlers. Learn global and per-logger configuration to intercept and manage spdlog internal errors effectively. Optimize your logging.

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

---

**You can intercept spdlog internal errors by installing a custom callback using `spdlog::set_error_handler()` for global scope or `logger::set_error_handler()` for specific loggers.**

Setting up custom error handlers in spdlog allows you to capture and process internal failures—such as file permission errors or sink write failures—according to your application's requirements. The **gabime/spdlog** library provides a two-tiered architecture that supports both application-wide and logger-specific error handling strategies. By default, spdlog writes error messages to `stderr`, but you can replace this behavior with custom logic for monitoring, alerting, or graceful degradation.

## Understanding spdlog Error Handling Architecture

spdlog implements error handling through function pointer callbacks that accept a `const std::string&` parameter containing the error message. The architecture operates at two distinct scopes:

- **Global handler**: Set via `spdlog::set_error_handler()`, applies to all loggers unless explicitly overridden
- **Per-logger handler**: Set via `logger::set_error_handler()`, takes precedence over the global handler for that specific instance

When a logging operation encounters an error—such as failing to open a log file or write to a sink—spdlog invokes the registered handler with an informative message. If no custom handler is registered, the library falls back to writing the error to standard error.

## Implementing a Global Error Handler

The global error handler provides a centralized mechanism for processing all spdlog errors across your application.

### Registering the Handler

To install a global handler, define a function with the signature `void(const std::string&)` and pass it to `spdlog::set_error_handler()`. According to the spdlog source code, this function is declared in [[`include/spdlog/spdlog.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h)](https://github.com/gabime/spdlog/blob/v1.x/include/spdlog/spdlog.h#L91) at line 91 and implemented in [[`include/spdlog/spdlog-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog-inl.h)](https://github.com/gabime/spdlog/blob/v1.x/include/spdlog/spdlog-inl.h#L54) at line 54. The registry propagates this handler to newly created loggers through [[`include/spdlog/details/registry.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/details/registry.h)](https://github.com/gabime/spdlog/blob/v1.x/include/spdlog/details/registry.h#L79) and [`registry-inl.h`](https://github.com/gabime/spdlog/blob/main/registry-inl.h) (lines 165-168).

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

void my_global_handler(const std::string& msg)
{
    // Send to monitoring system, alternate log, or stderr with formatting
    std::cerr << "[CRITICAL] spdlog error: " << msg << std::endl;
}

int main()
{
    // Install before creating any loggers
    spdlog::set_error_handler(my_global_handler);
    
    auto logger = spdlog::stdout_color_mt("console");
    // Any errors in this logger will now invoke my_global_handler
}

```

## Configuring Per-Logger Error Handlers

When different loggers require distinct error handling strategies—such as separating file logger failures from console logger issues—you can override the global handler at the logger level.

### Overriding the Global Default

The `logger` class provides `set_error_handler()` to register a logger-specific callback. This member is declared in [[`include/spdlog/logger.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/logger.h)](https://github.com/gabime/spdlog/blob/v1.x/include/spdlog/logger.h#L310) at line 310 and implemented in [[`include/spdlog/logger-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/logger-inl.h)](https://github.com/gabime/spdlog/blob/v1.x/include/spdlog/logger-inl.h#L112) at line 112.

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

// Install a lambda handler specific to this logger
file_logger->set_error_handler([](const std::string& msg)
{
    // Handle file-specific errors differently
    std::cerr << "[File Logger Failure] " << msg << std::endl;
    // Could also: increment metrics, send alerts, or trigger rotation
});

```

## Practical Implementation Example

This complete example demonstrates both global and per-logger error handlers working together:

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

// 1. Define a global custom error handler
void my_error_handler(const std::string& msg)
{
    std::cerr << "[spdlog error] " << msg << std::endl;
    // Optional: std::terminate() or throw custom exception
}

int main()
{
    // 2. Install global handler before any logger creation
    spdlog::set_error_handler(my_error_handler);
    
    // 3. Create logger using the global handler
    auto console = spdlog::stdout_color_mt("console");
    console->info("Hello, world!");
    
    // 4. Override per-logger for 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 logger specific] " << msg << std::endl;
    });
    
    // 5. Errors trigger the appropriate handler
    file_logger->error("This invokes the per-logger handler");
    
    return 0;
}

```

The implementation follows these steps:

1. **Define** your handler with the exact signature `void(const std::string&)`
2. **Register** globally via `spdlog::set_error_handler()` to establish default behavior
3. **Create** loggers normally—they automatically inherit the global handler
4. **Override** specific loggers using `logger::set_error_handler()` when specialized handling is required
5. **Handle** errors as they occur through your custom logic

## Summary

- **Global error handling** is configured through `spdlog::set_error_handler()` in [`spdlog.h`](https://github.com/gabime/spdlog/blob/main/spdlog.h) and applies to all loggers by default
- **Per-logger error handling** overrides the global setting via `logger::set_error_handler()` declared in [`logger.h`](https://github.com/gabime/spdlog/blob/main/logger.h)
- **Handler signature** must be `void(const std::string&)` to receive error messages
- **Registry mechanism** 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) propagates global handlers to new logger instances
- **Default behavior** writes errors to `stderr` if no custom handler is registered

## Frequently Asked Questions

### What signature must a custom error handler have in spdlog?

A custom error handler must conform to the signature `void(const std::string& msg)`. The function receives a string containing the error description. You can use a free function, static member function, or lambda expression as long as it matches this signature.

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

Yes. When you call `logger::set_error_handler()`, that specific logger will use your custom callback instead of the global handler installed via `spdlog::set_error_handler()`. Other loggers continue to use the global handler unless they also have their own override.

### When does spdlog invoke the error handler?

spdlog calls the error handler when internal logging operations fail, such as when a file sink cannot open the target file due to permissions, when disk space is exhausted, or when a network sink fails to connect. The handler is invoked synchronously during the logging call that triggered the error.

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

Yes, you can throw exceptions from your error handler, but this will propagate out of the logging call site. Since spdlog is often used in error paths or destructor contexts, throwing exceptions from handlers may cause `std::terminate()` to be called if the exception escapes during stack unwinding. Consider logging to alternative channels or using `std::abort()`/`std::terminate()` explicitly if you need to stop the application.