How to Create a Custom Error Handler in spdlog: Global and Per-Logger Configuration
You can intercept spdlog internal errors by installing a custom callback via spdlog::set_error_handler() for global coverage or logger::set_error_handler() for specific logger instances, allowing you to redirect failures to monitoring systems, throw exceptions, or perform cleanup instead of writing to stderr.
The gabime/spdlog library provides a robust mechanism to capture internal failures—such as file permission errors or sink write failures—through user-defined callbacks. When a logging operation fails, spdlog invokes your registered handler with a descriptive message, giving you full control over error reporting rather than relying on the default stderr output.
Understanding spdlog Error Handling Scopes
spdlog implements two distinct levels of error handling to accommodate different architectural needs. The global error handler applies to all loggers by default, while per-logger error handlers override the global setting for specific instances.
The default behavior, as implemented in the source, writes error messages to stderr. By installing a custom error handler, you can integrate with application-specific logging frameworks, trigger alerts, or implement graceful degradation strategies when the logging subsystem itself encounters problems.
Implementing a Global Custom Error Handler
The global API is declared in include/spdlog/spdlog.h (line 91) and implemented in include/spdlog/spdlog-inl.h (line 54). This handler propagates through the registry mechanism defined in include/spdlog/details/registry.h and registry-inl.h (lines 165-168), ensuring all newly created loggers inherit the setting unless explicitly overridden.
Registering the Handler
To install a global handler, define a function matching the signature void(const std::string&) and pass it to spdlog::set_error_handler():
#include <spdlog/spdlog.h>
#include <iostream>
// Define a custom error handler
void my_error_handler(const std::string& msg)
{
std::cerr << "[CRITICAL] spdlog error: " << msg << std::endl;
// Optionally: send to monitoring, write to alternative log, or std::terminate()
}
int main()
{
// Install globally before creating any loggers
spdlog::set_error_handler(my_error_handler);
auto console = spdlog::stdout_color_mt("console");
// Any internal errors in 'console' will now call my_error_handler
}
Global Handler Propagation
According to the spdlog source code, the registry stores the global handler and automatically assigns it to new loggers during creation. This ensures consistent error handling across your application without requiring per-instance configuration.
Configuring Per-Logger Error Handlers
For scenarios requiring specialized error handling—such as different failure strategies for file versus network loggers—use the per-logger API. The member declaration resides in include/spdlog/logger.h (line 310) with implementation in include/spdlog/logger-inl.h (line 112).
Overriding the Global Handler
Once you obtain a logger instance, call set_error_handler() with a callable object:
auto file_logger = spdlog::basic_logger_mt("file", "logs.txt");
// Install a lambda handler specific to this logger
file_logger->set_error_handler([](const std::string& msg)
{
std::cerr << "[file logger] Specific error: " << msg << std::endl;
// Implement file-specific recovery logic here
});
This per-logger error handler takes precedence over the global setting, allowing granular control when different logging destinations require distinct failure management strategies.
Complete Working Example
The following example demonstrates both global and per-logger custom error handlers working together:
// custom_handler_demo.cpp
#include <spdlog/spdlog.h>
#include <iostream>
void global_error_handler(const std::string& msg)
{
std::cerr << "[GLOBAL ERROR] " << msg << std::endl;
}
int main()
{
// 1. Set global handler (from spdlog.h)
spdlog::set_error_handler(global_error_handler);
// 2. Create logger inheriting global handler
auto console = spdlog::stdout_color_mt("console");
// 3. Create file logger with specific handler
auto file_logger = spdlog::basic_logger_mt("file", "logs.txt");
file_logger->set_error_handler([](const std::string& msg)
{
std::cerr << "[FILE LOGGER ERROR] " << msg << std::endl;
// Could attempt file rotation or alert operations team
});
// 4. Normal usage - errors will route to respective handlers
console->info("Console message");
file_logger->error("File message");
return 0;
}
Key Implementation Details
When implementing a custom error handler in spdlog, consider these technical specifics from the source code:
- Function Signature: Handlers must accept
const std::string&and returnvoid - Thread Safety: The registry implementation in
registry-inl.huses mutex protection when setting and retrieving the global handler - Inheritance: Loggers created after
spdlog::set_error_handler()automatically receive the global handler; existing loggers retain their current settings unless explicitly modified - Default Behavior: If no handler is set, spdlog uses an internal default that prints to
stderr
Summary
- Global error handlers apply application-wide via
spdlog::set_error_handler(), declared ininclude/spdlog/spdlog.h - Per-logger error handlers override global settings via
logger::set_error_handler(), declared ininclude/spdlog/logger.h - The registry (
include/spdlog/details/registry.h) propagates global handlers to new logger instances - Handlers must match the signature
void(const std::string&)and can perform any operation including throwing exceptions or terminating the application - Install handlers before logger creation to ensure consistent application-wide error handling
Frequently Asked Questions
What is the exact signature required for a custom error handler function?
Your custom handler must match the signature void handler_name(const std::string& msg). Both the global spdlog::set_error_handler() and the per-logger set_error_handler() expect this exact signature, as defined in include/spdlog/spdlog.h and include/spdlog/logger.h respectively.
Can I throw exceptions from within the custom error handler?
Yes, you can throw exceptions from your custom error handler, though you should consider whether your application can safely handle exceptions originating from the logging subsystem. The spdlog source code does not catch exceptions from user-provided handlers, so any uncaught exception will propagate up the call stack.
How do I restore the default stderr error handler?
To restore the default behavior, pass a null handler or a lambda that mimics the default behavior to spdlog::set_error_handler() or logger::set_error_handler(). The default implementation simply writes the message to stderr, so you can replicate this with [](const std::string& msg) { std::cerr << msg << std::endl; }.
What types of errors trigger the custom handler?
The custom error handler is invoked for internal spdlog failures such as being unable to open a log file, write failures to sinks, mutex acquisition failures, or formatting errors. It does not trigger on normal log messages; it only fires when the logging infrastructure itself encounters an error condition that would prevent successful message delivery.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →