Refactored error handler

pull/3309/head
gabime 8 months ago
parent 4b74c84354
commit ea1bcdb0f9

@ -5,6 +5,7 @@
#include <string> #include <string>
#include <mutex> #include <mutex>
#include <exception>
#include "spdlog/common.h" #include "spdlog/common.h"
// by default, prints the error to stderr, thread safe // by default, prints the error to stderr, thread safe
@ -13,7 +14,7 @@ namespace details {
class default_err_handler { class default_err_handler {
mutable std::mutex mutex_; mutable std::mutex mutex_;
public: 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;
}; };

@ -3,20 +3,13 @@
#pragma once #pragma once
// Thread safe logger, Except for the following methods which are not thread-safe: // Thread-safe logger, with exceptions for these non-thread-safe methods:
// set_pattern() // set_pattern() - Modifies the log pattern.
// set_formatter() // set_formatter() - Sets a new formatter.
// set_error_handler() // set_error_handler() - Assigns a new error handler.
// sinks() non const version // sinks() (non-const) - Accesses and potentially modifies the sinks directly.
// Has name, log level, vector of std::shared sink pointers and formatter // By default, the logger does not throw exceptions during logging.
// Upon each log write the logger: // To enable exception throwing for logging errors, set a custom error handler.
// 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.
#include <cassert> #include <cassert>
#include <iterator> #include <iterator>
@ -179,12 +172,10 @@ private:
memory_buf_t buf; memory_buf_t buf;
fmt::vformat_to(std::back_inserter(buf), format_string, fmt::make_format_args(args...)); 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()))); sink_it_(details::log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size())));
} } catch (const std::exception &ex) {
catch (const std::exception &ex) { \ handle_ex_(loc, ex);
handle_error_(loc, ex.what()); \ } catch (...) {
} \ handle_unknown_ex_(loc);
catch (...) { \
handle_error_(loc, "Unknown exception"); \
} }
} }
@ -195,12 +186,10 @@ private:
if (sink->should_log(msg.log_level)) { if (sink->should_log(msg.log_level)) {
try { try {
sink->log(msg); sink->log(msg);
} } catch (const std::exception &ex) {
catch (const std::exception &ex) { \ handle_ex_(msg.source, ex);
handle_error_(msg.source, ex.what()); \ } catch (...) {
} \ handle_unknown_ex_(msg.source);
catch (...) { \
handle_error_(msg.source, "Unknown exception"); \
} }
} }
} }
@ -212,7 +201,8 @@ private:
void flush_(); void flush_();
[[nodiscard]] bool should_flush_(const details::log_msg &msg) const; [[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 } // namespace spdlog

@ -8,17 +8,18 @@
namespace spdlog { namespace spdlog {
namespace details { 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_}; std::lock_guard lk{mutex_};
const auto tm_time = os::localtime(); const auto tm_time = os::localtime();
char date_buf[128]; char date_buf[128];
std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time); std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time);
std::string msg; std::string msg;
if (loc.empty()) { if (loc.empty()) {
msg = fmt_lib::format("[*** LOGGING ERROR ***] [{}] [{}] {}\n", date_buf, origin, err_msg); msg = fmt_lib::format("[*** LOGGING ERROR ***] [{}] [{}] {}\n", date_buf, origin, ex.what());
} } else {
else { msg = fmt_lib::format("[*** LOGGING ERROR ***] [{}({})] [{}] [{}] {}\n", loc.filename, loc.line, date_buf, origin,
msg = fmt_lib::format("[*** LOGGING ERROR ***] [{}({})] [{}] [{}] {}\n", loc.filename, loc.line, date_buf, origin, err_msg); ex.what());
} }
std::fputs(msg.c_str(), stderr); std::fputs(msg.c_str(), stderr);
} }

@ -60,9 +60,7 @@ const std::vector<sink_ptr> &logger::sinks() const { return sinks_; }
std::vector<sink_ptr> &logger::sinks() { return sinks_; } std::vector<sink_ptr> &logger::sinks() { return sinks_; }
// custom error handler // custom error handler
void logger::set_error_handler(err_handler handler) { void logger::set_error_handler(err_handler handler) { custom_err_handler_ = std::move(handler); }
custom_err_handler_ = std::move(handler);
}
// create new logger with same sinks and configuration. // create new logger with same sinks and configuration.
std::shared_ptr<logger> logger::clone(std::string logger_name) { std::shared_ptr<logger> logger::clone(std::string logger_name) {
@ -76,12 +74,10 @@ void logger::flush_() {
for (auto &sink : sinks_) { for (auto &sink : sinks_) {
try { try {
sink->flush(); sink->flush();
} } catch (const std::exception &ex) {
catch (const std::exception &ex) { \ handle_ex_(source_loc{}, ex);
handle_error_(source_loc{}, ex.what()); \ } catch (...) {
} \ handle_unknown_ex_(source_loc{});
catch (...) { \
handle_error_(source_loc{}, "Unknown exception"); \
} }
} }
} }
@ -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); 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_) { if (custom_err_handler_) {
custom_err_handler_(err_msg); custom_err_handler_("unknown exception");
return; return;
} }
default_err_handler_.handle(name_, loc, err_msg); default_err_handler_.handle_ex(name_, loc, std::runtime_error("Unknown exception"));
} }
} // namespace spdlog } // namespace spdlog

@ -107,7 +107,7 @@ void async_sink::backend_log_(const details::log_msg &msg) {
try { try {
sink->log(msg); sink->log(msg);
} catch (const std::exception &ex) { } 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 { try {
sink->flush(); sink->flush();
} catch (const std::exception &ex) { } 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 (...) { } 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"));
} }
} }
} }

Loading…
Cancel
Save