Added custom error handler to avoid throwing exceptions.

pull/230/head
Kevin M. Godby 9 years ago
parent 33a185188c
commit fa30defd5f

@ -13,6 +13,7 @@
void async_example(); void async_example();
void syslog_example(); void syslog_example();
void test_custom_error_handler();
namespace spd = spdlog; namespace spd = spdlog;
int main(int, char*[]) int main(int, char*[])
@ -68,6 +69,7 @@ int main(int, char*[])
// syslog example. linux/osx only.. // syslog example. linux/osx only..
syslog_example(); syslog_example();
test_custom_error_handler();
// Release and close all loggers // Release and close all loggers
spdlog::drop_all(); spdlog::drop_all();
@ -101,6 +103,31 @@ void syslog_example()
#endif #endif
} }
// Example of user-provided error handler
void test_custom_error_handler()
{
// Trigger default error handler
try {
spd::error("test default error handler (throw an exception)");
} catch (const spd::spdlog_ex& e) {
std::cerr << "caught spdlog_ex: " << e.what() << std::endl;
}
// Set custom error handler
spd::set_error_handler(
[](const std::string& message) {
std::cerr << "SPDLOG ERROR " << message << std::endl;
}
);
// Trigger custom error handler
try {
spd::error("test custom error handler");
} catch (const spd::spdlog_ex& e) {
std::cerr << "caught spdlog_ex: " << e.what() << std::endl;
}
}
// Example of user defined class with operator<< // Example of user defined class with operator<<
class some_class {}; class some_class {};

@ -12,7 +12,7 @@
// Upon each log write the logger: // Upon each log write the logger:
// 1. Checks if its log level is enough to log the message // 1. Checks if its log level is enough to log the message
// 2. Push a new copy of the message to a queue (or block the caller until space is available in the queue) // 2. Push a new copy of the message to a queue (or block the caller until space is available in the queue)
// 3. will throw spdlog_ex upon log exceptions // 3. will call error handler upon log exceptions (which, by default, will throw spdlog_ex exception)
// Upon destruction, logs all remaining messages in the queue before destructing.. // Upon destruction, logs all remaining messages in the queue before destructing..
#include <spdlog/common.h> #include <spdlog/common.h>

@ -15,6 +15,7 @@
#include <codecvt> #include <codecvt>
#include <locale> #include <locale>
#endif #endif
#include <functional>
#include <spdlog/details/null_mutex.h> #include <spdlog/details/null_mutex.h>
@ -107,6 +108,32 @@ private:
}; };
// Function pointer to error handler. Defaults to throwing a spdlog_ex
// exception. May be overridden by the user with set_error_handler().
static std::function<void(const std::string&)> error_handler = [](const std::string& message) {
throw spdlog_ex(message);
};
// Call the user-provided error handler when an internal spdlog error occurs.
inline void error(const std::string& message)
{
error_handler(message);
}
// Set an error handler to be called in case of errors during logging (e.g.,
// can't write to file because the disk is full). Defaults to an error handler
// which logs the errors to the console.
//
// Function must have the following signature (but can be named whatever you
// like):
//
// void error_handler(const std::string &message);
//
inline void set_error_handler(std::function<void(const std::string&)> func)
{
error_handler = func;
}
// //
// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined) // wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
// //

@ -8,10 +8,11 @@
// Helper class for file sink // Helper class for file sink
// When failing to open a file, retry several times(5) with small delay between the tries(10 ms) // When failing to open a file, retry several times(5) with small delay between the tries(10 ms)
// Can be set to auto flush on every line // Can be set to auto flush on every line
// Throw spdlog_ex exception on errors // Call error handler on errors (default: throw spdlog_ex)
#include <spdlog/details/os.h> #include <spdlog/details/os.h>
#include <spdlog/details/log_msg.h> #include <spdlog/details/log_msg.h>
#include <spdlog/common.h>
#include <chrono> #include <chrono>
#include <cstdio> #include <cstdio>
@ -58,13 +59,15 @@ public:
std::this_thread::sleep_for(std::chrono::milliseconds(open_interval)); std::this_thread::sleep_for(std::chrono::milliseconds(open_interval));
} }
throw spdlog_ex("Failed opening file " + os::filename_to_str(_filename) + " for writing"); error("Failed opening file " + os::filename_to_str(_filename) + " for writing");
} }
void reopen(bool truncate) void reopen(bool truncate)
{ {
if (_filename.empty()) if (_filename.empty()) {
throw spdlog_ex("Failed re opening file - was not opened before"); error("Failed re opening file - was not opened before");
return;
}
open(_filename, truncate); open(_filename, truncate);
} }
@ -88,8 +91,10 @@ public:
size_t msg_size = msg.formatted.size(); size_t msg_size = msg.formatted.size();
auto data = msg.formatted.data(); auto data = msg.formatted.data();
if (std::fwrite(data, 1, msg_size, _fd) != msg_size) if (std::fwrite(data, 1, msg_size, _fd) != msg_size) {
throw spdlog_ex("Failed writing to file " + os::filename_to_str(_filename)); error("Failed writing to file " + os::filename_to_str(_filename));
return;
}
if (_force_flush) if (_force_flush)
std::fflush(_fd); std::fflush(_fd);
@ -97,20 +102,26 @@ public:
long size() long size()
{ {
if (!_fd) if (!_fd) {
throw spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(_filename)); error("Cannot use size() on closed file " + os::filename_to_str(_filename));
return -1;
}
auto pos = ftell(_fd); auto pos = ftell(_fd);
if (fseek(_fd, 0, SEEK_END) != 0) if (fseek(_fd, 0, SEEK_END) != 0)
throw spdlog_ex("fseek failed on file " + os::filename_to_str(_filename)); error("fseek failed on file " + os::filename_to_str(_filename));
auto file_size = ftell(_fd); auto file_size = ftell(_fd);
if(fseek(_fd, pos, SEEK_SET) !=0) if(fseek(_fd, pos, SEEK_SET) !=0) {
throw spdlog_ex("fseek failed on file " + os::filename_to_str(_filename)); error("fseek failed on file " + os::filename_to_str(_filename));
return -1;
}
if (file_size == -1) if (file_size == -1) {
throw spdlog_ex("ftell failed on file " + os::filename_to_str(_filename)); error("ftell failed on file " + os::filename_to_str(_filename));
return -1;
}
return file_size; return file_size;
} }

