error handler wip

pull/3309/head
gabime 8 months ago
parent 833bb360a3
commit 0fd3e80794

@ -156,6 +156,7 @@ set(SPDLOG_HEADERS
"include/spdlog/details/mpmc_blocking_q.h" "include/spdlog/details/mpmc_blocking_q.h"
"include/spdlog/details/null_mutex.h" "include/spdlog/details/null_mutex.h"
"include/spdlog/details/os.h" "include/spdlog/details/os.h"
"include/spdlog/details/error_handler.h"
"include/spdlog/bin_to_hex.h" "include/spdlog/bin_to_hex.h"
"include/spdlog/sinks/android_sink.h" "include/spdlog/sinks/android_sink.h"
"include/spdlog/sinks/base_sink.h" "include/spdlog/sinks/base_sink.h"
@ -191,6 +192,7 @@ set(SPDLOG_SRCS
"src/details/os_filesystem.cpp" "src/details/os_filesystem.cpp"
"src/details/log_msg.cpp" "src/details/log_msg.cpp"
"src/details/async_log_msg.cpp" "src/details/async_log_msg.cpp"
"src/details/error_handler.cpp"
"src/sinks/base_sink.cpp" "src/sinks/base_sink.cpp"
"src/sinks/basic_file_sink.cpp" "src/sinks/basic_file_sink.cpp"
"src/sinks/rotating_file_sink.cpp" "src/sinks/rotating_file_sink.cpp"

@ -0,0 +1,33 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <string>
#include <mutex>
#include "spdlog/common.h"
// by default, prints the error to stderr. thread safe.
namespace spdlog {
namespace details {
class error_handler {
public:
explicit error_handler(std::string name);
error_handler(const error_handler &);
error_handler(error_handler &&) noexcept;
// for simplicity allow only construction of this class.
// otherwise we need to deal with mutexes and potential deadlocks.
error_handler &operator=(const error_handler &) = delete;
error_handler &operator=(error_handler &&) = delete;
void handle(const source_loc& loc, const std::string &err_msg) const;
void set_name(const std::string& name);
void set_custom_handler(err_handler handler);
private:
mutable std::mutex mutex_;
std::string name_;
err_handler custom_handler_ = nullptr;
};
}} // namespace spdlog::details

@ -20,19 +20,15 @@
#include "common.h" #include "common.h"
#include "details/log_msg.h" #include "details/log_msg.h"
#include "details/error_handler.h"
#include "sinks/sink.h" #include "sinks/sink.h"
#define SPDLOG_LOGGER_CATCH(location) \ #define SPDLOG_LOGGER_CATCH(location) \
catch (const std::exception &ex) { \ catch (const std::exception &ex) { \
if (!location.empty()) { \ err_handler_.handle(location, ex.what()); \
err_handler_(fmt_lib::format(SPDLOG_FMT_STRING("{} [{}({})]"), ex.what(), location.filename, location.line)); \
} else { \
err_handler_(ex.what()); \
} \
} \ } \
catch (...) { \ catch (...) { \
err_handler_("Rethrowing unknown exception in logger"); \ err_handler_.handle(location, "Unknown exception"); \
throw; \
} }
namespace spdlog { namespace spdlog {
@ -41,13 +37,15 @@ class SPDLOG_API logger {
public: public:
// Empty logger // Empty logger
explicit logger(std::string name) explicit logger(std::string name)
: name_(std::move(name)) {} : name_(name),
err_handler_(std::move(name)) {}
// Logger with range on sinks // Logger with range on sinks
template <typename It> template <typename It>
logger(std::string name, It begin, It end) logger(std::string name, It begin, It end)
: name_(std::move(name)), : name_(name),
sinks_(begin, end) {} sinks_(begin, end),
err_handler_(std::move(name)) {}
// Logger with single sink // Logger with single sink
logger(std::string name, sink_ptr single_sink) logger(std::string name, sink_ptr single_sink)
@ -175,7 +173,7 @@ private:
std::vector<sink_ptr> sinks_; std::vector<sink_ptr> sinks_;
atomic_level_t level_{level::info}; atomic_level_t level_{level::info};
atomic_level_t flush_level_{level::off}; atomic_level_t flush_level_{level::off};
err_handler custom_err_handler_{nullptr}; details::error_handler err_handler_;
// common implementation for after templated public api has been resolved to format string and // common implementation for after templated public api has been resolved to format string and
// args // args
@ -208,9 +206,6 @@ 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;
// default handler prints the error to stderr
void err_handler_(const std::string &msg);
}; };
} // namespace spdlog } // namespace spdlog

@ -8,6 +8,7 @@
#include <vector> #include <vector>
#include "../details/async_log_msg.h" #include "../details/async_log_msg.h"
#include "../details/error_handler.h"
#include "sink.h" #include "sink.h"
// async_sink is a sink that sends log messages to a dist_sink in a separate thread using a queue. // async_sink is a sink that sends log messages to a dist_sink in a separate thread using a queue.
@ -73,11 +74,11 @@ private:
void backend_loop_(); void backend_loop_();
void backend_log_(const details::log_msg &msg) ; void backend_log_(const details::log_msg &msg) ;
void backend_flush_(); void backend_flush_();
void err_handler_(const std::string &msg);
config config_; config config_;
std::unique_ptr<queue_t> q_; std::unique_ptr<queue_t> q_;
std::thread worker_thread_; std::thread worker_thread_;
details::error_handler err_handler_;
}; };
} // namespace sinks } // namespace sinks

