How to Implement a Custom Error Handler in spdlog
You can intercept spdlog internal failures by calling spdlog::set_error_handler() with a callback function that receives const std::string&, or by using logger::set_error_handler() for individual logger instances.
The gabime/spdlog library provides a robust mechanism to capture and process internal logging errors—such as file permission failures or sink write errors—through customizable error handlers. When you implement a custom error handler in spdlog, you gain control over how the library reports failures, allowing you to redirect errors to monitoring systems, throw exceptions, or execute recovery logic instead of the default stderr output.
Understanding the Error Handler Architecture
spdlog operates with two distinct scopes for error handling: global and per-logger. The global error handler serves as the default fallback for all loggers, while individual loggers can override this behavior with specialized handlers.
When an internal error occurs, spdlog invokes the registered handler with a descriptive message. The handler signature must conform to void(const std::string& msg). According to the source code in include/spdlog/spdlog.h (line 91), the global API is declared as:
void set_error_handler(void(*handler)(const std::string& msg));
The implementation in include/spdlog/spdlog-inl.h (line 54) delegates to the registry, which stores the handler and propagates it to newly created loggers via include/spdlog/details/registry.h (line 79) and its inline implementation in registry-inl.h (lines 165-168).
Setting a Global Error Handler
To establish a default error handling strategy across your entire application, install a global handler before creating any loggers. This approach ensures that every logger created subsequently inherits the custom error processing logic unless explicitly overridden.
The global handler is particularly useful for centralized error monitoring or when you need uniform failure reporting across multiple loggers. As implemented in include/spdlog/spdlog-inl.h, the function stores your callback in the internal registry, making it available to all future logger instances.
Here is how to define and register a global error handler:
#include <spdlog/spdlog.h>
#include <iostream>
void my_global_handler(const std::string& msg)
{
// Redirect to monitoring system or alternative logging
std::cerr << "[CRITICAL LOG ERROR] " << msg << std::endl;
// Optionally terminate or throw based on severity
// std::terminate();
}
int main()
{
// Install before creating any loggers
spdlog::set_error_handler(my_global_handler);
// This logger inherits the global handler
auto console = spdlog::stdout_color_mt("console");
}
Implementing Per-Logger Error Handlers
For scenarios requiring differentiated error handling strategies, spdlog allows you to override the global handler on individual logger instances. The logger class declares this capability in include/spdlog/logger.h (line 310):
void set_error_handler(err_handler handler);
The implementation resides in include/spdlog/logger-inl.h (line 112), where the member function replaces the logger's internal error handler pointer. This design enables file-specific error recovery, network sink isolation, or distinct alerting thresholds per logging channel.
Per-logger handlers take precedence over the global handler, allowing fine-grained control:
auto file_logger = spdlog::basic_logger_mt("file", "/read-only/path/app.log");
// Override with lambda handler for this specific logger
file_logger->set_error_handler([](const std::string& msg)
{
std::cerr << "[File Logger Specific] Failed to write: " << msg << std::endl;
// Implement file-specific recovery or alerting
});
Complete Implementation Example
The following example demonstrates both global and per-logger error handler installation, showcasing how to implement a custom error handler in spdlog for comprehensive failure management:
// custom_error_handling.cpp
#include <spdlog/spdlog.h>
#include <iostream>
#include <stdexcept>
void global_error_handler(const std::string& msg)
{
std::cerr << "[Global Handler] spdlog error: " << msg << std::endl;
// Could integrate with external monitoring here
}
int main()
{
// 1. Set global handler before any logger creation
spdlog::set_error_handler(global_error_handler);
// 2. Create console logger (inherits global handler)
auto console = spdlog::stdout_color_mt("console");
console->info("Console logger initialized");
// 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)
{
// Custom behavior for file operations
std::cerr << "[File Handler] Disk write failed: " << msg << std::endl;
throw std::runtime_error("Logging infrastructure failure: " + msg);
});
// 4. Operations that trigger error handling
file_logger->error("This invokes the per-logger handler on failure");
return 0;
}
Summary
- Global Installation: Use
spdlog::set_error_handler()defined ininclude/spdlog/spdlog.hto establish a default error callback for all loggers, implemented ininclude/spdlog/spdlog-inl.h. - Per-Logger Override: Call
set_error_handler()on individual logger instances (declared ininclude/spdlog/logger.h, implemented ininclude/spdlog/logger-inl.h) to implement logger-specific error processing. - Handler Signature: All error handlers must conform to
void(const std::string& msg)and receive descriptive failure messages from the library. - Registry Propagation: The global handler propagates through
include/spdlog/details/registry.hto new loggers via the mechanism inregistry-inl.h(lines 165-168).
Frequently Asked Questions
What signature must a custom spdlog error handler implement?
Your custom error handler must implement the function signature void(const std::string& msg). The library passes a descriptive error message string when internal failures occur, such as file permission denials or sink write failures. This applies to both global handlers set via spdlog::set_error_handler() and per-logger handlers set via logger::set_error_handler().
How do I make a specific logger use a different error handler than the global default?
Call set_error_handler() directly on the logger instance after creation. According to the implementation in include/spdlog/logger-inl.h (line 112), this method overrides the global handler stored in the registry. The per-logger handler takes exclusive precedence for that specific logger instance, while other loggers continue using the global handler.
Can I throw exceptions from within a spdlog error handler?
Yes, you can throw exceptions from your error handler implementation, but be aware that this will propagate out from the logging call site. Since spdlog error handlers are called when the library encounters internal failures (like being unable to write to a sink), throwing exceptions here may interrupt your application's normal logging flow. Ensure your surrounding code is prepared to catch these exceptions if you choose this approach.
Where does spdlog store the global error handler internally?
The global error handler is stored in the internal registry class defined in include/spdlog/details/registry.h (line 79). When you call spdlog::set_error_handler(), the implementation in include/spdlog/spdlog-inl.h (line 54) forwards the callback to this registry. Newly created loggers receive this handler during initialization through the propagation logic in registry-inl.h (lines 165-168), unless explicitly overridden per-logger.
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 →