@ -70,7 +70,7 @@ inline void spdlog::details::line_logger::write(const char* fmt, const Args&...
} }
catch (const fmt::FormatError& e) catch (const fmt::FormatError& e)
{ {
throw spdlog_ex(fmt::format("formatting error while processing format string '{}': {}", fmt, e.what())); error(fmt::format("formatting error while processing format string '{}': {}", fmt, e.what()));
} }
} }

@ -64,8 +64,11 @@ public:
buffer_mask_(buffer_size - 1) buffer_mask_(buffer_size - 1)
{ {
//queue size must be power of two //queue size must be power of two
if(!((buffer_size >= 2) && ((buffer_size & (buffer_size - 1)) == 0))) if(!((buffer_size >= 2) && ((buffer_size & (buffer_size - 1)) == 0))) {
// FIXME: call error() instead
// FIXME: can we just round buffer_size down to the next power of two and skip the error altogether?
throw spdlog_ex("async logger queue size must be power of two"); throw spdlog_ex("async logger queue size must be power of two");
}
for (size_t i = 0; i != buffer_size; i += 1) for (size_t i = 0; i != buffer_size; i += 1)
buffer_[i].sequence_.store(i, std::memory_order_relaxed); buffer_[i].sequence_.store(i, std::memory_order_relaxed);

@ -198,8 +198,10 @@ inline int utc_minutes_offset(const std::tm& tm = details::os::localtime())
DYNAMIC_TIME_ZONE_INFORMATION tzinfo; DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
auto rv = GetDynamicTimeZoneInformation(&tzinfo); auto rv = GetDynamicTimeZoneInformation(&tzinfo);
#endif #endif
if (rv == TIME_ZONE_ID_INVALID) if (rv == TIME_ZONE_ID_INVALID) {
throw spdlog::spdlog_ex("Failed getting timezone info. Last error: " + std::to_string(GetLastError())); error("Failed getting timezone info. Last error: " + std::to_string(GetLastError()));
return 0;
}
int offset = -tzinfo.Bias; int offset = -tzinfo.Bias;
if (tm.tm_isdst) if (tm.tm_isdst)

@ -9,6 +9,7 @@
#include <spdlog/details/log_msg.h> #include <spdlog/details/log_msg.h>
#include <spdlog/details/os.h> #include <spdlog/details/os.h>
#include <spdlog/details/format.h> #include <spdlog/details/format.h>
#include <spdlog/common.h>
#include <chrono> #include <chrono>
#include <ctime> #include <ctime>
@ -623,6 +624,6 @@ inline void spdlog::pattern_formatter::format(details::log_msg& msg)
} }
catch(const fmt::FormatError& e) catch(const fmt::FormatError& e)
{ {
throw spdlog_ex(fmt::format("formatting error while processing format string: {}", e.what())); error(fmt::format("formatting error while processing format string: {}", e.what()));
} }
} }

