diff --git a/include/spdlog/common.h b/include/spdlog/common.h index 2d489a10..5ea0a1d3 100644 --- a/include/spdlog/common.h +++ b/include/spdlog/common.h @@ -70,6 +70,12 @@ #define SPDLOG_CONSTEXPR constexpr #endif +#ifdef SPDLOG_LOGGER_NOEXCEPT + #define SPDLOG_COND_NOEXCEPT SPDLOG_NOEXCEPT +#else + #define SPDLOG_COND_NOEXCEPT +#endif + // If building with std::format, can just use constexpr, otherwise if building with fmt // SPDLOG_CONSTEXPR_FUNC needs to be set the same as FMT_CONSTEXPR to avoid situations where // a constexpr function in spdlog could end up calling a non-constexpr function in fmt diff --git a/include/spdlog/logger.h b/include/spdlog/logger.h index f49bdc00..2e415453 100644 --- a/include/spdlog/logger.h +++ b/include/spdlog/logger.h @@ -76,17 +76,20 @@ public: void swap(spdlog::logger &other) SPDLOG_NOEXCEPT; template - void log(source_loc loc, level::level_enum lvl, format_string_t fmt, Args &&...args) { + void log(source_loc loc, level::level_enum lvl, format_string_t fmt, Args &&...args) + SPDLOG_COND_NOEXCEPT { log_(loc, lvl, details::to_string_view(fmt), std::forward(args)...); } template - void log(level::level_enum lvl, format_string_t fmt, Args &&...args) { + void log(level::level_enum lvl, + format_string_t fmt, + Args &&...args) SPDLOG_COND_NOEXCEPT { log(source_loc{}, lvl, fmt, std::forward(args)...); } template - void log(level::level_enum lvl, const T &msg) { + void log(level::level_enum lvl, const T &msg) SPDLOG_COND_NOEXCEPT { log(source_loc{}, lvl, msg); } @@ -94,14 +97,14 @@ public: template ::value, int>::type = 0> - void log(source_loc loc, level::level_enum lvl, const T &msg) { + void log(source_loc loc, level::level_enum lvl, const T &msg) SPDLOG_COND_NOEXCEPT { log(loc, lvl, "{}", msg); } void log(log_clock::time_point log_time, source_loc loc, level::level_enum lvl, - string_view_t msg) { + string_view_t msg) SPDLOG_COND_NOEXCEPT { bool log_enabled = should_log(lvl); bool traceback_enabled = tracer_.enabled(); if (!log_enabled && !traceback_enabled) { @@ -112,7 +115,7 @@ public: log_it_(log_msg, log_enabled, traceback_enabled); } - void log(source_loc loc, level::level_enum lvl, string_view_t msg) { + void log(source_loc loc, level::level_enum lvl, string_view_t msg) SPDLOG_COND_NOEXCEPT { bool log_enabled = should_log(lvl); bool traceback_enabled = tracer_.enabled(); if (!log_enabled && !traceback_enabled) { @@ -123,53 +126,58 @@ public: log_it_(log_msg, log_enabled, traceback_enabled); } - void log(level::level_enum lvl, string_view_t msg) { log(source_loc{}, lvl, msg); } + void log(level::level_enum lvl, string_view_t msg) SPDLOG_COND_NOEXCEPT { + log(source_loc{}, lvl, msg); + } template - void trace(format_string_t fmt, Args &&...args) { + void trace(format_string_t fmt, Args &&...args) SPDLOG_COND_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) SPDLOG_COND_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) SPDLOG_COND_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) SPDLOG_COND_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) SPDLOG_COND_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) SPDLOG_COND_NOEXCEPT { log(level::critical, fmt, std::forward(args)...); } #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT template - void log(source_loc loc, level::level_enum lvl, wformat_string_t fmt, Args &&...args) { + void log(source_loc loc, level::level_enum lvl, wformat_string_t fmt, Args &&...args) + SPDLOG_COND_NOEXCEPT { log_(loc, lvl, details::to_string_view(fmt), std::forward(args)...); } template - void log(level::level_enum lvl, wformat_string_t fmt, Args &&...args) { + void log(level::level_enum lvl, + wformat_string_t fmt, + Args &&...args) SPDLOG_COND_NOEXCEPT { log(source_loc{}, lvl, fmt, std::forward(args)...); } void log(log_clock::time_point log_time, source_loc loc, level::level_enum lvl, - wstring_view_t msg) { + wstring_view_t msg) SPDLOG_COND_NOEXCEPT { bool log_enabled = should_log(lvl); bool traceback_enabled = tracer_.enabled(); if (!log_enabled && !traceback_enabled) { @@ -182,7 +190,7 @@ public: log_it_(log_msg, log_enabled, traceback_enabled); } - void log(source_loc loc, level::level_enum lvl, wstring_view_t msg) { + void log(source_loc loc, level::level_enum lvl, wstring_view_t msg) SPDLOG_COND_NOEXCEPT { bool log_enabled = should_log(lvl); bool traceback_enabled = tracer_.enabled(); if (!log_enabled && !traceback_enabled) { @@ -195,66 +203,68 @@ public: log_it_(log_msg, log_enabled, traceback_enabled); } - void log(level::level_enum lvl, wstring_view_t msg) { log(source_loc{}, lvl, msg); } + void log(level::level_enum lvl, wstring_view_t msg) SPDLOG_COND_NOEXCEPT { + log(source_loc{}, lvl, msg); + } template - void trace(wformat_string_t fmt, Args &&...args) { + void trace(wformat_string_t fmt, Args &&...args) SPDLOG_COND_NOEXCEPT { log(level::trace, fmt, std::forward(args)...); } template - void debug(wformat_string_t fmt, Args &&...args) { + void debug(wformat_string_t fmt, Args &&...args) SPDLOG_COND_NOEXCEPT { log(level::debug, fmt, std::forward(args)...); } template - void info(wformat_string_t fmt, Args &&...args) { + void info(wformat_string_t fmt, Args &&...args) SPDLOG_COND_NOEXCEPT { log(level::info, fmt, std::forward(args)...); } template - void warn(wformat_string_t fmt, Args &&...args) { + void warn(wformat_string_t fmt, Args &&...args) SPDLOG_COND_NOEXCEPT { log(level::warn, fmt, std::forward(args)...); } template - void error(wformat_string_t fmt, Args &&...args) { + void error(wformat_string_t fmt, Args &&...args) SPDLOG_COND_NOEXCEPT { log(level::err, fmt, std::forward(args)...); } template - void critical(wformat_string_t fmt, Args &&...args) { + void critical(wformat_string_t fmt, Args &&...args) SPDLOG_COND_NOEXCEPT { log(level::critical, fmt, std::forward(args)...); } #endif template - void trace(const T &msg) { + void trace(const T &msg) SPDLOG_COND_NOEXCEPT { log(level::trace, msg); } template - void debug(const T &msg) { + void debug(const T &msg) SPDLOG_COND_NOEXCEPT { log(level::debug, msg); } template - void info(const T &msg) { + void info(const T &msg) SPDLOG_COND_NOEXCEPT { log(level::info, msg); } template - void warn(const T &msg) { + void warn(const T &msg) SPDLOG_COND_NOEXCEPT { log(level::warn, msg); } template - void error(const T &msg) { + void error(const T &msg) SPDLOG_COND_NOEXCEPT { log(level::err, msg); } template - void critical(const T &msg) { + void critical(const T &msg) SPDLOG_COND_NOEXCEPT { log(level::critical, msg); } diff --git a/include/spdlog/spdlog.h b/include/spdlog/spdlog.h index a8afbcec..e90f8170 100644 --- a/include/spdlog/spdlog.h +++ b/include/spdlog/spdlog.h @@ -144,52 +144,52 @@ template inline void log(source_loc source, level::level_enum lvl, format_string_t fmt, - Args &&...args) { + Args &&...args) SPDLOG_COND_NOEXCEPT { default_logger_raw()->log(source, lvl, fmt, std::forward(args)...); } template -inline void log(level::level_enum lvl, format_string_t fmt, Args &&...args) { +inline void log(level::level_enum lvl, format_string_t fmt, Args &&...args) SPDLOG_COND_NOEXCEPT { default_logger_raw()->log(source_loc{}, lvl, fmt, std::forward(args)...); } template -inline void trace(format_string_t fmt, Args &&...args) { +inline void trace(format_string_t fmt, Args &&...args) SPDLOG_COND_NOEXCEPT { default_logger_raw()->trace(fmt, std::forward(args)...); } template -inline void debug(format_string_t fmt, Args &&...args) { +inline void debug(format_string_t fmt, Args &&...args) SPDLOG_COND_NOEXCEPT { default_logger_raw()->debug(fmt, std::forward(args)...); } template -inline void info(format_string_t fmt, Args &&...args) { +inline void info(format_string_t fmt, Args &&...args) SPDLOG_COND_NOEXCEPT { default_logger_raw()->info(fmt, std::forward(args)...); } template -inline void warn(format_string_t fmt, Args &&...args) { +inline void warn(format_string_t fmt, Args &&...args) SPDLOG_COND_NOEXCEPT { default_logger_raw()->warn(fmt, std::forward(args)...); } template -inline void error(format_string_t fmt, Args &&...args) { +inline void error(format_string_t fmt, Args &&...args) SPDLOG_COND_NOEXCEPT { default_logger_raw()->error(fmt, std::forward(args)...); } template -inline void critical(format_string_t fmt, Args &&...args) { +inline void critical(format_string_t fmt, Args &&...args) SPDLOG_COND_NOEXCEPT { default_logger_raw()->critical(fmt, std::forward(args)...); } template -inline void log(source_loc source, level::level_enum lvl, const T &msg) { +inline void log(source_loc source, level::level_enum lvl, const T &msg) SPDLOG_COND_NOEXCEPT { default_logger_raw()->log(source, lvl, msg); } template -inline void log(level::level_enum lvl, const T &msg) { +inline void log(level::level_enum lvl, const T &msg) SPDLOG_COND_NOEXCEPT { default_logger_raw()->log(lvl, msg); } @@ -198,73 +198,73 @@ template inline void log(source_loc source, level::level_enum lvl, wformat_string_t fmt, - Args &&...args) { + Args &&...args) SPDLOG_COND_NOEXCEPT { default_logger_raw()->log(source, lvl, fmt, std::forward(args)...); } template -inline void log(level::level_enum lvl, wformat_string_t fmt, Args &&...args) { +inline void log(level::level_enum lvl, wformat_string_t fmt, Args &&...args) SPDLOG_COND_NOEXCEPT { default_logger_raw()->log(source_loc{}, lvl, fmt, std::forward(args)...); } template -inline void trace(wformat_string_t fmt, Args &&...args) { +inline void trace(wformat_string_t fmt, Args &&...args) SPDLOG_COND_NOEXCEPT { default_logger_raw()->trace(fmt, std::forward(args)...); } template -inline void debug(wformat_string_t fmt, Args &&...args) { +inline void debug(wformat_string_t fmt, Args &&...args) SPDLOG_COND_NOEXCEPT { default_logger_raw()->debug(fmt, std::forward(args)...); } template -inline void info(wformat_string_t fmt, Args &&...args) { +inline void info(wformat_string_t fmt, Args &&...args) SPDLOG_COND_NOEXCEPT { default_logger_raw()->info(fmt, std::forward(args)...); } template -inline void warn(wformat_string_t fmt, Args &&...args) { +inline void warn(wformat_string_t fmt, Args &&...args) SPDLOG_COND_NOEXCEPT { default_logger_raw()->warn(fmt, std::forward(args)...); } template -inline void error(wformat_string_t fmt, Args &&...args) { +inline void error(wformat_string_t fmt, Args &&...args) SPDLOG_COND_NOEXCEPT { default_logger_raw()->error(fmt, std::forward(args)...); } template -inline void critical(wformat_string_t fmt, Args &&...args) { +inline void critical(wformat_string_t fmt, Args &&...args) SPDLOG_COND_NOEXCEPT { default_logger_raw()->critical(fmt, std::forward(args)...); } #endif template -inline void trace(const T &msg) { +inline void trace(const T &msg) SPDLOG_COND_NOEXCEPT { default_logger_raw()->trace(msg); } template -inline void debug(const T &msg) { +inline void debug(const T &msg) SPDLOG_COND_NOEXCEPT { default_logger_raw()->debug(msg); } template -inline void info(const T &msg) { +inline void info(const T &msg) SPDLOG_COND_NOEXCEPT { default_logger_raw()->info(msg); } template -inline void warn(const T &msg) { +inline void warn(const T &msg) SPDLOG_COND_NOEXCEPT { default_logger_raw()->warn(msg); } template -inline void error(const T &msg) { +inline void error(const T &msg) SPDLOG_COND_NOEXCEPT { default_logger_raw()->error(msg); } template -inline void critical(const T &msg) { +inline void critical(const T &msg) SPDLOG_COND_NOEXCEPT { default_logger_raw()->critical(msg); } diff --git a/include/spdlog/tweakme.h b/include/spdlog/tweakme.h index a47a9076..0f5c50ab 100644 --- a/include/spdlog/tweakme.h +++ b/include/spdlog/tweakme.h @@ -139,3 +139,16 @@ // # define SPDLOG_FUNCTION __FUNCTION__ // #endif /////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to declare all output functionality in spdlog namespace and on spdlog::logger as +// noexcept. This may allow the compiler to perform further optimizations when logging is performed. +// Additionally, static analysis can assume that logging never throws, which may be useful +// when logging is used in inherently exception-unsafe places such as destructors. +// +// Note that this will result in program termination if the registered error handler +// throws. It might also interact badly with mechanisms that inject exceptions into running +// code (such as the pthread_cancel implementation of NPTL). +// +// #define SPDLOG_LOGGER_NOEXCEPT +/////////////////////////////////////////////////////////////////////////////// diff --git a/tests/test_errors.cpp b/tests/test_errors.cpp index 7dde919d..2d5cfcf4 100644 --- a/tests/test_errors.cpp +++ b/tests/test_errors.cpp @@ -39,11 +39,16 @@ TEST_CASE("custom_error_handler", "[errors]") { spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG); auto logger = spdlog::create("logger", filename, true); logger->flush_on(spdlog::level::info); - logger->set_error_handler([=](const std::string &) { throw custom_ex(); }); + bool error_seen = false; + logger->set_error_handler([&](const std::string &) { error_seen = true; }); logger->info("Good message #1"); + REQUIRE_FALSE(error_seen); - REQUIRE_THROWS_AS(logger->info(SPDLOG_FMT_RUNTIME("Bad format msg {} {}"), "xxx"), custom_ex); + logger->info(SPDLOG_FMT_RUNTIME("Bad format msg {} {}"), "xxx"); + REQUIRE(error_seen); + error_seen = false; logger->info("Good message #2"); + REQUIRE_FALSE(error_seen); require_message_count(SIMPLE_LOG, 2); } #endif @@ -51,8 +56,10 @@ TEST_CASE("custom_error_handler", "[errors]") { TEST_CASE("default_error_handler2", "[errors]") { spdlog::drop_all(); auto logger = spdlog::create("failed_logger"); - logger->set_error_handler([=](const std::string &) { throw custom_ex(); }); - REQUIRE_THROWS_AS(logger->info("Some message"), custom_ex); + bool error_seen = false; + logger->set_error_handler([&](const std::string &) { error_seen = true; }); + logger->info("Some message"); + REQUIRE(error_seen); } TEST_CASE("flush_error_handler", "[errors]") { @@ -62,6 +69,15 @@ TEST_CASE("flush_error_handler", "[errors]") { REQUIRE_THROWS_AS(logger->flush(), custom_ex); } +#if !defined(SPDLOG_LOGGER_NOEXCEPT) +TEST_CASE("custom_throw_error_handler", "[errors]") { + spdlog::drop_all(); + auto logger = spdlog::create("failed_logger"); + logger->set_error_handler([=](const std::string &) { throw custom_ex(); }); + REQUIRE_THROWS_AS(logger->info("Some message"), custom_ex); +} +#endif + #if !defined(SPDLOG_USE_STD_FORMAT) TEST_CASE("async_error_handler", "[errors]") { prepare_logdir();