Refactored error handler
This commit is contained in:
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_) {
|
if (custom_err_handler_) {
|
||||||
custom_err_handler_(err_msg);
|
custom_err_handler_(ex.what());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
default_err_handler_.handle(name_, loc, err_msg);
|
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_("unknown exception");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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…
Reference in New Issue
Block a user