From f795297e15b431efd0fc5c45d92a79cce82e24ea Mon Sep 17 00:00:00 2001 From: gabime Date: Thu, 5 Sep 2019 00:39:11 +0300 Subject: [PATCH] try different apprach to backtracer object --- include/spdlog/details/backtracer.h | 109 ++++++++++++------ include/spdlog/details/circular_q.h | 143 +++++++++++++++--------- include/spdlog/details/log_msg_buffer.h | 8 ++ include/spdlog/logger-inl.h | 16 +-- include/spdlog/logger.h | 7 +- 5 files changed, 182 insertions(+), 101 deletions(-) diff --git a/include/spdlog/details/backtracer.h b/include/spdlog/details/backtracer.h index 49c07d47..af878680 100644 --- a/include/spdlog/details/backtracer.h +++ b/include/spdlog/details/backtracer.h @@ -13,39 +13,80 @@ // Useful for storing debug data in case of error/warning happens. namespace spdlog { -namespace details { -class backtracer -{ - std::mutex mutex_; - size_t n_messages_; - circular_q messages_; - -public: - explicit backtracer(size_t n_messages) : n_messages_{n_messages}, messages_{n_messages} - {} - - size_t n_messages() const - { - return n_messages_; - } - - void add(const log_msg &msg) - { - std::lock_guard lock{mutex_}; - messages_.push_back(log_msg_buffer{msg}); - } - - // pop all items in the q and apply the given fun on each of them. - void foreach_pop(std::function fun) - { - std::lock_guard lock{mutex_}; - while (!messages_.empty()) + namespace details { + class backtracer { - log_msg_buffer popped; - messages_.pop_front(popped); - fun(popped); - } - } -}; -} // namespace details + mutable std::mutex mutex_; + std::atomic enabled_ {false}; + circular_q messages_; + + public: + backtracer() = default; + backtracer(const backtracer& other) + { + std::lock_guard lock(other.mutex_); + enabled_ = other.enabled(); + messages_ = other.messages_; + } + + backtracer(backtracer&& other) SPDLOG_NOEXCEPT + { + std::lock_guard lock(other.mutex_); + enabled_ = other.enabled(); + messages_ = std::move(other.messages_); + } + + backtracer& operator=(backtracer other) + { + std::lock_guard lock(mutex_); + enabled_ = other.enabled(); + messages_ = other.messages_; + return *this; + } + + void enable(size_t size) + { + std::lock_guard lock{ mutex_ }; + enabled_.store(true, std::memory_order_relaxed); + messages_ = circular_q{ size }; + } + + + void disable() + { + std::lock_guard lock{ mutex_ }; + enabled_.store(false, std::memory_order_relaxed); + } + + + bool enabled() const + { + return enabled_.load(std::memory_order_relaxed); + } + + operator bool() const + { + return enabled(); + } + + void push_back(const log_msg &msg) + { + std::lock_guard lock{ mutex_ }; + messages_.push_back(log_msg_buffer{ msg }); + } + + // pop all items in the q and apply the given fun on each of them. + void foreach_pop(std::function fun) + { + std::lock_guard lock{ mutex_ }; + while (!messages_.empty()) + { + log_msg_buffer popped; + messages_.pop_front(popped); + fun(popped); + } + } + }; + + } // namespace details } // namespace spdlog \ No newline at end of file diff --git a/include/spdlog/details/circular_q.h b/include/spdlog/details/circular_q.h index 055bc635..f92c6bd7 100644 --- a/include/spdlog/details/circular_q.h +++ b/include/spdlog/details/circular_q.h @@ -7,62 +7,101 @@ #include namespace spdlog { -namespace details { -template -class circular_q -{ -public: - using item_type = T; - - explicit circular_q(size_t max_items) - : max_items_(max_items + 1) // one item is reserved as marker for full q - , v_(max_items_) - {} - - // push back, overrun (oldest) item if no room left - void push_back(T &&item) - { - v_[tail_] = std::move(item); - tail_ = (tail_ + 1) % max_items_; - - if (tail_ == head_) // overrun last item if full + namespace details { + template + class circular_q { - head_ = (head_ + 1) % max_items_; - ++overrun_counter_; - } - } + public: + using item_type = T; - // Pop item from front. - // If there are no elements in the container, the behavior is undefined. - void pop_front(T &popped_item) - { - popped_item = std::move(v_[head_]); - head_ = (head_ + 1) % max_items_; - } + // empty cir + circular_q() = default; - bool empty() - { - return tail_ == head_; - } + explicit circular_q(size_t max_items) + : max_items_(max_items + 1) // one item is reserved as marker for full q + , v_(max_items_) + {} - bool full() - { - // head is ahead of the tail by 1 - return ((tail_ + 1) % max_items_) == head_; - } - size_t overrun_counter() const - { - return overrun_counter_; - } -private: - size_t max_items_; - typename std::vector::size_type head_ = 0; - typename std::vector::size_type tail_ = 0; - size_t overrun_counter_ = 0; - std::vector v_; - -}; -} // namespace details + circular_q(const circular_q&) = default; + circular_q& operator=(const circular_q&) = default; + + // move cannot be default, + // since we need to reset head_, tail_, etc to zero in the moved object + circular_q(circular_q&& other) SPDLOG_NOEXCEPT: + { + copy_moveable(std::move(other)); + } + + circular_q& operator=(circular_q&& other) SPDLOG_NOEXCEPT + { + copy_moveable(std::move(other)); + return *this; + } + + + // push back, overrun (oldest) item if no room left + void push_back(T &&item) + { + if(max_items_ > 0) + { + v_[tail_] = std::move(item); + tail_ = (tail_ + 1) % max_items_; + + if (tail_ == head_) // overrun last item if full + { + head_ = (head_ + 1) % max_items_; + ++overrun_counter_; + } + } + } + + // Pop item from front. + // If there are no elements in the container, the behavior is undefined. + void pop_front(T &popped_item) + { + if(max_items_ > 0) + { + popped_item = std::move(v_[head_]); + head_ = (head_ + 1) % max_items_; + } + } + + bool empty() + { + return tail_ == head_; + } + + bool full() + { + // head is ahead of the tail by 1 + return ((tail_ + 1) % max_items_) == head_; + } + + size_t overrun_counter() const + { + return overrun_counter_; + } + + private: + size_t max_items_ = 0; + typename std::vector::size_type head_ = 0; + typename std::vector::size_type tail_ = 0; + size_t overrun_counter_ = 0; + std::vector v_; + + + void copy_moveable(circular_q&& other) SPDLOG_NOEXCEPT + { + max_items_ = other.max_items_; + head_ = other.head_; + tail_ = other.tail_; + overrun_counter_ = other.overrun_counter_, + v_ = std::move(other.v_); + other.max_items_ = 0; // disable other + } + + }; + } // namespace details } // namespace spdlog diff --git a/include/spdlog/details/log_msg_buffer.h b/include/spdlog/details/log_msg_buffer.h index f7becf07..9f77d5ce 100644 --- a/include/spdlog/details/log_msg_buffer.h +++ b/include/spdlog/details/log_msg_buffer.h @@ -47,6 +47,14 @@ public: update_string_views(); } + log_msg_buffer &operator=(log_msg_buffer &other) + { + log_msg::operator=(other); + buffer.append(other.buffer.begin(), other.buffer.end()); + update_string_views(); + return *this; + } + log_msg_buffer &operator=(log_msg_buffer &&other) { log_msg::operator=(std::move(other)); diff --git a/include/spdlog/logger-inl.h b/include/spdlog/logger-inl.h index 52ed6839..357e8325 100644 --- a/include/spdlog/logger-inl.h +++ b/include/spdlog/logger-inl.h @@ -23,11 +23,7 @@ SPDLOG_INLINE logger::logger(const logger &other) , flush_level_(other.flush_level_.load(std::memory_order_relaxed)) , custom_err_handler_(other.custom_err_handler_) , tracer_(other.tracer_) -{ - if (tracer_) - { - enable_backtrace(tracer_->n_messages()); - } +{ } SPDLOG_INLINE logger::logger(logger &&other) SPDLOG_NOEXCEPT : name_(std::move(other.name_)), @@ -61,7 +57,7 @@ SPDLOG_INLINE void logger::swap(spdlog::logger &other) SPDLOG_NOEXCEPT other.flush_level_.store(tmp); custom_err_handler_.swap(other.custom_err_handler_); - tracer_.swap(other.tracer_); + std::swap(tracer_, other.tracer_); } SPDLOG_INLINE void swap(logger &a, logger &b) @@ -116,13 +112,13 @@ SPDLOG_INLINE void logger::set_pattern(std::string pattern, pattern_time_type ti // create new backtrace sink and move to it all our child sinks SPDLOG_INLINE void logger::enable_backtrace(size_t n_messages) { - tracer_ = std::make_shared(n_messages); + tracer_.enable(n_messages); } // restore orig sinks and level and delete the backtrace sink SPDLOG_INLINE void logger::disable_backtrace() { - tracer_.reset(); + tracer_.disable(); } SPDLOG_INLINE void logger::dump_backtrace() @@ -206,7 +202,7 @@ SPDLOG_INLINE void logger::flush_() SPDLOG_INLINE void logger::backtrace_add_(const details::log_msg &msg) { - tracer_->add(msg); + tracer_.push_back(msg); } SPDLOG_INLINE void logger::dump_backtrace_() @@ -215,7 +211,7 @@ SPDLOG_INLINE void logger::dump_backtrace_() if (tracer_) { sink_it_(log_msg{name(), level::info, "****************** Backtrace Start ******************"}); - tracer_->foreach_pop([this](const details::log_msg &msg) { this->sink_it_(msg); }); + tracer_.foreach_pop([this](const details::log_msg &msg) { this->sink_it_(msg); }); sink_it_(log_msg{name(), level::info, "****************** Backtrace End ********************"}); } } diff --git a/include/spdlog/logger.h b/include/spdlog/logger.h index d18b6234..4e39c7ea 100644 --- a/include/spdlog/logger.h +++ b/include/spdlog/logger.h @@ -17,6 +17,7 @@ #include "spdlog/common.h" #include "spdlog/details/log_msg.h" +#include "spdlog/details/backtracer.h" #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT #include "spdlog/details/os.h" @@ -39,10 +40,6 @@ namespace spdlog { -namespace details { -class backtracer; -} - class logger { public: @@ -365,7 +362,7 @@ protected: spdlog::level_t level_{level::info}; spdlog::level_t flush_level_{level::off}; err_handler custom_err_handler_{nullptr}; - std::shared_ptr tracer_; + details::backtracer tracer_; virtual void sink_it_(const details::log_msg &msg); virtual void flush_();