@ -34,7 +34,7 @@ public:
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
auto logger_name = logger->name(); auto logger_name = logger->name();
throw_if_exists(logger_name); error_if_exists(logger_name);
_loggers[logger_name] = logger; _loggers[logger_name] = logger;
} }
@ -50,7 +50,7 @@ public:
std::shared_ptr<logger> create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end) std::shared_ptr<logger> create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end)
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
throw_if_exists(logger_name); error_if_exists(logger_name);
std::shared_ptr<logger> new_logger; std::shared_ptr<logger> new_logger;
if (_async_mode) if (_async_mode)
new_logger = std::make_shared<async_logger>(logger_name, sinks_begin, sinks_end, _async_q_size, _overflow_policy, _worker_warmup_cb, _flush_interval_ms, _worker_teardown_cb); new_logger = std::make_shared<async_logger>(logger_name, sinks_begin, sinks_end, _async_q_size, _overflow_policy, _worker_warmup_cb, _flush_interval_ms, _worker_teardown_cb);
@ -140,10 +140,10 @@ private:
registry_t<Mutex>(const registry_t<Mutex>&) = delete; registry_t<Mutex>(const registry_t<Mutex>&) = delete;
registry_t<Mutex>& operator=(const registry_t<Mutex>&) = delete; registry_t<Mutex>& operator=(const registry_t<Mutex>&) = delete;
void throw_if_exists(const std::string &logger_name) void error_if_exists(const std::string &logger_name)
{ {
if (_loggers.find(logger_name) != _loggers.end()) if (_loggers.find(logger_name) != _loggers.end())
throw spdlog_ex("logger with name '" + logger_name + "' already exists"); error("logger with name '" + logger_name + "' already exists");
} }
Mutex _mutex; Mutex _mutex;
std::unordered_map <std::string, std::shared_ptr<logger>> _loggers; std::unordered_map <std::string, std::shared_ptr<logger>> _loggers;
@ -155,6 +155,7 @@ private:
std::function<void()> _worker_warmup_cb = nullptr; std::function<void()> _worker_warmup_cb = nullptr;
std::chrono::milliseconds _flush_interval_ms; std::chrono::milliseconds _flush_interval_ms;
std::function<void()> _worker_teardown_cb = nullptr; std::function<void()> _worker_teardown_cb = nullptr;
std::function<void(std::string)> _error_handler = [](const std::string& message) { throw spdlog_ex(message); };
}; };
#ifdef SPDLOG_NO_REGISTRY_MUTEX #ifdef SPDLOG_NO_REGISTRY_MUTEX
typedef registry_t<spdlog::details::null_mutex> registry; typedef registry_t<spdlog::details::null_mutex> registry;

@ -146,3 +146,4 @@ inline void spdlog::drop_all()
{ {
details::registry::instance().drop_all(); details::registry::instance().drop_all();
} }

@ -9,6 +9,7 @@
#include <spdlog/sinks/base_sink.h> #include <spdlog/sinks/base_sink.h>
#include <spdlog/details/null_mutex.h> #include <spdlog/details/null_mutex.h>
#include <spdlog/common.h>
#include <android/log.h> #include <android/log.h>
@ -48,7 +49,7 @@ protected:
} }
else else
{ {
throw spdlog_ex("Send to Android logcat failed"); error("Send to Android logcat failed");
} }
} }
@ -76,7 +77,8 @@ private:
case spdlog::level::emerg: case spdlog::level::emerg:
return ANDROID_LOG_FATAL; return ANDROID_LOG_FATAL;
default: default:
throw spdlog_ex("Incorrect level value"); error("Incorrect level value");
return ANDROID_LOG_INFO;
} }
} }

@ -9,6 +9,7 @@
#include <spdlog/details/null_mutex.h> #include <spdlog/details/null_mutex.h>
#include <spdlog/details/file_helper.h> #include <spdlog/details/file_helper.h>
#include <spdlog/details/format.h> #include <spdlog/details/format.h>
#include <spdlog/common.h>
#include <algorithm> #include <algorithm>
#include <chrono> #include <chrono>
@ -119,12 +120,14 @@ private:
{ {
if (details::os::remove(target) != 0) if (details::os::remove(target) != 0)
{ {
throw spdlog_ex("rotating_file_sink: failed removing " + filename_to_str(target)); error("rotating_file_sink: failed removing " + filename_to_str(target));
return;
} }
} }
if (details::file_helper::file_exists(src) && details::os::rename(src, target)) if (details::file_helper::file_exists(src) && details::os::rename(src, target))
{ {
throw spdlog_ex("rotating_file_sink: failed renaming " + filename_to_str(src) + " to " + filename_to_str(target)); error("rotating_file_sink: failed renaming " + filename_to_str(src) + " to " + filename_to_str(target));
return;
} }
} }
_file_helper.reopen(true); _file_helper.reopen(true);
@ -189,8 +192,16 @@ public:
_rotation_m(rotation_minute), _rotation_m(rotation_minute),
_file_helper(force_flush) _file_helper(force_flush)
{ {
if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59) if (rotation_hour < 0 || rotation_hour > 23) {
throw spdlog_ex("daily_file_sink: Invalid rotation time in ctor"); error("daily_file_sink: Invalid rotation hour (" + std::to_string(rotation_hour) + "). Must be between 0 and 23.");
rotation_hour = 0;
}
if (rotation_minute < 0 || rotation_minute > 59) {
error("daily_file_sink: Invalid rotation minute (" + std::to_string(rotation_minute) + "). Must be between 0 and 59.");
rotation_minute = 0;
}
_rotation_tp = _next_rotation_tp(); _rotation_tp = _next_rotation_tp();
_file_helper.open(FileNameCalc::calc_filename(_base_filename, _extension)); _file_helper.open(FileNameCalc::calc_filename(_base_filename, _extension));
} }

@ -112,7 +112,6 @@ void drop(const std::string &name);
// Drop all references // Drop all references
void drop_all(); void drop_all();
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// //
// Macros to be display source file & line // Macros to be display source file & line

Loading…
Cancel
Save