@ -0,0 +1,55 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#include "spdlog/details/error_handler.h"
#include "spdlog/details/os.h"
#include "iostream"
namespace spdlog {
namespace details {
error_handler::error_handler(std::string name)
: name_(std::move(name)) {}
error_handler::error_handler(const error_handler &other) {
std::lock_guard lk{other.mutex_};
name_ = other.name_;
custom_handler_ = other.custom_handler_;
}
error_handler::error_handler(error_handler &&other) noexcept {
std::lock_guard lk{other.mutex_};
name_ = std::move(other.name_);
custom_handler_ = std::move(other.custom_handler_);
}
void error_handler::handle(const source_loc &loc, const std::string &err_msg) const {
std::lock_guard lk{mutex_};
if (custom_handler_) {
custom_handler_(err_msg);
return;
}
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, name_, err_msg);
}
else {
msg = fmt_lib::format("[*** LOGGING ERROR ***] [{}({})] [{}] [{}] {}\n", loc.filename, loc.line, date_buf, name_, err_msg);
}
std::fputs(msg.c_str(), stderr);
}
void error_handler::set_name(const std::string &name) {
std::lock_guard lk{mutex_};
name_ = name;
}
void error_handler::set_custom_handler(err_handler handler) {
std::lock_guard lk{mutex_};
custom_handler_ = std::move(handler);
}
} // namespace details
} // namespace spdlog

