diff --git a/CMakeLists.txt b/CMakeLists.txt index b3a75253..a3594b58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,6 +82,7 @@ option(SPDLOG_SANITIZE_ADDRESS "Enable address sanitizer in tests" OFF) option(SPDLOG_BUILD_WARNINGS "Enable compiler warnings" OFF) # install options +option(SPDLOG_SYSTEM_INCLUDES "Include as system headers (skip for clang-tidy)." OFF) option(SPDLOG_INSTALL "Generate the install target" ${SPDLOG_MASTER_PROJECT}) option(SPDLOG_USE_STD_FORMAT "Use std::format instead of fmt library." OFF) option(SPDLOG_FMT_EXTERNAL "Use external fmt library instead of bundled" OFF) @@ -170,8 +171,14 @@ endif() add_library(spdlog::spdlog ALIAS spdlog) +set(SPDLOG_INCLUDES_LEVEL "") +if(SPDLOG_SYSTEM_INCLUDES) + set(SPDLOG_INCLUDES_LEVEL "SYSTEM") +endif() + + target_compile_definitions(spdlog PUBLIC SPDLOG_COMPILED_LIB) -target_include_directories(spdlog PUBLIC "$" +target_include_directories(spdlog ${SPDLOG_INCLUDES_LEVEL} PUBLIC "$" "$") target_link_libraries(spdlog PUBLIC Threads::Threads) spdlog_enable_warnings(spdlog) @@ -190,7 +197,7 @@ endif() add_library(spdlog_header_only INTERFACE) add_library(spdlog::spdlog_header_only ALIAS spdlog_header_only) -target_include_directories(spdlog_header_only INTERFACE "$" +target_include_directories(spdlog_header_only ${SPDLOG_INCLUDES_LEVEL} INTERFACE "$" "$") target_link_libraries(spdlog_header_only INTERFACE Threads::Threads) diff --git a/include/spdlog/details/backtracer-inl.h b/include/spdlog/details/backtracer-inl.h index 2621c8f7..40eba408 100644 --- a/include/spdlog/details/backtracer-inl.h +++ b/include/spdlog/details/backtracer-inl.h @@ -54,6 +54,12 @@ SPDLOG_INLINE void backtracer::push_back(const log_msg &msg) messages_.push_back(log_msg_buffer{msg}); } +SPDLOG_INLINE bool backtracer::empty() const +{ + std::lock_guard lock{mutex_}; + return messages_.empty(); +} + // pop all items in the q and apply the given fun on each of them. SPDLOG_INLINE void backtracer::foreach_pop(std::function fun) { diff --git a/include/spdlog/details/backtracer.h b/include/spdlog/details/backtracer.h index b336ee77..13785d85 100644 --- a/include/spdlog/details/backtracer.h +++ b/include/spdlog/details/backtracer.h @@ -32,6 +32,7 @@ public: void disable(); bool enabled() const; void push_back(const log_msg &msg); + bool empty() const; // pop all items in the q and apply the given fun on each of them. void foreach_pop(std::function fun); diff --git a/include/spdlog/details/mpmc_blocking_q.h b/include/spdlog/details/mpmc_blocking_q.h index 785180c1..101ea8c0 100644 --- a/include/spdlog/details/mpmc_blocking_q.h +++ b/include/spdlog/details/mpmc_blocking_q.h @@ -49,7 +49,7 @@ public: push_cv_.notify_one(); } - // try to dequeue item. if no item found. wait up to timeout and try again + // dequeue with a timeout. // Return true, if succeeded dequeue item, false otherwise bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration) { @@ -66,6 +66,18 @@ public: return true; } + // blocking dequeue without a timeout. + void dequeue(T &popped_item) + { + { + std::unique_lock lock(queue_mutex_); + push_cv_.wait(lock, [this] { return !this->q_.empty(); }); + popped_item = std::move(q_.front()); + q_.pop_front(); + } + pop_cv_.notify_one(); + } + #else // apparently mingw deadlocks if the mutex is released before cv.notify_one(), // so release the mutex at the very end each function. @@ -87,7 +99,7 @@ public: push_cv_.notify_one(); } - // try to dequeue item. if no item found. wait up to timeout and try again + // dequeue with a timeout. // Return true, if succeeded dequeue item, false otherwise bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration) { @@ -102,6 +114,16 @@ public: return true; } + // blocking dequeue without a timeout. + void dequeue(T &popped_item) + { + std::unique_lock lock(queue_mutex_); + push_cv_.wait(lock, [this] { return !this->q_.empty(); }); + popped_item = std::move(q_.front()); + q_.pop_front(); + pop_cv_.notify_one(); + } + #endif size_t overrun_counter() diff --git a/include/spdlog/details/os-inl.h b/include/spdlog/details/os-inl.h index b9bab53c..7f22335f 100644 --- a/include/spdlog/details/os-inl.h +++ b/include/spdlog/details/os-inl.h @@ -236,8 +236,8 @@ SPDLOG_INLINE size_t filesize(FILE *f) # else int fd = ::fileno(f); # endif -// 64 bits(but not in osx or cygwin, where fstat64 is deprecated) -# if (defined(__linux__) || defined(__sun) || defined(_AIX)) && (defined(__LP64__) || defined(_LP64)) +// 64 bits(but not in osx, linux/musl or cygwin, where fstat64 is deprecated) +# if ((defined(__linux__) && defined(__GLIBC__)) || defined(__sun) || defined(_AIX)) && (defined(__LP64__) || defined(_LP64)) struct stat64 st; if (::fstat64(fd, &st) == 0) { diff --git a/include/spdlog/details/tcp_client.h b/include/spdlog/details/tcp_client.h index 0daff0eb..45883f34 100644 --- a/include/spdlog/details/tcp_client.h +++ b/include/spdlog/details/tcp_client.h @@ -16,6 +16,7 @@ #include #include #include +#include #include diff --git a/include/spdlog/details/thread_pool-inl.h b/include/spdlog/details/thread_pool-inl.h index 369f30fe..dbd424ff 100644 --- a/include/spdlog/details/thread_pool-inl.h +++ b/include/spdlog/details/thread_pool-inl.h @@ -108,11 +108,7 @@ void SPDLOG_INLINE thread_pool::worker_loop_() bool SPDLOG_INLINE thread_pool::process_next_msg_() { async_msg incoming_async_msg; - bool dequeued = q_.dequeue_for(incoming_async_msg, std::chrono::seconds(10)); - if (!dequeued) - { - return true; - } + q_.dequeue(incoming_async_msg); switch (incoming_async_msg.msg_type) { diff --git a/include/spdlog/logger-inl.h b/include/spdlog/logger-inl.h index 411f2cb5..ff82db4c 100644 --- a/include/spdlog/logger-inl.h +++ b/include/spdlog/logger-inl.h @@ -210,7 +210,7 @@ SPDLOG_INLINE void logger::flush_() SPDLOG_INLINE void logger::dump_backtrace_() { using details::log_msg; - if (tracer_.enabled()) + if (tracer_.enabled() && !tracer_.empty()) { sink_it_(log_msg{name(), level::info, "****************** Backtrace Start ******************"}); tracer_.foreach_pop([this](const log_msg &msg) { this->sink_it_(msg); }); diff --git a/include/spdlog/sinks/dup_filter_sink.h b/include/spdlog/sinks/dup_filter_sink.h index 1a4fb348..3c96549c 100644 --- a/include/spdlog/sinks/dup_filter_sink.h +++ b/include/spdlog/sinks/dup_filter_sink.h @@ -20,7 +20,7 @@ // #include // // int main() { -// auto dup_filter = std::make_shared(std::chrono::seconds(5)); +// auto dup_filter = std::make_shared(std::chrono::seconds(5), level::info); // dup_filter->add_sink(std::make_shared()); // spdlog::logger l("logger", dup_filter); // l.info("Hello"); @@ -41,8 +41,9 @@ class dup_filter_sink : public dist_sink { public: template - explicit dup_filter_sink(std::chrono::duration max_skip_duration) + explicit dup_filter_sink(std::chrono::duration max_skip_duration, level::level_enum notification_level = level::info) : max_skip_duration_{max_skip_duration} + , log_level_{notification_level} {} protected: @@ -50,6 +51,7 @@ protected: log_clock::time_point last_msg_time_; std::string last_msg_payload_; size_t skip_counter_ = 0; + level::level_enum log_level_; void sink_it_(const details::log_msg &msg) override { @@ -67,7 +69,7 @@ protected: auto msg_size = ::snprintf(buf, sizeof(buf), "Skipped %u duplicate messages..", static_cast(skip_counter_)); if (msg_size > 0 && static_cast(msg_size) < sizeof(buf)) { - details::log_msg skipped_msg{msg.source, msg.logger_name, level::info, string_view_t{buf, static_cast(msg_size)}}; + details::log_msg skipped_msg{msg.source, msg.logger_name, log_level_, string_view_t{buf, static_cast(msg_size)}}; dist_sink::sink_it_(skipped_msg); } } diff --git a/include/spdlog/sinks/msvc_sink.h b/include/spdlog/sinks/msvc_sink.h index 09008b78..708b35ac 100644 --- a/include/spdlog/sinks/msvc_sink.h +++ b/include/spdlog/sinks/msvc_sink.h @@ -26,13 +26,13 @@ class msvc_sink : public base_sink { public: msvc_sink() = default; - msvc_sink(bool check_ebugger_present) - : check_debbugger_present_{check_ebugger_present} {}; + msvc_sink(bool check_debugger_present) + : check_debugger_present_{check_debugger_present} {}; protected: void sink_it_(const details::log_msg &msg) override { - if (check_debbugger_present_ && !IsDebuggerPresent()) + if (check_debugger_present_ && !IsDebuggerPresent()) { return; } @@ -44,7 +44,7 @@ protected: void flush_() override {} - bool check_debbugger_present_ = true; + bool check_debugger_present_ = true; }; using msvc_sink_mt = msvc_sink; diff --git a/tests/includes.h b/tests/includes.h index 16394440..100984cc 100644 --- a/tests/includes.h +++ b/tests/includes.h @@ -32,4 +32,5 @@ #include "spdlog/sinks/ostream_sink.h" #include "spdlog/sinks/rotating_file_sink.h" #include "spdlog/sinks/stdout_color_sinks.h" +#include "spdlog/sinks/msvc_sink.h" #include "spdlog/pattern_formatter.h" diff --git a/tests/test_backtrace.cpp b/tests/test_backtrace.cpp index 9504b82b..6cf9ec55 100644 --- a/tests/test_backtrace.cpp +++ b/tests/test_backtrace.cpp @@ -31,6 +31,19 @@ TEST_CASE("bactrace1", "[bactrace]") REQUIRE(test_sink->lines()[7] == "****************** Backtrace End ********************"); } +TEST_CASE("bactrace-empty", "[bactrace]") +{ + using spdlog::sinks::test_sink_st; + auto test_sink = std::make_shared(); + size_t backtrace_size = 5; + + spdlog::logger logger("test-backtrace", test_sink); + logger.set_pattern("%v"); + logger.enable_backtrace(backtrace_size); + logger.dump_backtrace(); + REQUIRE(test_sink->lines().size() == 0); +} + TEST_CASE("bactrace-async", "[bactrace]") { using spdlog::sinks::test_sink_mt; diff --git a/tests/test_mpmc_q.cpp b/tests/test_mpmc_q.cpp index 3b8aec36..1540dcc8 100644 --- a/tests/test_mpmc_q.cpp +++ b/tests/test_mpmc_q.cpp @@ -43,6 +43,26 @@ TEST_CASE("dequeue-empty-wait", "[mpmc_blocking_q]") REQUIRE(delta_ms <= wait_ms + tolerance_wait); } +TEST_CASE("dequeue-full-nowait", "[mpmc_blocking_q]") +{ + spdlog::details::mpmc_blocking_queue q(1); + q.enqueue(42); + + int item = 0; + q.dequeue_for(item, milliseconds::zero()); + REQUIRE(item == 42); +} + +TEST_CASE("dequeue-full-wait", "[mpmc_blocking_q]") +{ + spdlog::details::mpmc_blocking_queue q(1); + q.enqueue(42); + + int item = 0; + q.dequeue(item); + REQUIRE(item == 42); +} + TEST_CASE("enqueue_nowait", "[mpmc_blocking_q]") { @@ -95,12 +115,12 @@ TEST_CASE("full_queue", "[mpmc_blocking_q]") for (int i = 1; i < static_cast(q_size); i++) { int item = -1; - q.dequeue_for(item, milliseconds(0)); + q.dequeue(item); REQUIRE(item == i); } // last item pushed has overridden the oldest. int item = -1; - q.dequeue_for(item, milliseconds(0)); + q.dequeue(item); REQUIRE(item == 123456); }