From ffbb35368d415959b6e959822f85d5996a45832e Mon Sep 17 00:00:00 2001 From: gabime Date: Mon, 6 Jan 2025 10:35:08 +0200 Subject: [PATCH] noexcept --- include/spdlog/details/err_helper.h | 4 +- include/spdlog/logger.h | 63 +++++++++++++++-------------- src/details/err_helper.cpp | 45 ++++++++++++--------- src/logger.cpp | 14 +++---- tests/test_errors.cpp | 13 +++--- 5 files changed, 73 insertions(+), 66 deletions(-) diff --git a/include/spdlog/details/err_helper.h b/include/spdlog/details/err_helper.h index bb6434b3..6ae8815a 100644 --- a/include/spdlog/details/err_helper.h +++ b/include/spdlog/details/err_helper.h @@ -14,8 +14,8 @@ namespace details { class SPDLOG_API err_helper { err_handler custom_err_handler_; public: - void handle_ex(const std::string& origin, const source_loc& loc, const std::exception& ex) const; - void handle_unknown_ex(const std::string& origin, const source_loc& loc) const; + 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; void set_err_handler(err_handler handler); }; diff --git a/include/spdlog/logger.h b/include/spdlog/logger.h index f4c19e2c..c4fc18dc 100644 --- a/include/spdlog/logger.h +++ b/include/spdlog/logger.h @@ -48,81 +48,81 @@ public: ~logger() = default; template - void log(const source_loc &loc, level lvl, format_string_t fmt, Args &&...args) { + void log(const source_loc &loc, level lvl, format_string_t fmt, Args &&...args) noexcept { if (should_log(lvl)) { log_with_format_(loc, lvl, fmt, std::forward(args)...); } } template - void log(level lvl, format_string_t fmt, Args &&...args) { + void log(level lvl, format_string_t fmt, Args &&...args) noexcept { if (should_log(lvl)) { log_with_format_(source_loc{}, lvl, fmt, std::forward(args)...); } } // log with no format string, just string message - void log(const source_loc &loc, level lvl, string_view_t msg) { + void log(const source_loc &loc, level lvl, string_view_t msg) noexcept { if (should_log(lvl)) { sink_it_(details::log_msg(loc, name_, lvl, msg)); } } - void log(level lvl, string_view_t msg) { + void log(level lvl, string_view_t msg) noexcept { if (should_log(lvl)) { sink_it_(details::log_msg(source_loc{}, name_, lvl, msg)); } } // support for custom time - void log(log_clock::time_point log_time, const source_loc &loc, level lvl, string_view_t msg) { + void log(log_clock::time_point log_time, const source_loc &loc, level lvl, string_view_t msg) noexcept { if (should_log(lvl)) { sink_it_(details::log_msg(log_time, loc, name_, lvl, msg)); } } template - void trace(format_string_t fmt, Args &&...args) { + void trace(format_string_t fmt, Args &&...args) noexcept { log(level::trace, fmt, std::forward(args)...); } template - void debug(format_string_t fmt, Args &&...args) { + void debug(format_string_t fmt, Args &&...args) noexcept { log(level::debug, fmt, std::forward(args)...); } template - void info(format_string_t fmt, Args &&...args) { + void info(format_string_t fmt, Args &&...args) noexcept { log(level::info, fmt, std::forward(args)...); } template - void warn(format_string_t fmt, Args &&...args) { + void warn(format_string_t fmt, Args &&...args) noexcept { log(level::warn, fmt, std::forward(args)...); } template - void error(format_string_t fmt, Args &&...args) { + void error(format_string_t fmt, Args &&...args) noexcept { log(level::err, fmt, std::forward(args)...); } template - void critical(format_string_t fmt, Args &&...args) { + void critical(format_string_t fmt, Args &&...args) noexcept { log(level::critical, fmt, std::forward(args)...); } // log functions with no format string, just string - void trace(string_view_t msg) { log(level::trace, msg); } - void debug(string_view_t msg) { log(level::debug, msg); } - void info(string_view_t msg) { log(level::info, msg); } - void warn(string_view_t msg) { log(level::warn, msg); } - void error(string_view_t msg) { log(level::err, msg); } - void critical(string_view_t msg) { log(level::critical, msg); } + void trace(string_view_t msg) noexcept { log(level::trace, msg); } + void debug(string_view_t msg) noexcept { log(level::debug, msg); } + void info(string_view_t msg) noexcept { log(level::info, msg); } + void warn(string_view_t msg) noexcept { log(level::warn, msg); } + void error(string_view_t msg) noexcept { log(level::err, msg); } + void critical(string_view_t msg) noexcept { log(level::critical, msg); } // return true if logging is enabled for the given level. - [[nodiscard]] bool should_log(level msg_level) const { return msg_level >= level_.load(std::memory_order_relaxed); } + [[nodiscard]] bool should_log(level msg_level) const noexcept { return msg_level >= level_.load(std::memory_order_relaxed); } // return true if the given message should be flushed - [[nodiscard]] bool should_flush(const details::log_msg &msg) const { + [[nodiscard]] bool should_flush(const details::log_msg &msg) const noexcept { return (msg.log_level >= flush_level_.load(std::memory_order_relaxed)) && (msg.log_level != level::off); } @@ -130,10 +130,10 @@ public: void set_level(level level); // return the active log level - [[nodiscard]] level log_level() const; + [[nodiscard]] level log_level() const noexcept; // return the name of the logger - [[nodiscard]] const std::string &name() const; + [[nodiscard]] const std::string &name() const noexcept; // set formatting for the sinks in this logger. // each sink will get a separate instance of the formatter object. @@ -146,15 +146,15 @@ public: void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local); // flush functions - void flush(); - void flush_on(level level); - [[nodiscard]] level flush_level() const; + void flush() noexcept; + void flush_on(level level) noexcept; + [[nodiscard]] level flush_level() const noexcept; // sinks - [[nodiscard]] const std::vector &sinks() const; - [[nodiscard]] std::vector &sinks(); + [[nodiscard]] const std::vector &sinks() const noexcept; + [[nodiscard]] std::vector &sinks() noexcept; - // error handler + // error handler. default is err_handler that prints the error to stderr. void set_error_handler(err_handler); // create new logger with same sinks and configuration. @@ -170,7 +170,10 @@ private: // common implementation for after templated public api has been resolved to format string and // args template - void log_with_format_(const source_loc &loc, const level lvl, const format_string_t &format_string, Args &&...args) { + void log_with_format_(const source_loc &loc, + const level lvl, + const format_string_t &format_string, + Args &&...args) noexcept { assert(should_log(lvl)); try { memory_buf_t buf; @@ -184,7 +187,7 @@ private: } // log the given message (if the given log level is high enough) - void sink_it_(const details::log_msg &msg) { + void sink_it_(const details::log_msg &msg) noexcept { assert(should_log(msg.log_level)); for (auto &sink : sinks_) { if (sink->should_log(msg.log_level)) { @@ -202,7 +205,7 @@ private: flush_(); } } - void flush_(); + void flush_() noexcept; }; } // namespace spdlog diff --git a/src/details/err_helper.cpp b/src/details/err_helper.cpp index 153cf988..430f27c0 100644 --- a/src/details/err_helper.cpp +++ b/src/details/err_helper.cpp @@ -1,8 +1,9 @@ // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -#include "iostream" #include "spdlog/details/err_helper.h" + +#include "iostream" #include "spdlog/details/os.h" namespace spdlog { @@ -10,31 +11,35 @@ namespace details { // 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 { - if (custom_err_handler_) { - custom_err_handler_(ex.what()); - return; +void err_helper::handle_ex(const std::string &origin, const source_loc &loc, const std::exception &ex) const noexcept { + try { + if (custom_err_handler_) { + custom_err_handler_(ex.what()); + return; + } + 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); + std::string msg; + if (loc.empty()) { + msg = fmt_lib::format("[*** LOG ERROR ***] [{}] [{}] {}\n", date_buf, origin, ex.what()); + } else { + msg = fmt_lib::format("[*** LOG ERROR ***] [{}({})] [{}] [{}] {}\n", loc.filename, loc.line, date_buf, origin, + ex.what()); + } + 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()); + } catch (...) { // catch all exceptions + std::fprintf(stderr, "[*** LOG ERROR ***] [%s] caught unknown exception during error handler\n", origin.c_str()); } - 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); - std::string msg; - if (loc.empty()) { - msg = fmt_lib::format("[*** LOG ERROR ***] [{}] [{}] {}\n", date_buf, origin, ex.what()); - } else { - msg = fmt_lib::format("[*** LOG ERROR ***] [{}({})] [{}] [{}] {}\n", loc.filename, loc.line, date_buf, origin, - ex.what()); - } - std::fputs(msg.c_str(), stderr); } -void err_helper::handle_unknown_ex(const std::string &origin, const source_loc &loc) const { +void err_helper::handle_unknown_ex(const std::string &origin, const source_loc &loc) const 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) { custom_err_handler_ = std::move(handler); } } // namespace details } // namespace spdlog diff --git a/src/logger.cpp b/src/logger.cpp index 21158770..0d685cc9 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -25,7 +25,7 @@ logger::logger(logger &&other) noexcept void logger::set_level(level level) { level_.store(level); } -level logger::log_level() const { return level_.load(std::memory_order_relaxed); } +level logger::log_level() const noexcept { return level_.load(std::memory_order_relaxed); } const std::string &logger::name() const { return name_; } @@ -48,16 +48,16 @@ void logger::set_pattern(std::string pattern, pattern_time_type time_type) { } // flush functions -void logger::flush() { flush_(); } +void logger::flush() noexcept { flush_(); } -void logger::flush_on(level level) { flush_level_.store(level); } +void logger::flush_on(level level) noexcept { flush_level_.store(level); } -level logger::flush_level() const { return flush_level_.load(std::memory_order_relaxed); } +level logger::flush_level() const noexcept { return flush_level_.load(std::memory_order_relaxed); } // sinks -const std::vector &logger::sinks() const { return sinks_; } +const std::vector &logger::sinks() const noexcept { return sinks_; } -std::vector &logger::sinks() { return sinks_; } +std::vector &logger::sinks() noexcept { return sinks_; } // custom error handler void logger::set_error_handler(err_handler handler) { err_helper_.set_err_handler(std::move(handler)); } @@ -70,7 +70,7 @@ std::shared_ptr logger::clone(std::string logger_name) { } // private/protected methods -void logger::flush_() { +void logger::flush_() noexcept{ for (auto &sink : sinks_) { try { sink->flush(); diff --git a/tests/test_errors.cpp b/tests/test_errors.cpp index aa7d0935..9985f4e8 100644 --- a/tests/test_errors.cpp +++ b/tests/test_errors.cpp @@ -34,32 +34,31 @@ TEST_CASE("default_error_handler", "[errors]") { TEST_CASE("custom_error_handler", "[errors]") { prepare_logdir(); - auto logger = spdlog::create("test-error", log_filename); + auto logger = spdlog::create("test-format-error", log_filename); logger->flush_on(spdlog::level::info); logger->set_error_handler([=](const std::string & msg) { REQUIRE(msg == "argument not found"); - throw custom_ex(); }); logger->info("Good message #1"); - REQUIRE_THROWS_AS(logger->info(SPDLOG_FMT_RUNTIME("Bad format msg {} {}"), "xxx"), custom_ex); + REQUIRE_NOTHROW(logger->info(SPDLOG_FMT_RUNTIME("Bad format msg {} {}"), "xxx")); logger->info("Good message #2"); require_message_count(log_filename, 2); } TEST_CASE("default_error_handler2", "[errors]") { - auto logger = std::make_shared("failed_logger", std::make_shared()); + auto logger = std::make_shared("test-failing-sink", std::make_shared()); logger->set_error_handler([=](const std::string &msg) { REQUIRE(msg == log_err_msg); throw custom_ex(); }); - REQUIRE_THROWS_AS(logger->info("Some message"), custom_ex); + REQUIRE_NOTHROW(logger->info("Some message")); } TEST_CASE("flush_error_handler", "[errors]") { - auto logger = spdlog::create("failed_logger"); + auto logger = spdlog::create("test-failing-sink"); logger->set_error_handler([=](const std::string &msg) { REQUIRE(msg == flush_err_msg); throw custom_ex(); }); - REQUIRE_THROWS_AS(logger->flush(), custom_ex); + REQUIRE_NOTHROW(logger->flush()); }