@ -2,9 +2,7 @@
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
#include "spdlog/logger.h" #include "spdlog/logger.h"
#include <cstdio> #include <cstdio>
#include <mutex>
#include "spdlog/pattern_formatter.h" #include "spdlog/pattern_formatter.h"
#include "spdlog/sinks/sink.h" #include "spdlog/sinks/sink.h"
@ -17,14 +15,14 @@ logger::logger(const logger &other) noexcept
sinks_(other.sinks_), sinks_(other.sinks_),
level_(other.level_.load(std::memory_order_relaxed)), level_(other.level_.load(std::memory_order_relaxed)),
flush_level_(other.flush_level_.load(std::memory_order_relaxed)), flush_level_(other.flush_level_.load(std::memory_order_relaxed)),
custom_err_handler_(other.custom_err_handler_) {} err_handler_(other.err_handler_) {}
logger::logger(logger &&other) noexcept logger::logger(logger &&other) noexcept
: name_(std::move(other.name_)), : name_(std::move(other.name_)),
sinks_(std::move(other.sinks_)), sinks_(std::move(other.sinks_)),
level_(other.level_.load(std::memory_order_relaxed)), level_(other.level_.load(std::memory_order_relaxed)),
flush_level_(other.flush_level_.load(std::memory_order_relaxed)), flush_level_(other.flush_level_.load(std::memory_order_relaxed)),
custom_err_handler_(std::move(other.custom_err_handler_)) {} err_handler_(std::move(other.err_handler_)) {}
void logger::set_level(level level) { level_.store(level); } void logger::set_level(level level) { level_.store(level); }
@ -62,13 +60,16 @@ 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_; }
// error handler // 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) {
err_handler_.set_custom_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) {
auto cloned = std::make_shared<logger>(*this); auto cloned = std::make_shared<logger>(*this);
cloned->name_ = std::move(logger_name); cloned->name_ = std::move(logger_name);
cloned->err_handler_.set_name(cloned->name_);
return cloned; return cloned;
} }
@ -78,7 +79,7 @@ void logger::flush_() {
try { try {
sink->flush(); sink->flush();
} }
SPDLOG_LOGGER_CATCH(source_loc()) SPDLOG_LOGGER_CATCH(source_loc{})
} }
} }
@ -87,20 +88,4 @@ 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::err_handler_(const std::string &msg) {
if (custom_err_handler_) {
custom_err_handler_(msg);
} else {
using std::chrono::system_clock;
auto now = system_clock::now();
auto tm_time = details::os::localtime(system_clock::to_time_t(now));
char date_buf[64];
std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time);
#if defined(USING_R) && defined(R_R_H) // if in R environment
REprintf("[*** LOG ERROR ***] [%s] [%s] %s\n", date_buf, name().c_str(), msg.c_str());
#else
std::fprintf(stderr, "[*** LOG ERROR ***] [%s] [%s] %s\n", date_buf, name().c_str(), msg.c_str());
#endif
}
}
} // namespace spdlog } // namespace spdlog

@ -15,7 +15,7 @@ namespace spdlog {
namespace sinks { namespace sinks {
async_sink::async_sink(config async_config) async_sink::async_sink(config async_config)
: config_(std::move(async_config)) { : config_(std::move(async_config)), err_handler_("async_sink") {
if (config_.queue_size == 0 || config_.queue_size > max_queue_size) { if (config_.queue_size == 0 || config_.queue_size > max_queue_size) {
throw spdlog_ex("async_sink: invalid queue size"); throw spdlog_ex("async_sink: invalid queue size");
} }
@ -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_(std::string("async log failed: ") + ex.what()); err_handler_.handle(msg.source, std::string("async log failed: ") + ex.what());
} }
} }
} }
@ -118,24 +118,11 @@ void async_sink::backend_flush_() {
try { try {
sink->flush(); sink->flush();
} catch (const std::exception &ex) { } catch (const std::exception &ex) {
err_handler_(std::string("async flush failed: ") + ex.what()); err_handler_.handle(source_loc{}, std::string("async flush failed: ") + ex.what());
} catch (...) { } catch (...) {
err_handler_("Async flush failed with unknown exception"); err_handler_.handle(source_loc{}, "Async flush failed with unknown exception");
} }
} }
} }
void async_sink::err_handler_(const std::string &message) {
using std::chrono::system_clock;
const auto now = system_clock::now();
const auto tm_time = details::os::localtime(system_clock::to_time_t(now));
char date_buf[64];
std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time);
#if defined(USING_R) && defined(R_R_H) // if in R environment
REprintf("[*** LOG ERROR ***] [%s] [%s] %s\n", date_buf, name().c_str(), message.c_str());
#else
std::fprintf(stderr, "[*** LOG ERROR ***] [%s] %s\n", date_buf, message.c_str());
#endif
}
} // namespace sinks } // namespace sinks
} // namespace spdlog } // namespace spdlog

Loading…
Cancel
Save