diff --git a/include/spdlog/details/default_err_handler.h b/include/spdlog/details/default_err_handler.h index 81a7a933b..cfe906344 100644 --- a/include/spdlog/details/default_err_handler.h +++ b/include/spdlog/details/default_err_handler.h @@ -5,6 +5,7 @@ #include #include +#include #include "spdlog/common.h" // by default, prints the error to stderr, thread safe @@ -13,7 +14,7 @@ namespace details { class default_err_handler { mutable std::mutex mutex_; public: - void handle(const std::string& origin, const source_loc& loc, const std::string &err_msg) const; + void handle_ex(const std::string& origin, const source_loc& loc, const std::exception& ex) const; }; diff --git a/include/spdlog/logger.h b/include/spdlog/logger.h index babf2a710..6171bc54e 100644 --- a/include/spdlog/logger.h +++ b/include/spdlog/logger.h @@ -3,20 +3,13 @@ #pragma once -// Thread safe logger, Except for the following methods which are not thread-safe: -// set_pattern() -// set_formatter() -// set_error_handler() -// sinks() non const version -// Has name, log level, vector of std::shared sink pointers and formatter -// Upon each log write the logger: -// 1. Checks if its log level is enough to log the message and if yes: -// 2. Call the underlying sinks to do the job. -// 3. Each sink use its own private copy of a formatter to format the message -// and send to its destination. -// -// The use of private formatter per sink provides the opportunity to cache some -// formatted data, and support for different format per sink. +// Thread-safe logger, with exceptions for these non-thread-safe methods: +// set_pattern() - Modifies the log pattern. +// set_formatter() - Sets a new formatter. +// set_error_handler() - Assigns a new error handler. +// sinks() (non-const) - Accesses and potentially modifies the sinks directly. +// By default, the logger does not throw exceptions during logging. +// To enable exception throwing for logging errors, set a custom error handler. #include #include @@ -179,12 +172,10 @@ class SPDLOG_API logger { memory_buf_t buf; fmt::vformat_to(std::back_inserter(buf), format_string, fmt::make_format_args(args...)); sink_it_(details::log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()))); - } - catch (const std::exception &ex) { \ - handle_error_(loc, ex.what()); \ - } \ - catch (...) { \ - handle_error_(loc, "Unknown exception"); \ + } catch (const std::exception &ex) { + handle_ex_(loc, ex); + } catch (...) { + handle_unknown_ex_(loc); } } @@ -195,12 +186,10 @@ class SPDLOG_API logger { if (sink->should_log(msg.log_level)) { try { sink->log(msg); - } - catch (const std::exception &ex) { \ - handle_error_(msg.source, ex.what()); \ - } \ - catch (...) { \ - handle_error_(msg.source, "Unknown exception"); \ + } catch (const std::exception &ex) { + handle_ex_(msg.source, ex); + } catch (...) { + handle_unknown_ex_(msg.source); } } } @@ -212,7 +201,8 @@ class SPDLOG_API logger { void flush_(); [[nodiscard]] bool should_flush_(const details::log_msg &msg) const; - void handle_error_(const source_loc& loc, const std::string &err_msg) const; + void handle_ex_(const source_loc &loc, const std::exception &ex) const; + void handle_unknown_ex_(const source_loc &loc) const; }; } // namespace spdlog diff --git a/src/details/default_err_handler.cpp b/src/details/default_err_handler.cpp index 648580554..cd4394b6c 100644 --- a/src/details/default_err_handler.cpp +++ b/src/details/default_err_handler.cpp @@ -8,17 +8,18 @@ namespace spdlog { namespace details { -void default_err_handler::handle(const std::string &origin, const source_loc &loc, const std::string &err_msg) const { +// print error to stderr with source location if present +void default_err_handler::handle_ex(const std::string &origin, const source_loc &loc, const std::exception &ex) const { std::lock_guard lk{mutex_}; const auto tm_time = os::localtime(); char date_buf[128]; std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time); std::string msg; if (loc.empty()) { - msg = fmt_lib::format("[*** LOGGING ERROR ***] [{}] [{}] {}\n", date_buf, origin, err_msg); - } - else { - msg = fmt_lib::format("[*** LOGGING ERROR ***] [{}({})] [{}] [{}] {}\n", loc.filename, loc.line, date_buf, origin, err_msg); + msg = fmt_lib::format("[*** LOGGING ERROR ***] [{}] [{}] {}\n", date_buf, origin, ex.what()); + } else { + msg = fmt_lib::format("[*** LOGGING ERROR ***] [{}({})] [{}] [{}] {}\n", loc.filename, loc.line, date_buf, origin, + ex.what()); } std::fputs(msg.c_str(), stderr); } diff --git a/src/logger.cpp b/src/logger.cpp index e4428d04e..93c92fa86 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -60,9 +60,7 @@ const std::vector &logger::sinks() const { return sinks_; } std::vector &logger::sinks() { return sinks_; } // custom error handler -void logger::set_error_handler(err_handler handler) { - custom_err_handler_ = std::move(handler); -} +void logger::set_error_handler(err_handler handler) { custom_err_handler_ = std::move(handler); } // create new logger with same sinks and configuration. std::shared_ptr logger::clone(std::string logger_name) { @@ -76,12 +74,10 @@ void logger::flush_() { for (auto &sink : sinks_) { try { sink->flush(); - } - catch (const std::exception &ex) { \ - handle_error_(source_loc{}, ex.what()); \ - } \ - catch (...) { \ - handle_error_(source_loc{}, "Unknown exception"); \ + } catch (const std::exception &ex) { + handle_ex_(source_loc{}, ex); + } catch (...) { + handle_unknown_ex_(source_loc{}); } } } @@ -91,12 +87,20 @@ bool logger::should_flush_(const details::log_msg &msg) const { return (msg.log_level >= flush_level) && (msg.log_level != level::off); } -void logger::handle_error_(const source_loc &loc, const std::string &err_msg) const { +void logger::handle_ex_(const source_loc &loc, const std::exception &ex) const { + if (custom_err_handler_) { + custom_err_handler_(ex.what()); + return; + } + default_err_handler_.handle_ex(name_, loc, ex); +} + +void logger::handle_unknown_ex_(const source_loc &loc) const { if (custom_err_handler_) { - custom_err_handler_(err_msg); + custom_err_handler_("unknown exception"); return; } - default_err_handler_.handle(name_, loc, err_msg); + default_err_handler_.handle_ex(name_, loc, std::runtime_error("Unknown exception")); } } // namespace spdlog diff --git a/src/sinks/async_sink.cpp b/src/sinks/async_sink.cpp index 0ba9e0d80..b59d4baab 100644 --- a/src/sinks/async_sink.cpp +++ b/src/sinks/async_sink.cpp @@ -107,7 +107,7 @@ void async_sink::backend_log_(const details::log_msg &msg) { try { sink->log(msg); } catch (const std::exception &ex) { - err_handler_.handle("async", msg.source, std::string("async log failed: ") + ex.what()); + err_handler_.handle_ex("async log", msg.source, ex); } } } @@ -118,9 +118,9 @@ void async_sink::backend_flush_() { try { sink->flush(); } catch (const std::exception &ex) { - err_handler_.handle("async", source_loc{}, std::string("async flush failed: ") + ex.what()); + err_handler_.handle_ex("async flush", source_loc{}, ex); } catch (...) { - err_handler_.handle("async", source_loc{}, "Async flush failed with unknown exception"); + err_handler_.handle_ex("async flush", source_loc{}, std::runtime_error("Unknown exception during flush")); } } }