// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) #pragma once #include "dist_sink.h" #include #include #include #include #include #include // Duplicate message removal sink. // Skip the message if previous one is identical and less than "max_skip_duration" have passed // // Example: // // #include // // int main() { // 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"); // l.info("Hello"); // l.info("Hello"); // l.info("Different Hello"); // } // // Will produce: // [2019-06-25 17:50:56.511] [logger] [info] Hello // [2019-06-25 17:50:56.512] [logger] [info] Skipped 3 duplicate messages.. // [2019-06-25 17:50:56.512] [logger] [info] Different Hello namespace spdlog { namespace sinks { template class dup_filter_sink : public dist_sink { public: template 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: std::chrono::microseconds max_skip_duration_; 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 { bool filtered = filter_(msg); if (!filtered) { skip_counter_ += 1; return; } // log the "skipped.." message if (skip_counter_ > 0) { char buf[64]; 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, log_level_, string_view_t{buf, static_cast(msg_size)}}; dist_sink::sink_it_(skipped_msg); } } // log current message dist_sink::sink_it_(msg); last_msg_time_ = msg.time; skip_counter_ = 0; last_msg_payload_.assign(msg.payload.data(), msg.payload.data() + msg.payload.size()); } // return whether the log msg should be displayed (true) or skipped (false) bool filter_(const details::log_msg &msg) { auto filter_duration = msg.time - last_msg_time_; return (filter_duration > max_skip_duration_) || (msg.payload != last_msg_payload_); } }; using dup_filter_sink_mt = dup_filter_sink; using dup_filter_sink_st = dup_filter_sink; } // namespace sinks } // namespace spdlog