From be942e0a2dc92ab8f50c7353baf995bd99dc2388 Mon Sep 17 00:00:00 2001 From: gabime Date: Fri, 17 Jan 2025 16:42:06 +0200 Subject: [PATCH] Limit error handler rate to 1/sec --- include/spdlog/details/err_helper.h | 14 ++++++++++---- src/details/err_helper.cpp | 28 +++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/include/spdlog/details/err_helper.h b/include/spdlog/details/err_helper.h index 3b6bdcaa..f8285660 100644 --- a/include/spdlog/details/err_helper.h +++ b/include/spdlog/details/err_helper.h @@ -4,18 +4,24 @@ #pragma once #include -#include +#include #include +#include #include "spdlog/common.h" -// by default, prints the error to stderr, thread safe +// by default, prints the error to stderr, at max rate of 1/sec thread safe namespace spdlog { namespace details { class SPDLOG_API err_helper { err_handler custom_err_handler_; + std::chrono::steady_clock::time_point last_report_time_; + std::mutex mutex_; public: - void handle_ex(const std::string& origin, const source_loc& loc, const std::exception& ex) const noexcept; - void handle_unknown_ex(const std::string& origin, const source_loc& loc) const noexcept; + err_helper() = default; + err_helper(const err_helper& other); + err_helper(err_helper&& other); + void handle_ex(const std::string& origin, const source_loc& loc, const std::exception& ex) noexcept; + void handle_unknown_ex(const std::string& origin, const source_loc& loc) noexcept; void set_err_handler(err_handler handler); }; } // namespace details diff --git a/src/details/err_helper.cpp b/src/details/err_helper.cpp index 430f27c0..c2c79938 100644 --- a/src/details/err_helper.cpp +++ b/src/details/err_helper.cpp @@ -3,20 +3,34 @@ #include "spdlog/details/err_helper.h" -#include "iostream" #include "spdlog/details/os.h" namespace spdlog { namespace details { +err_helper::err_helper(const err_helper &other) + : custom_err_handler_(other.custom_err_handler_), + last_report_time_(other.last_report_time_) {} + +err_helper::err_helper(err_helper &&other) + : custom_err_handler_(std::move(other.custom_err_handler_)), + last_report_time_(other.last_report_time_) {}; + // Prints error to stderr with source location (if available). A stderr sink is not used because reaching // this point might indicate a problem with the logging system itself so we use fputs() directly. -void err_helper::handle_ex(const std::string &origin, const source_loc &loc, const std::exception &ex) const noexcept { +void err_helper::handle_ex(const std::string &origin, const source_loc &loc, const std::exception &ex) noexcept { + std::lock_guard lock(mutex_); try { if (custom_err_handler_) { custom_err_handler_(ex.what()); return; } + + const auto now = std::chrono::steady_clock::now(); + if (now - last_report_time_ < std::chrono::seconds(1)) { + return; + } + last_report_time_ = now; const auto tm_time = os::localtime(); char date_buf[32]; std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time); @@ -29,17 +43,21 @@ void err_helper::handle_ex(const std::string &origin, const source_loc &loc, con } std::fputs(msg.c_str(), stderr); } catch (const std::exception &handler_ex) { - std::fprintf(stderr, "[*** LOG ERROR ***] [%s] caught exception during error handler: %s\n", origin.c_str(), handler_ex.what()); + std::fprintf(stderr, "[*** LOG ERROR ***] [%s] caught exception during error handler: %s\n", origin.c_str(), + handler_ex.what()); } catch (...) { // catch all exceptions std::fprintf(stderr, "[*** LOG ERROR ***] [%s] caught unknown exception during error handler\n", origin.c_str()); } } -void err_helper::handle_unknown_ex(const std::string &origin, const source_loc &loc) const noexcept { +void err_helper::handle_unknown_ex(const std::string &origin, const source_loc &loc) noexcept { handle_ex(origin, loc, std::runtime_error("unknown exception")); } -void err_helper::set_err_handler(err_handler handler) { custom_err_handler_ = std::move(handler); } +void err_helper::set_err_handler(err_handler handler) { + std::lock_guard lock(mutex_); + custom_err_handler_ = std::move(handler); +} } // namespace details } // namespace spdlog