From 8512000f36c2ad9b1265bd78b11c0b34151d6be4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gy=C3=B6rgy=20Katona?= Date: Fri, 9 Dec 2022 09:25:17 +0100 Subject: [PATCH 01/24] Unnecessary backtrace begin/end logs (#2568) * add empty getter function to tracer * add unit test to check empty tracer Co-authored-by: Gyorgy Katona --- include/spdlog/details/backtracer-inl.h | 6 ++++++ include/spdlog/details/backtracer.h | 1 + include/spdlog/logger-inl.h | 2 +- tests/test_backtrace.cpp | 13 +++++++++++++ 4 files changed, 21 insertions(+), 1 deletion(-) 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/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/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; From dd0d0f68c4e331eaf65953d4f21579ccef7a0d87 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sat, 10 Dec 2022 00:25:31 +0200 Subject: [PATCH 02/24] Added compile mscv_sink.h to tests --- tests/includes.h | 1 + 1 file changed, 1 insertion(+) 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" From ff88b13c356935acf8e51d3799aa1a065dde40a2 Mon Sep 17 00:00:00 2001 From: NaDDu Date: Sat, 10 Dec 2022 07:28:28 +0900 Subject: [PATCH 03/24] Fixed variable name (#2573) * fixed variable name * Changed the variable name from check_debbugger_present_ to check_debugger_present_. Co-authored-by: cpp --- include/spdlog/sinks/msvc_sink.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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; From edc51df1bdad8667b628999394a1e7c4dc6f3658 Mon Sep 17 00:00:00 2001 From: Darby Payne Date: Sun, 11 Dec 2022 00:58:02 -0800 Subject: [PATCH 04/24] Feature/add system includes option (#2575) * Adding system includes option * Adding system includes option --- CMakeLists.txt | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a66e8405..61d21781 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) From a4e99175753d9fcdd7dcd803bb9b340107b73492 Mon Sep 17 00:00:00 2001 From: Alok Priyadarshi Date: Fri, 30 Dec 2022 05:20:10 -0800 Subject: [PATCH 05/24] feat(mpmc_blocking_q): add blocking dequeue without timeout (#2588) Use the new blocking dequeue to avoid unnecessarily waking up the thread pool every 10s. Fixes #2587 by replacing std::condition_variable::wait_for with std::condition_variable::wait as a workaroung for gcc 11.3 issue 101978. Co-authored-by: Alok Priyadarshi --- include/spdlog/details/mpmc_blocking_q.h | 26 ++++++++++++++++++++++-- include/spdlog/details/thread_pool-inl.h | 6 +----- tests/test_mpmc_q.cpp | 24 ++++++++++++++++++++-- 3 files changed, 47 insertions(+), 9 deletions(-) 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/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/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); } From 3c93f7690a184847a277a1c40704aa1ee17dcba4 Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Sun, 1 Jan 2023 00:52:46 +0300 Subject: [PATCH 06/24] fix build: fix for freebsd (#2590) The build error was: include/spdlog/details/tcp_client.h:106:31: error: use of undeclared identifier 'IPPROTO_TCP' --- include/spdlog/details/tcp_client.h | 1 + 1 file changed, 1 insertion(+) 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 From 287a00d364990edbb621fe5e392aeb550135fb96 Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Tue, 3 Jan 2023 09:54:50 -0800 Subject: [PATCH 07/24] Do not use LFS64 functions on linux/musl (#2589) On musl, off_t is 64bit always ( even on 32bit platforms ), therefore using LFS64 funcitons is not needed on such platforms. Moreover, musl has stopped providing aliases for these functions [1] which means it wont compile on newer musl systems. Therefore only use it on 32bit glibc/linux platforms and exclude musl like cygwin or OSX [1] https://git.musl-libc.org/cgit/musl/commit/?id=246f1c811448f37a44b41cd8df8d0ef9736d95f4 Signed-off-by: Khem Raj --- include/spdlog/details/os-inl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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) { From 85a009ad643a827ff8115452c739e9e8158b505f Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 10 Jan 2023 00:12:03 +0100 Subject: [PATCH 08/24] Support newlib C library configurations without tm_gmtoff field (#2600) Newlib C library (https://sourceware.org/newlib/) has a configuration option to add tm_gmtoff field to the tm structure. Not all the platforms supported by newlib enable this option, and spdlog doesn't compile on such platforms due to missing tm_gmtoff field. Fix this by checking for `__NEWLIB__` and `__TM_GMTOFF` and enabling calculate_gmt_offset. --- include/spdlog/details/os-inl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/spdlog/details/os-inl.h b/include/spdlog/details/os-inl.h index 7f22335f..2ac8cc3f 100644 --- a/include/spdlog/details/os-inl.h +++ b/include/spdlog/details/os-inl.h @@ -286,7 +286,7 @@ SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm) return offset; #else -# if defined(sun) || defined(__sun) || defined(_AIX) || (!defined(_BSD_SOURCE) && !defined(_GNU_SOURCE)) +# if defined(sun) || defined(__sun) || defined(_AIX) || (defined(__NEWLIB__) && !defined(__TM_GMTOFF)) || (!defined(_BSD_SOURCE) && !defined(_GNU_SOURCE)) // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris struct helper { From 0b9ff5210a95149b1cfcb8a66bf53d34f2b6d30d Mon Sep 17 00:00:00 2001 From: Arnar Bjarni Arnarson Date: Mon, 9 Jan 2023 23:25:01 +0000 Subject: [PATCH 09/24] Fix type of event id in win_eventlog_sink (#2598) Co-authored-by: Arnar Bjarni Arnarson --- include/spdlog/sinks/win_eventlog_sink.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/spdlog/sinks/win_eventlog_sink.h b/include/spdlog/sinks/win_eventlog_sink.h index 2f2aacb5..def4b135 100644 --- a/include/spdlog/sinks/win_eventlog_sink.h +++ b/include/spdlog/sinks/win_eventlog_sink.h @@ -210,7 +210,7 @@ private: HANDLE hEventLog_{NULL}; internal::sid_t current_user_sid_; std::string source_; - WORD event_id_; + DWORD event_id_; HANDLE event_log_handle() { @@ -258,7 +258,7 @@ protected: void flush_() override {} public: - win_eventlog_sink(std::string const &source, WORD event_id = 1000 /* according to mscoree.dll */) + win_eventlog_sink(std::string const &source, DWORD event_id = 1000 /* according to mscoree.dll */) : source_(source) , event_id_(event_id) { From 6df64c6c34997e298a81150b9ce55c440c6f503f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robin=20Lind=C3=A9n?= Date: Tue, 10 Jan 2023 00:25:26 +0100 Subject: [PATCH 10/24] Fix -Wshadow warnings in spdlog::sinks::dist_sink (#2599) This is similar to fbba6dff20b0c04a0694515168914a62161999d7 but fixes a few member functions missed in that commit. --- include/spdlog/sinks/dist_sink.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/spdlog/sinks/dist_sink.h b/include/spdlog/sinks/dist_sink.h index 065048ad..7ec3a2ec 100644 --- a/include/spdlog/sinks/dist_sink.h +++ b/include/spdlog/sinks/dist_sink.h @@ -31,16 +31,16 @@ public: dist_sink(const dist_sink &) = delete; dist_sink &operator=(const dist_sink &) = delete; - void add_sink(std::shared_ptr sink) + void add_sink(std::shared_ptr sub_sink) { std::lock_guard lock(base_sink::mutex_); - sinks_.push_back(sink); + sinks_.push_back(sub_sink); } - void remove_sink(std::shared_ptr sink) + void remove_sink(std::shared_ptr sub_sink) { std::lock_guard lock(base_sink::mutex_); - sinks_.erase(std::remove(sinks_.begin(), sinks_.end(), sink), sinks_.end()); + sinks_.erase(std::remove(sinks_.begin(), sinks_.end(), sub_sink), sinks_.end()); } void set_sinks(std::vector> sinks) From c92d12bc18127a2e976e2ca780fc44f94e62ae18 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Thu, 12 Jan 2023 10:12:30 +0100 Subject: [PATCH 11/24] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 46adb9f0..b0c7fe5e 100644 --- a/README.md +++ b/README.md @@ -146,7 +146,7 @@ void daily_example() ```c++ // Debug messages can be stored in a ring buffer instead of being logged immediately. // This is useful in order to display debug logs only when really needed (e.g. when error happens). -// When needed, call dump_backtrace() to see them. +// When needed, call dump_backtrace() to dump them to your log. spdlog::enable_backtrace(32); // Store the latest 32 messages in a buffer. Older messages will be dropped. // or my_logger->enable_backtrace(32).. From 05e3a73b162705b37ed464ceb4644addfb03f25b Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Thu, 12 Jan 2023 10:15:58 +0100 Subject: [PATCH 12/24] Update README.md --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b0c7fe5e..7cc4db9e 100644 --- a/README.md +++ b/README.md @@ -148,15 +148,14 @@ void daily_example() // This is useful in order to display debug logs only when really needed (e.g. when error happens). // When needed, call dump_backtrace() to dump them to your log. -spdlog::enable_backtrace(32); // Store the latest 32 messages in a buffer. Older messages will be dropped. +spdlog::enable_backtrace(32); // Store the latest 32 messages in a buffer. // or my_logger->enable_backtrace(32).. for(int i = 0; i < 100; i++) { spdlog::debug("Backtrace message {}", i); // not logged yet.. } -// e.g. if some error happened: +// e.g. if some has error happened: spdlog::dump_backtrace(); // log them now! show the last 32 messages - // or my_logger->dump_backtrace(32).. ``` From 5a63426d1cb9d7e16dbe6b6779e041012513202e Mon Sep 17 00:00:00 2001 From: albert-github Date: Sun, 15 Jan 2023 12:41:30 +0100 Subject: [PATCH 13/24] Spelling corrections (#2606) Spelling corrections v1.x --- README.md | 2 +- include/spdlog/details/tcp_client.h | 2 +- include/spdlog/sinks/android_sink.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7cc4db9e..b98a920b 100644 --- a/README.md +++ b/README.md @@ -375,7 +375,7 @@ $ ./example #### Log file open/close event handlers ```c++ // You can get callbacks from spdlog before/after log file has been opened or closed. -// This is useful for cleanup procedures or for adding someting the start/end of the log files. +// This is useful for cleanup procedures or for adding something the start/end of the log files. void file_events_example() { // pass the spdlog::file_event_handlers to file sinks for open/close log file notifications diff --git a/include/spdlog/details/tcp_client.h b/include/spdlog/details/tcp_client.h index 45883f34..e4d7a48e 100644 --- a/include/spdlog/details/tcp_client.h +++ b/include/spdlog/details/tcp_client.h @@ -111,7 +111,7 @@ public: #endif #if !defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL) -# error "tcp_sink would raise SIGPIPE since niether SO_NOSIGPIPE nor MSG_NOSIGNAL are available" +# error "tcp_sink would raise SIGPIPE since neither SO_NOSIGPIPE nor MSG_NOSIGNAL are available" #endif } diff --git a/include/spdlog/sinks/android_sink.h b/include/spdlog/sinks/android_sink.h index 07dbeea8..8e79638b 100644 --- a/include/spdlog/sinks/android_sink.h +++ b/include/spdlog/sinks/android_sink.h @@ -74,7 +74,7 @@ protected: private: // There might be liblog versions used, that do not support __android_log_buf_write. So we only compile and link against - // __android_log_buf_write, if user explicitely provides a non-default log buffer. Otherwise, when using the default log buffer, always + // __android_log_buf_write, if user explicitly provides a non-default log buffer. Otherwise, when using the default log buffer, always // log via __android_log_write. template typename std::enable_if(log_id::LOG_ID_MAIN), int>::type android_log(int prio, const char *tag, const char *text) @@ -139,4 +139,4 @@ inline std::shared_ptr android_logger_st(const std::string &logger_name, } // namespace spdlog -#endif // __ANDROID__ \ No newline at end of file +#endif // __ANDROID__ From f29f369a12c701db27e816c6762e914863e8e951 Mon Sep 17 00:00:00 2001 From: espkk Date: Sun, 15 Jan 2023 15:33:40 +0200 Subject: [PATCH 14/24] Add sync to file_helper (#2343) --- include/spdlog/details/file_helper-inl.h | 8 ++++++++ include/spdlog/details/file_helper.h | 1 + include/spdlog/details/os-inl.h | 16 ++++++++++++++-- include/spdlog/details/os.h | 4 ++++ 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/include/spdlog/details/file_helper-inl.h b/include/spdlog/details/file_helper-inl.h index d4528711..3c45d8c0 100644 --- a/include/spdlog/details/file_helper-inl.h +++ b/include/spdlog/details/file_helper-inl.h @@ -90,6 +90,14 @@ SPDLOG_INLINE void file_helper::flush() } } +SPDLOG_INLINE void file_helper::sync() +{ + if(!os::fsync(fd_)) + { + throw_spdlog_ex("Failed to fsync file " + os::filename_to_str(filename_), errno); + } +} + SPDLOG_INLINE void file_helper::close() { if (fd_ != nullptr) diff --git a/include/spdlog/details/file_helper.h b/include/spdlog/details/file_helper.h index 0f5988b9..f42a5eb1 100644 --- a/include/spdlog/details/file_helper.h +++ b/include/spdlog/details/file_helper.h @@ -26,6 +26,7 @@ public: void open(const filename_t &fname, bool truncate = false); void reopen(bool truncate); void flush(); + void sync(); void close(); void write(const memory_buf_t &buf); size_t size() const; diff --git a/include/spdlog/details/os-inl.h b/include/spdlog/details/os-inl.h index 2ac8cc3f..42acf3fe 100644 --- a/include/spdlog/details/os-inl.h +++ b/include/spdlog/details/os-inl.h @@ -23,9 +23,10 @@ #ifdef _WIN32 -# include // _get_osfhandle and _isatty support -# include // _get_pid support +# include // for _get_osfhandle, _isatty, _fileno +# include // for _get_pid # include +# include // for FlushFileBuffers # ifdef __MINGW32__ # include @@ -601,6 +602,17 @@ std::string SPDLOG_INLINE getenv(const char *field) #endif } +// Do fsync by FILE descriptor +// Return true on success +SPDLOG_INLINE bool fsync(FILE *fd) +{ +#ifdef _WIN32 + return FlushFileBuffers(reinterpret_cast(_get_osfhandle(_fileno(fd)))) != 0; +#else + return ::fsync(fileno(fd)) == 0; +#endif +} + } // namespace os } // namespace details } // namespace spdlog diff --git a/include/spdlog/details/os.h b/include/spdlog/details/os.h index b154bc47..742482d0 100644 --- a/include/spdlog/details/os.h +++ b/include/spdlog/details/os.h @@ -109,6 +109,10 @@ SPDLOG_API bool create_dir(const filename_t &path); // return empty string if field not found SPDLOG_API std::string getenv(const char *field); +// Do fsync by FILE descriptor +// Return true on success +SPDLOG_API bool fsync(FILE * fd); + } // namespace os } // namespace details } // namespace spdlog From 435827fe5a4340c192d9e68d7b5cd92205f299a8 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 15 Jan 2023 15:57:08 +0200 Subject: [PATCH 15/24] Update os.h --- include/spdlog/details/os.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/spdlog/details/os.h b/include/spdlog/details/os.h index 742482d0..b92acb2f 100644 --- a/include/spdlog/details/os.h +++ b/include/spdlog/details/os.h @@ -109,9 +109,9 @@ SPDLOG_API bool create_dir(const filename_t &path); // return empty string if field not found SPDLOG_API std::string getenv(const char *field); -// Do fsync by FILE descriptor +// Do fsync by FILE object // Return true on success -SPDLOG_API bool fsync(FILE * fd); +SPDLOG_API bool fsync(FILE * f); } // namespace os } // namespace details From 78e86ba01f4ea9f0583eb7efa94ee8a703d73485 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 15 Jan 2023 15:59:41 +0200 Subject: [PATCH 16/24] Update os-inl.h --- include/spdlog/details/os-inl.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/spdlog/details/os-inl.h b/include/spdlog/details/os-inl.h index 42acf3fe..19d4bdc5 100644 --- a/include/spdlog/details/os-inl.h +++ b/include/spdlog/details/os-inl.h @@ -602,14 +602,14 @@ std::string SPDLOG_INLINE getenv(const char *field) #endif } -// Do fsync by FILE descriptor +// Do fsync by FILE handlerpointer // Return true on success -SPDLOG_INLINE bool fsync(FILE *fd) +SPDLOG_INLINE bool fsync(FILE *fp) { #ifdef _WIN32 - return FlushFileBuffers(reinterpret_cast(_get_osfhandle(_fileno(fd)))) != 0; + return FlushFileBuffers(reinterpret_cast(_get_osfhandle(_fileno(fp)))) != 0; #else - return ::fsync(fileno(fd)) == 0; + return ::fsync(fileno(fp)) == 0; #endif } From 654dbc5c3291a0981e6c473fac199409d41fcde8 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 15 Jan 2023 16:00:26 +0200 Subject: [PATCH 17/24] Update os.h --- include/spdlog/details/os.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/spdlog/details/os.h b/include/spdlog/details/os.h index b92acb2f..f55642c1 100644 --- a/include/spdlog/details/os.h +++ b/include/spdlog/details/os.h @@ -109,9 +109,9 @@ SPDLOG_API bool create_dir(const filename_t &path); // return empty string if field not found SPDLOG_API std::string getenv(const char *field); -// Do fsync by FILE object -// Return true on success -SPDLOG_API bool fsync(FILE * f); +// Do fsync by FILE objectpointer. +// Return true on success. +SPDLOG_API bool fsync(FILE * fp); } // namespace os } // namespace details From 3cab260814613b0a7e6889d2a030b2992c916d1a Mon Sep 17 00:00:00 2001 From: Mohammad Ali Date: Thu, 19 Jan 2023 21:16:34 +0330 Subject: [PATCH 18/24] Add a trivial callback sink (#2610) Add a trivial callback sink --- README.md | 22 ++++++++++ example/example.cpp | 11 +++++ include/spdlog/sinks/callback_sink.h | 61 ++++++++++++++++++++++++++++ tests/CMakeLists.txt | 1 + tests/test_custom_callbacks.cpp | 34 ++++++++++++++++ 5 files changed, 129 insertions(+) create mode 100644 include/spdlog/sinks/callback_sink.h create mode 100644 tests/test_custom_callbacks.cpp diff --git a/README.md b/README.md index b98a920b..d650b3ed 100644 --- a/README.md +++ b/README.md @@ -232,6 +232,28 @@ void multi_sink_example() } ``` +--- +#### Logger with a custom callback function that receives the logs +```c++ + +// create logger with a lambda function callback, the callback will be called +// each time something is logged to the logger +void callback_example() +{ + auto callback_sink = std::make_shared([](const spdlog::details::log_msg &msg) { + // for example you can be notified by sending an email to yourself + }); + callback_sink->set_level(spdlog::level::err); + + auto console_sink = std::make_shared(); + spdlog::logger logger("custom_callback_logger", {console_sink, callback_sink}); + + logger.info("some info log"); + logger.debug("some debug log"); + logger.error("critical issue"); // will notify you +} +``` + --- #### Asynchronous logging ```c++ diff --git a/example/example.cpp b/example/example.cpp index ccfdcf2f..316a22b1 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -12,6 +12,7 @@ void stdout_logger_example(); void basic_example(); void rotating_example(); void daily_example(); +void callback_example(); void async_example(); void binary_example(); void vector_example(); @@ -72,6 +73,7 @@ int main(int, char *[]) basic_example(); rotating_example(); daily_example(); + callback_example(); async_example(); binary_example(); vector_example(); @@ -136,6 +138,15 @@ void daily_example() auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30); } +#include "spdlog/sinks/callback_sink.h" +void callback_example() +{ + // Create the logger + auto logger = spdlog::callback_logger_mt("custom_callback_logger", [](const spdlog::details::log_msg &/*msg*/) { + // do what you need to do with msg + }); +} + #include "spdlog/cfg/env.h" void load_levels_example() { diff --git a/include/spdlog/sinks/callback_sink.h b/include/spdlog/sinks/callback_sink.h new file mode 100644 index 00000000..bcd31383 --- /dev/null +++ b/include/spdlog/sinks/callback_sink.h @@ -0,0 +1,61 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include + +#include +#include + +namespace spdlog { + +// callbacks type +typedef std::function custom_log_callback; + +namespace sinks { +/* + * Trivial callback sink, gets a callback function and calls it on each log + */ +template +class callback_sink final : public base_sink +{ +public: + explicit callback_sink(const custom_log_callback &callback) + : callback_{callback} + {} + +protected: + void sink_it_(const details::log_msg &msg) override + { + callback_(msg); + } + void flush_() override{}; + +private: + custom_log_callback callback_; +}; + +using callback_sink_mt = callback_sink; +using callback_sink_st = callback_sink; + +} // namespace sinks + +// +// factory functions +// +template +inline std::shared_ptr callback_logger_mt(const std::string &logger_name, const custom_log_callback &callback) +{ + return Factory::template create(logger_name, callback); +} + +template +inline std::shared_ptr callback_logger_st(const std::string &logger_name, const custom_log_callback &callback) +{ + return Factory::template create(logger_name, callback); +} + +} // namespace spdlog diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7fe4791e..12204e2b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -31,6 +31,7 @@ set(SPDLOG_UTESTS_SOURCES test_stdout_api.cpp test_backtrace.cpp test_create_dir.cpp + test_custom_callbacks.cpp test_cfg.cpp test_time_point.cpp test_stopwatch.cpp) diff --git a/tests/test_custom_callbacks.cpp b/tests/test_custom_callbacks.cpp new file mode 100644 index 00000000..877e1608 --- /dev/null +++ b/tests/test_custom_callbacks.cpp @@ -0,0 +1,34 @@ +/* + * This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE + */ +#include "includes.h" +#include "test_sink.h" +#include "spdlog/sinks/callback_sink.h" +#include "spdlog/async.h" +#include "spdlog/common.h" + +TEST_CASE("custom_callback_logger", "[custom_callback_logger]]") +{ + std::vector lines; + spdlog::pattern_formatter formatter; + auto callback_logger = std::make_shared([&](const spdlog::details::log_msg &msg) { + spdlog::memory_buf_t formatted; + formatter.format(msg, formatted); + auto eol_len = strlen(spdlog::details::os::default_eol); + lines.emplace_back(formatted.begin(), formatted.end() - eol_len); + }); + std::shared_ptr test_sink(new spdlog::sinks::test_sink_st); + + spdlog::logger logger("test-callback", {callback_logger, test_sink}); + + logger.info("test message 1"); + logger.info("test message 2"); + logger.info("test message 3"); + + std::vector ref_lines = test_sink->lines(); + + REQUIRE(lines[0] == ref_lines[0]); + REQUIRE(lines[1] == ref_lines[1]); + REQUIRE(lines[2] == ref_lines[2]); + spdlog::drop_all(); +} From d8c061aa6e160ac25a5b44ccf9a93bb13dbfc3be Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sat, 21 Jan 2023 00:35:53 +0200 Subject: [PATCH 19/24] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d650b3ed..afcd1958 100644 --- a/README.md +++ b/README.md @@ -233,7 +233,7 @@ void multi_sink_example() ``` --- -#### Logger with a custom callback function that receives the logs +#### User defined callbacks about log events ```c++ // create logger with a lambda function callback, the callback will be called From 5a589438d2d2abc67bdbec2aad7e2a94800c00ea Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sat, 21 Jan 2023 00:36:56 +0200 Subject: [PATCH 20/24] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index afcd1958..9f6291b9 100644 --- a/README.md +++ b/README.md @@ -249,7 +249,6 @@ void callback_example() spdlog::logger logger("custom_callback_logger", {console_sink, callback_sink}); logger.info("some info log"); - logger.debug("some debug log"); logger.error("critical issue"); // will notify you } ``` From 927cc29444a294d76e83dfb898e797dc431ce094 Mon Sep 17 00:00:00 2001 From: Li Z Date: Wed, 1 Feb 2023 18:04:30 +0800 Subject: [PATCH 21/24] Fix unexpected delimiter at start of line in to_hex formatter (#2627) --- include/spdlog/fmt/bin_to_hex.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/spdlog/fmt/bin_to_hex.h b/include/spdlog/fmt/bin_to_hex.h index 47fec05b..1cb51ce6 100644 --- a/include/spdlog/fmt/bin_to_hex.h +++ b/include/spdlog/fmt/bin_to_hex.h @@ -196,7 +196,7 @@ struct formatter, char> continue; } - if (put_delimiters) + if (put_delimiters && i != the_range.get_begin()) { *inserter++ = delimiter; } From da14258533cb951ce85087ceb45556e0b8253660 Mon Sep 17 00:00:00 2001 From: Zeus James <39390245+zEuS0390@users.noreply.github.com> Date: Sun, 12 Feb 2023 16:34:22 +0800 Subject: [PATCH 22/24] Fix MinGW build issue on example (#2642) * Fix MinGW build issue on example #2638 * Move the cmake change to example\CMakeLists.txt * Update CMakeLists.txt on the example --- CMakeLists.txt | 1 - example/CMakeLists.txt | 2 +- include/spdlog/details/udp_client-windows.h | 10 ++++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 61d21781..3389c04b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -176,7 +176,6 @@ if(SPDLOG_SYSTEM_INCLUDES) set(SPDLOG_INCLUDES_LEVEL "SYSTEM") endif() - target_compile_definitions(spdlog PUBLIC SPDLOG_COMPILED_LIB) target_include_directories(spdlog ${SPDLOG_INCLUDES_LEVEL} PUBLIC "$" "$") diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 83336e98..a7863493 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -12,7 +12,7 @@ endif() # Example of using pre-compiled library # --------------------------------------------------------------------------------------- add_executable(example example.cpp) -target_link_libraries(example PRIVATE spdlog::spdlog) +target_link_libraries(example PRIVATE spdlog::spdlog $<$:ws2_32>) # --------------------------------------------------------------------------------------- # Example of using header-only library diff --git a/include/spdlog/details/udp_client-windows.h b/include/spdlog/details/udp_client-windows.h index 8e763356..7d25f037 100644 --- a/include/spdlog/details/udp_client-windows.h +++ b/include/spdlog/details/udp_client-windows.h @@ -15,9 +15,11 @@ #include #include -#pragma comment(lib, "Ws2_32.lib") -#pragma comment(lib, "Mswsock.lib") -#pragma comment(lib, "AdvApi32.lib") +#if defined(_MSC_VER) +# pragma comment(lib, "Ws2_32.lib") +# pragma comment(lib, "Mswsock.lib") +# pragma comment(lib, "AdvApi32.lib") +#endif namespace spdlog { namespace details { @@ -25,7 +27,7 @@ class udp_client { static constexpr int TX_BUFFER_SIZE = 1024 * 10; SOCKET socket_ = INVALID_SOCKET; - sockaddr_in addr_ = {0}; + sockaddr_in addr_ = {}; static void init_winsock_() { From 73725961264feb88e70f280c382a3b552bcb33e6 Mon Sep 17 00:00:00 2001 From: Charles Hardin <53844049+chardin-cpi@users.noreply.github.com> Date: Fri, 24 Feb 2023 15:33:37 -0800 Subject: [PATCH 23/24] Add optional TID definition to the systemd sink send (#2619) From the systemd.journal-fields the TID is a user defined field passed directly from the clients and stored in the journal. Adding the arguement in the journal send to support that storage option in the journal. --- include/spdlog/sinks/systemd_sink.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/spdlog/sinks/systemd_sink.h b/include/spdlog/sinks/systemd_sink.h index e1e97bff..f889f7d5 100644 --- a/include/spdlog/sinks/systemd_sink.h +++ b/include/spdlog/sinks/systemd_sink.h @@ -4,6 +4,7 @@ #pragma once #include +#include #include #include @@ -75,11 +76,17 @@ protected: { // Note: function call inside '()' to avoid macro expansion err = (sd_journal_send)("MESSAGE=%.*s", static_cast(length), payload.data(), "PRIORITY=%d", syslog_level(msg.level), +#ifndef SPDLOG_NO_THREAD_ID + "TID=%zu", os::thread_id(), +#endif "SYSLOG_IDENTIFIER=%.*s", static_cast(syslog_identifier.size()), syslog_identifier.data(), nullptr); } else { err = (sd_journal_send)("MESSAGE=%.*s", static_cast(length), payload.data(), "PRIORITY=%d", syslog_level(msg.level), +#ifndef SPDLOG_NO_THREAD_ID + "TID=%zu", os::thread_id(), +#endif "SYSLOG_IDENTIFIER=%.*s", static_cast(syslog_identifier.size()), syslog_identifier.data(), "CODE_FILE=%s", msg.source.filename, "CODE_LINE=%d", msg.source.line, "CODE_FUNC=%s", msg.source.funcname, nullptr); } From 51bcff820e40a6d26c684284509a9fcf27b10c0a Mon Sep 17 00:00:00 2001 From: afshinpir Date: Sat, 25 Feb 2023 13:37:33 +0330 Subject: [PATCH 24/24] Added `apply_logger_env_levels` (#2649) This method applies levels which is set by environment variable `SPDLOG_LEVEL` to the a single controller. Usefull for loading configuration into manually created loggers. --- include/spdlog/details/registry-inl.h | 8 ++++++++ include/spdlog/details/registry.h | 2 ++ include/spdlog/spdlog-inl.h | 5 +++++ include/spdlog/spdlog.h | 9 +++++++++ 4 files changed, 24 insertions(+) diff --git a/include/spdlog/details/registry-inl.h b/include/spdlog/details/registry-inl.h index e6ecc9b0..323a5c13 100644 --- a/include/spdlog/details/registry-inl.h +++ b/include/spdlog/details/registry-inl.h @@ -287,6 +287,14 @@ SPDLOG_INLINE registry ®istry::instance() return s_instance; } +SPDLOG_INLINE void registry::apply_logger_env_levels(std::shared_ptr new_logger) +{ + std::lock_guard lock(logger_map_mutex_); + auto it = log_levels_.find(new_logger->name()); + auto new_level = it != log_levels_.end() ? it->second : global_log_level_; + new_logger->set_level(new_level); +} + SPDLOG_INLINE void registry::throw_if_exists_(const std::string &logger_name) { if (loggers_.find(logger_name) != loggers_.end()) diff --git a/include/spdlog/details/registry.h b/include/spdlog/details/registry.h index 6a4a5abc..4666fa29 100644 --- a/include/spdlog/details/registry.h +++ b/include/spdlog/details/registry.h @@ -91,6 +91,8 @@ public: static registry &instance(); + void apply_logger_env_levels(std::shared_ptr new_logger); + private: registry(); ~registry(); diff --git a/include/spdlog/spdlog-inl.h b/include/spdlog/spdlog-inl.h index 708399c1..22ea22bb 100644 --- a/include/spdlog/spdlog-inl.h +++ b/include/spdlog/spdlog-inl.h @@ -117,4 +117,9 @@ SPDLOG_INLINE void set_default_logger(std::shared_ptr default_lo details::registry::instance().set_default_logger(std::move(default_logger)); } +SPDLOG_INLINE void apply_logger_env_levels(std::shared_ptr logger) +{ + details::registry::instance().apply_logger_env_levels(std::move(logger)); +} + } // namespace spdlog diff --git a/include/spdlog/spdlog.h b/include/spdlog/spdlog.h index ee83e8de..6b7b221a 100644 --- a/include/spdlog/spdlog.h +++ b/include/spdlog/spdlog.h @@ -131,6 +131,15 @@ SPDLOG_API spdlog::logger *default_logger_raw(); SPDLOG_API void set_default_logger(std::shared_ptr default_logger); +// Initialize logger level based on environment configs. +// +// Useful for applying SPDLOG_LEVEL to manually created loggers. +// +// Example: +// auto mylogger = std::make_shared("mylogger", ...); +// spdlog::apply_logger_env_levels(mylogger); +SPDLOG_API void apply_logger_env_levels(std::shared_ptr logger); + template inline void log(source_loc source, level::level_enum lvl, format_string_t fmt, Args &&... args) {