Setting Up Custom Error Handlers in spdlog: Global and Per-Logger Configuration
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/v1.x/include/spdlog/spdlog.h#L91) at line 91 and implemented in [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/v1.x/include/spdlog/details/registry.h#L79) and registry-inl.h (lines 165-168).
#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/v1.x/include/spdlog/logger.h#L310) at line 310 and implemented in [include/spdlog/logger-inl.h](https://github.com/gabime/spdlog/blob/v1.x/include/spdlog/logger-inl.h#L112) at line 112.
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:
// 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:
- Define your handler with the exact signature
void(const std::string&) - Register globally via
spdlog::set_error_handler()to establish default behavior - Create loggers normally—they automatically inherit the global handler
- Override specific loggers using
logger::set_error_handler()when specialized handling is required - Handle errors as they occur through your custom logic
Summary
- Global error handling is configured through
spdlog::set_error_handler()inspdlog.hand applies to all loggers by default - Per-logger error handling overrides the global setting via
logger::set_error_handler()declared inlogger.h - Handler signature must be
void(const std::string&)to receive error messages - Registry mechanism in
registry.handregistry-inl.hpropagates global handlers to new logger instances - Default behavior writes errors to
stderrif 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.
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 →