Skip to content

Commit

Permalink
Refactored error handler
Browse files Browse the repository at this point in the history
  • Loading branch information
gabime committed Jan 4, 2025
1 parent 4b74c84 commit ea1bcdb
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 48 deletions.
3 changes: 2 additions & 1 deletion include/spdlog/details/default_err_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <string>
#include <mutex>
#include <exception>
#include "spdlog/common.h"

// by default, prints the error to stderr, thread safe
Expand All @@ -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;
};


Expand Down
44 changes: 17 additions & 27 deletions include/spdlog/logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <cassert>
#include <iterator>
Expand Down Expand Up @@ -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);
}
}

Expand All @@ -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);
}
}
}
Expand All @@ -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
11 changes: 6 additions & 5 deletions src/details/default_err_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
28 changes: 16 additions & 12 deletions src/logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,7 @@ const std::vector<sink_ptr> &logger::sinks() const { return sinks_; }
std::vector<sink_ptr> &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> logger::clone(std::string logger_name) {
Expand All @@ -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{});
}
}
}
Expand All @@ -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
6 changes: 3 additions & 3 deletions src/sinks/async_sink.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
Expand All @@ -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"));
}
}
}
Expand Down

0 comments on commit ea1bcdb

Please sign in to comment.