From 84a4f56eaeec8acfb96b4ee635a5e413e596d4b9 Mon Sep 17 00:00:00 2001 From: Barrett Date: Tue, 9 May 2017 18:31:44 -0700 Subject: [PATCH 1/9] Allow compiler to select an strerror_r stringify On Alpine (and potentially other systems) that don't identify their runtime correctly there is an issue with the string conversion Specifically, alpine linux and musl where the errno_to_string is incorrectly called. To fix this I have added two overloaded functions and use auto err to allow the compiler to detect the actual types returned and call the correct method for conversion --- include/spdlog/details/os.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/include/spdlog/details/os.h b/include/spdlog/details/os.h index 4d9f60a5..afb56971 100644 --- a/include/spdlog/details/os.h +++ b/include/spdlog/details/os.h @@ -364,6 +364,17 @@ inline std::string filename_to_str(const filename_t& filename) } #endif +inline std::string errno_to_string(char [256], char* res) { + return std::string(res); +} + +inline std::string errno_to_string(char buf[256], int res) { + if (res == 0) { + return std::string(buf); + } else { + return "Unknown error"; + } +} // Return errno string (thread safe) inline std::string errno_str(int err_num) @@ -386,7 +397,8 @@ inline std::string errno_str(int err_num) return "Unknown error"; #else // gnu version (might not use the given buf, so its retval pointer must be used) - return std::string(strerror_r(err_num, buf, buf_size)); + auto err = strerror_r(err_num, buf, buf_size); // let compiler choose type + return errno_to_string(buf, err); // use overloading to select correct stringify function #endif } From 8ee6d38501529957d1183969a9068505d825cf81 Mon Sep 17 00:00:00 2001 From: Sidyhe Date: Sat, 1 Apr 2017 23:37:16 +0800 Subject: [PATCH 2/9] add wide string to utf8 string support --- include/spdlog/details/logger_impl.h | 57 ++++++++++++++++++++++++++++ include/spdlog/logger.h | 10 +++++ include/spdlog/tweakme.h | 6 +++ 3 files changed, 73 insertions(+) diff --git a/include/spdlog/details/logger_impl.h b/include/spdlog/details/logger_impl.h index c712b27a..cf65f31b 100644 --- a/include/spdlog/details/logger_impl.h +++ b/include/spdlog/details/logger_impl.h @@ -195,6 +195,63 @@ inline void spdlog::logger::critical(const T& msg) log(level::critical, msg); } +#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT +#include + +template +inline void spdlog::logger::log(level::level_enum lvl, const wchar_t* msg) +{ + std::wstring_convert > conv; + + log(lvl, conv.to_bytes(msg)); +} + +template +inline void spdlog::logger::log(level::level_enum lvl, const wchar_t* fmt, const Args&... args) +{ + fmt::WMemoryWriter wWriter; + + wWriter.write(fmt, args...); + log(lvl, wWriter.c_str()); +} + +template +inline void spdlog::logger::trace(const wchar_t* fmt, const Args&... args) +{ + log(level::trace, fmt, args...); +} + +template +inline void spdlog::logger::debug(const wchar_t* fmt, const Args&... args) +{ + log(level::debug, fmt, args...); +} + +template +inline void spdlog::logger::info(const wchar_t* fmt, const Args&... args) +{ + log(level::info, fmt, args...); +} + + +template +inline void spdlog::logger::warn(const wchar_t* fmt, const Args&... args) +{ + log(level::warn, fmt, args...); +} + +template +inline void spdlog::logger::error(const wchar_t* fmt, const Args&... args) +{ + log(level::err, fmt, args...); +} + +template +inline void spdlog::logger::critical(const wchar_t* fmt, const Args&... args) +{ + log(level::critical, fmt, args...); +} +#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT diff --git a/include/spdlog/logger.h b/include/spdlog/logger.h index 58b4841a..0c864f9e 100644 --- a/include/spdlog/logger.h +++ b/include/spdlog/logger.h @@ -43,6 +43,16 @@ public: template void warn(const char* fmt, const Arg1&, const Args&... args); template void error(const char* fmt, const Arg1&, const Args&... args); template void critical(const char* fmt, const Arg1&, const Args&... args); +#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT + template void log(level::level_enum lvl, const wchar_t* msg); + template void log(level::level_enum lvl, const wchar_t* fmt, const Args&... args); + template void trace(const wchar_t* fmt, const Args&... args); + template void debug(const wchar_t* fmt, const Args&... args); + template void info(const wchar_t* fmt, const Args&... args); + template void warn(const wchar_t* fmt, const Args&... args); + template void error(const wchar_t* fmt, const Args&... args); + template void critical(const wchar_t* fmt, const Args&... args); +#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT template void log(level::level_enum lvl, const T&); template void trace(const T&); diff --git a/include/spdlog/tweakme.h b/include/spdlog/tweakme.h index bde27967..c167c716 100644 --- a/include/spdlog/tweakme.h +++ b/include/spdlog/tweakme.h @@ -101,6 +101,12 @@ /////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to enable wchar_t support (convert to utf8) +// +// #define SPDLOG_WCHAR_TO_UTF8_SUPPORT +/////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// // Uncomment to prevent child processes from inheriting log file descriptors // From 0aeaf9e28e080c4cc1754571370b9e0654c7137f Mon Sep 17 00:00:00 2001 From: Alexander Zilberkant Date: Thu, 11 May 2017 23:52:42 +0300 Subject: [PATCH 3/9] add an option to warn about discarded messages when using async_logger with async_overflow_policy::discard_log_msg each discarded message will be counted and warning will be printed by the worker thread this new feature is disabled by default - as it may have a performance hit when discarding messages --- include/spdlog/details/async_log_helper.h | 42 ++++++++++++++++++----- include/spdlog/tweakme.h | 7 ++++ 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/include/spdlog/details/async_log_helper.h b/include/spdlog/details/async_log_helper.h index 1e454550..2b5e382e 100644 --- a/include/spdlog/details/async_log_helper.h +++ b/include/spdlog/details/async_log_helper.h @@ -27,6 +27,7 @@ #include #include #include +#include namespace spdlog { @@ -185,6 +186,9 @@ private: // wait until the queue is empty void wait_empty_q(); + // counter for messages discarded due to queue overflow + std::atomic _discarded_msg_count; + }; } } @@ -211,7 +215,8 @@ inline spdlog::details::async_log_helper::async_log_helper( _worker_warmup_cb(worker_warmup_cb), _flush_interval_ms(flush_interval_ms), _worker_teardown_cb(worker_teardown_cb), - _worker_thread(&async_log_helper::worker_loop, this) + _worker_thread(&async_log_helper::worker_loop, this), + _discarded_msg_count(0) {} // Send to the worker thread termination message(level=off) @@ -237,16 +242,24 @@ inline void spdlog::details::async_log_helper::log(const details::log_msg& msg) inline void spdlog::details::async_log_helper::push_msg(details::async_log_helper::async_msg&& new_msg) { - if (!_q.enqueue(std::move(new_msg)) && _overflow_policy != async_overflow_policy::discard_log_msg) + if (!_q.enqueue(std::move(new_msg))) { - auto last_op_time = details::os::now(); - auto now = last_op_time; - do + if (_overflow_policy != async_overflow_policy::discard_log_msg) { - now = details::os::now(); - sleep_or_yield(now, last_op_time); + auto last_op_time = details::os::now(); + auto now = last_op_time; + do + { + now = details::os::now(); + sleep_or_yield(now, last_op_time); + } while (!_q.enqueue(std::move(new_msg))); + } + else + { +#if defined(SPDLOG_ASYNC_COUNT_DISCARDED_MSG) + _discarded_msg_count++; +#endif } - while (!_q.enqueue(std::move(new_msg))); } } @@ -305,6 +318,19 @@ inline bool spdlog::details::async_log_helper::process_next_msg(log_clock::time_ break; default: +#if defined(SPDLOG_ASYNC_COUNT_DISCARDED_MSG) + unsigned int num_of_discarded_messages = _discarded_msg_count.exchange(0); + if (num_of_discarded_messages) + { + log_msg discarded_warning_msg(&incoming_async_msg.logger_name, level::warn); + discarded_warning_msg.raw << "Dropped " << num_of_discarded_messages << " messages"; + for (auto &s : _sinks) + { + s->log(discarded_warning_msg); + } + } +#endif + log_msg incoming_log_msg; incoming_async_msg.fill_log_msg(incoming_log_msg); _formatter->format(incoming_log_msg); diff --git a/include/spdlog/tweakme.h b/include/spdlog/tweakme.h index bde27967..0f3c2763 100644 --- a/include/spdlog/tweakme.h +++ b/include/spdlog/tweakme.h @@ -114,3 +114,10 @@ // // #define SPDLOG_FINAL final /////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment count in print warning message about number of dropped messages. +// Only relevant for async_logger with async_overflow_policy::discard_log_msg +// +#define SPDLOG_ASYNC_COUNT_DISCARDED_MSG +/////////////////////////////////////////////////////////////////////////////// From 42258a1059645e2c264a0caa8aa737d2e13d0c80 Mon Sep 17 00:00:00 2001 From: Alexander Zilberkant Date: Sat, 13 May 2017 00:53:57 +0300 Subject: [PATCH 4/9] move discarded message handling to a dedicated function fix - formatter new discarded message --- include/spdlog/details/async_log_helper.h | 29 ++++++++++++++--------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/include/spdlog/details/async_log_helper.h b/include/spdlog/details/async_log_helper.h index 2b5e382e..c5a147ec 100644 --- a/include/spdlog/details/async_log_helper.h +++ b/include/spdlog/details/async_log_helper.h @@ -189,6 +189,9 @@ private: // counter for messages discarded due to queue overflow std::atomic _discarded_msg_count; + // handle discarded messages + void handle_discarded_msg(const std::string& logger_name); + }; } } @@ -319,16 +322,7 @@ inline bool spdlog::details::async_log_helper::process_next_msg(log_clock::time_ default: #if defined(SPDLOG_ASYNC_COUNT_DISCARDED_MSG) - unsigned int num_of_discarded_messages = _discarded_msg_count.exchange(0); - if (num_of_discarded_messages) - { - log_msg discarded_warning_msg(&incoming_async_msg.logger_name, level::warn); - discarded_warning_msg.raw << "Dropped " << num_of_discarded_messages << " messages"; - for (auto &s : _sinks) - { - s->log(discarded_warning_msg); - } - } + handle_discarded_msg(incoming_async_msg.logger_name); #endif log_msg incoming_log_msg; @@ -415,5 +409,18 @@ inline void spdlog::details::async_log_helper::set_error_handler(spdlog::log_err _err_handler = err_handler; } - +inline void spdlog::details::async_log_helper::handle_discarded_msg(const std::string& logger_name) +{ + unsigned int num_of_discarded_messages = _discarded_msg_count.exchange(0); + if (num_of_discarded_messages) + { + log_msg discarded_warning_msg(&logger_name, level::warn); + discarded_warning_msg.raw << "Discarded " << num_of_discarded_messages << " messages - logger queue overflow"; + _formatter->format(discarded_warning_msg); + for (auto &s : _sinks) + { + s->log(discarded_warning_msg); + } + } +} From 0f25b25b20908a89495809b062cef71920d887e5 Mon Sep 17 00:00:00 2001 From: Alexander Zilberkant Date: Sat, 13 May 2017 01:01:28 +0300 Subject: [PATCH 5/9] add async_logger tests cover discarded messages use-case --- tests/CMakeLists.txt | 2 +- tests/async_logger.cpp | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 tests/async_logger.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ce275ccb..22329b4e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -10,7 +10,7 @@ find_package(Threads) add_library(catch INTERFACE) target_include_directories(catch INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) -file(GLOB catch_tests LIST_DIRECTORIES false RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp) +file(GLOB catch_tests LIST_DIRECTORIES false RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp *.h *.hpp) add_executable(catch_tests ${catch_tests}) target_link_libraries(catch_tests spdlog ${CMAKE_THREAD_LIBS_INIT}) diff --git a/tests/async_logger.cpp b/tests/async_logger.cpp new file mode 100644 index 00000000..bcfb1ca6 --- /dev/null +++ b/tests/async_logger.cpp @@ -0,0 +1,38 @@ + +#include + +#include "includes.h" +#include "../include/spdlog/common.h" +#include "../include/spdlog/tweakme.h" + + +TEST_CASE("async_logging_overflow ", "[async_logging]") +{ + std::string filename = "logs/async_log_overflow.txt"; + auto sink = std::make_shared(filename, true); + auto logger = std::make_shared( + "overflow_logger", + sink, + 2, // queue size + spdlog::async_overflow_policy::discard_log_msg + ); + for (int i = 0; i < 8; i++) { + logger->info("Message #{}", i); + } + logger->flush(); + logger.reset(); + std::string the_log = file_contents(filename); +#if defined(SPDLOG_ASYNC_COUNT_DISCARDED_MSG) + std::cout << the_log << std::endl; + REQUIRE(the_log.find("Dropped 6 messages") != std::string::npos); +#endif +} + + + + + + + + + From 2b008efb0696e7cdd5271f28824e9652b80a28d6 Mon Sep 17 00:00:00 2001 From: Alexander Zilberkant Date: Sat, 13 May 2017 01:10:58 +0300 Subject: [PATCH 6/9] disable SPDLOG_ASYNC_COUNT_DISCARDED_MSG --- include/spdlog/tweakme.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/spdlog/tweakme.h b/include/spdlog/tweakme.h index 0f3c2763..99b8f4dd 100644 --- a/include/spdlog/tweakme.h +++ b/include/spdlog/tweakme.h @@ -119,5 +119,5 @@ // Uncomment count in print warning message about number of dropped messages. // Only relevant for async_logger with async_overflow_policy::discard_log_msg // -#define SPDLOG_ASYNC_COUNT_DISCARDED_MSG +// #define SPDLOG_ASYNC_COUNT_DISCARDED_MSG /////////////////////////////////////////////////////////////////////////////// From 13199034f0c8c670dd653882622f413927a32401 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sat, 13 May 2017 01:25:48 +0300 Subject: [PATCH 7/9] Update tweakme.h --- include/spdlog/tweakme.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/spdlog/tweakme.h b/include/spdlog/tweakme.h index e568d301..f1d25be6 100644 --- a/include/spdlog/tweakme.h +++ b/include/spdlog/tweakme.h @@ -122,7 +122,7 @@ /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// -// Uncomment count in print warning message about number of dropped messages. +// Uncomment to count and print warning message about number of dropped messages. // Only relevant for async_logger with async_overflow_policy::discard_log_msg // // #define SPDLOG_ASYNC_COUNT_DISCARDED_MSG From 6547675e4376ae821d99adb4a1bd80c117a175ee Mon Sep 17 00:00:00 2001 From: Alexander Zilberkant Date: Mon, 15 May 2017 20:07:24 +0300 Subject: [PATCH 8/9] Revert "Merge pull request #441 from alzix/count_discarded" This reverts commit 038733345a44aca8ce3baf1ce19e57d7844e22ee, reversing changes made to 862d2f6f3549aa64404b2a3fbfd1b0a637f7e093. --- include/spdlog/details/async_log_helper.h | 51 ++++------------------- include/spdlog/tweakme.h | 7 ---- tests/async_logger.cpp | 38 ----------------- 3 files changed, 9 insertions(+), 87 deletions(-) delete mode 100644 tests/async_logger.cpp diff --git a/include/spdlog/details/async_log_helper.h b/include/spdlog/details/async_log_helper.h index c5a147ec..1e454550 100644 --- a/include/spdlog/details/async_log_helper.h +++ b/include/spdlog/details/async_log_helper.h @@ -27,7 +27,6 @@ #include #include #include -#include namespace spdlog { @@ -186,12 +185,6 @@ private: // wait until the queue is empty void wait_empty_q(); - // counter for messages discarded due to queue overflow - std::atomic _discarded_msg_count; - - // handle discarded messages - void handle_discarded_msg(const std::string& logger_name); - }; } } @@ -218,8 +211,7 @@ inline spdlog::details::async_log_helper::async_log_helper( _worker_warmup_cb(worker_warmup_cb), _flush_interval_ms(flush_interval_ms), _worker_teardown_cb(worker_teardown_cb), - _worker_thread(&async_log_helper::worker_loop, this), - _discarded_msg_count(0) + _worker_thread(&async_log_helper::worker_loop, this) {} // Send to the worker thread termination message(level=off) @@ -245,24 +237,16 @@ inline void spdlog::details::async_log_helper::log(const details::log_msg& msg) inline void spdlog::details::async_log_helper::push_msg(details::async_log_helper::async_msg&& new_msg) { - if (!_q.enqueue(std::move(new_msg))) + if (!_q.enqueue(std::move(new_msg)) && _overflow_policy != async_overflow_policy::discard_log_msg) { - if (_overflow_policy != async_overflow_policy::discard_log_msg) + auto last_op_time = details::os::now(); + auto now = last_op_time; + do { - auto last_op_time = details::os::now(); - auto now = last_op_time; - do - { - now = details::os::now(); - sleep_or_yield(now, last_op_time); - } while (!_q.enqueue(std::move(new_msg))); - } - else - { -#if defined(SPDLOG_ASYNC_COUNT_DISCARDED_MSG) - _discarded_msg_count++; -#endif + now = details::os::now(); + sleep_or_yield(now, last_op_time); } + while (!_q.enqueue(std::move(new_msg))); } } @@ -321,10 +305,6 @@ inline bool spdlog::details::async_log_helper::process_next_msg(log_clock::time_ break; default: -#if defined(SPDLOG_ASYNC_COUNT_DISCARDED_MSG) - handle_discarded_msg(incoming_async_msg.logger_name); -#endif - log_msg incoming_log_msg; incoming_async_msg.fill_log_msg(incoming_log_msg); _formatter->format(incoming_log_msg); @@ -409,18 +389,5 @@ inline void spdlog::details::async_log_helper::set_error_handler(spdlog::log_err _err_handler = err_handler; } -inline void spdlog::details::async_log_helper::handle_discarded_msg(const std::string& logger_name) -{ - unsigned int num_of_discarded_messages = _discarded_msg_count.exchange(0); - if (num_of_discarded_messages) - { - log_msg discarded_warning_msg(&logger_name, level::warn); - discarded_warning_msg.raw << "Discarded " << num_of_discarded_messages << " messages - logger queue overflow"; - _formatter->format(discarded_warning_msg); - for (auto &s : _sinks) - { - s->log(discarded_warning_msg); - } - } -} + diff --git a/include/spdlog/tweakme.h b/include/spdlog/tweakme.h index f1d25be6..c167c716 100644 --- a/include/spdlog/tweakme.h +++ b/include/spdlog/tweakme.h @@ -120,10 +120,3 @@ // // #define SPDLOG_FINAL final /////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// Uncomment to count and print warning message about number of dropped messages. -// Only relevant for async_logger with async_overflow_policy::discard_log_msg -// -// #define SPDLOG_ASYNC_COUNT_DISCARDED_MSG -/////////////////////////////////////////////////////////////////////////////// diff --git a/tests/async_logger.cpp b/tests/async_logger.cpp deleted file mode 100644 index bcfb1ca6..00000000 --- a/tests/async_logger.cpp +++ /dev/null @@ -1,38 +0,0 @@ - -#include - -#include "includes.h" -#include "../include/spdlog/common.h" -#include "../include/spdlog/tweakme.h" - - -TEST_CASE("async_logging_overflow ", "[async_logging]") -{ - std::string filename = "logs/async_log_overflow.txt"; - auto sink = std::make_shared(filename, true); - auto logger = std::make_shared( - "overflow_logger", - sink, - 2, // queue size - spdlog::async_overflow_policy::discard_log_msg - ); - for (int i = 0; i < 8; i++) { - logger->info("Message #{}", i); - } - logger->flush(); - logger.reset(); - std::string the_log = file_contents(filename); -#if defined(SPDLOG_ASYNC_COUNT_DISCARDED_MSG) - std::cout << the_log << std::endl; - REQUIRE(the_log.find("Dropped 6 messages") != std::string::npos); -#endif -} - - - - - - - - - From 8329d97d9027651022bea278f3ddf864f60d5630 Mon Sep 17 00:00:00 2001 From: Alexander Zilberkant Date: Sat, 13 May 2017 18:57:56 +0300 Subject: [PATCH 9/9] fix indentation --- include/spdlog/details/async_log_helper.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/include/spdlog/details/async_log_helper.h b/include/spdlog/details/async_log_helper.h index c5a147ec..f174955a 100644 --- a/include/spdlog/details/async_log_helper.h +++ b/include/spdlog/details/async_log_helper.h @@ -57,19 +57,19 @@ class async_log_helper ~async_msg() = default; -async_msg(async_msg&& other) SPDLOG_NOEXCEPT: - logger_name(std::move(other.logger_name)), - level(std::move(other.level)), - time(std::move(other.time)), - thread_id(other.thread_id), - txt(std::move(other.txt)), - msg_type(std::move(other.msg_type)) + async_msg(async_msg&& other) SPDLOG_NOEXCEPT: + logger_name(std::move(other.logger_name)), + level(std::move(other.level)), + time(std::move(other.time)), + thread_id(other.thread_id), + txt(std::move(other.txt)), + msg_type(std::move(other.msg_type)) {} async_msg(async_msg_type m_type): - level(level::info), - thread_id(0), - msg_type(m_type) + level(level::info), + thread_id(0), + msg_type(m_type) {} async_msg& operator=(async_msg&& other) SPDLOG_NOEXCEPT