mirror of https://github.com/gabime/spdlog.git
Merge branch 'v1.x' into v1.x
commit
dc054c3f8a
@ -0,0 +1,90 @@
|
|||||||
|
// 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 "spdlog/details/null_mutex.h"
|
||||||
|
#include "spdlog/details/log_msg.h"
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
// Duplicate message removal sink.
|
||||||
|
// Skip the message if previous one is identical and less than "max_skip_duration" have passed
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// #include "spdlog/sinks/dup_filter_sink.h"
|
||||||
|
//
|
||||||
|
// int main() {
|
||||||
|
// auto dup_filter = std::make_shared<dup_filter_sink_st>(std::chrono::seconds(5));
|
||||||
|
// dup_filter->add_sink(std::make_shared<stdout_color_sink_mt>());
|
||||||
|
// 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<typename Mutex>
|
||||||
|
class dup_filter_sink : public dist_sink<Mutex>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<class Rep, class Period>
|
||||||
|
explicit dup_filter_sink(std::chrono::duration<Rep, Period> max_skip_duration)
|
||||||
|
: max_skip_duration_{max_skip_duration}
|
||||||
|
{}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::chrono::microseconds max_skip_duration_;
|
||||||
|
log_clock::time_point last_msg_time_;
|
||||||
|
std::string last_msg_payload_;
|
||||||
|
size_t skip_counter_ = 0;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
fmt::basic_memory_buffer<char, 64> buf;
|
||||||
|
fmt::format_to(buf, "Skipped {} duplicate messages..", skip_counter_);
|
||||||
|
details::log_msg skipped_msg{msg.logger_name, msg.level, string_view_t{buf.data(), buf.size()}};
|
||||||
|
dist_sink<Mutex>::sink_it_(skipped_msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// log current message
|
||||||
|
dist_sink<Mutex>::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<std::mutex>;
|
||||||
|
using dup_filter_sink_st = dup_filter_sink<details::null_mutex>;
|
||||||
|
|
||||||
|
} // namespace sinks
|
||||||
|
} // namespace spdlog
|
@ -0,0 +1,76 @@
|
|||||||
|
#include "includes.h"
|
||||||
|
#include "spdlog/sinks/dup_filter_sink.h"
|
||||||
|
#include "test_sink.h"
|
||||||
|
|
||||||
|
using namespace spdlog;
|
||||||
|
using namespace spdlog::sinks;
|
||||||
|
|
||||||
|
TEST_CASE("dup_filter_test1", "[dup_filter_sink]")
|
||||||
|
{
|
||||||
|
dup_filter_sink_st dup_sink{std::chrono::seconds{5}};
|
||||||
|
auto test_sink = std::make_shared<test_sink_mt>();
|
||||||
|
dup_sink.add_sink(test_sink);
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message1"});
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(test_sink->msg_counter() == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("dup_filter_test2", "[dup_filter_sink]")
|
||||||
|
{
|
||||||
|
dup_filter_sink_st dup_sink{std::chrono::seconds{0}};
|
||||||
|
auto test_sink = std::make_shared<test_sink_mt>();
|
||||||
|
dup_sink.add_sink(test_sink);
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message1"});
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(test_sink->msg_counter() == 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("dup_filter_test3", "[dup_filter_sink]")
|
||||||
|
{
|
||||||
|
dup_filter_sink_st dup_sink{std::chrono::seconds{1}};
|
||||||
|
auto test_sink = std::make_shared<test_sink_mt>();
|
||||||
|
dup_sink.add_sink(test_sink);
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message1"});
|
||||||
|
dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message2"});
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(test_sink->msg_counter() == 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("dup_filter_test4", "[dup_filter_sink]")
|
||||||
|
{
|
||||||
|
dup_filter_sink_mt dup_sink{std::chrono::milliseconds{10}};
|
||||||
|
auto test_sink = std::make_shared<test_sink_mt>();
|
||||||
|
dup_sink.add_sink(test_sink);
|
||||||
|
|
||||||
|
dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message"});
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||||
|
dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message"});
|
||||||
|
REQUIRE(test_sink->msg_counter() == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("dup_filter_test5", "[dup_filter_sink]")
|
||||||
|
{
|
||||||
|
dup_filter_sink_mt dup_sink{std::chrono::seconds{5}};
|
||||||
|
auto test_sink = std::make_shared<test_sink_mt>();
|
||||||
|
dup_sink.add_sink(test_sink);
|
||||||
|
|
||||||
|
dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message1"});
|
||||||
|
dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message1"});
|
||||||
|
dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message1"});
|
||||||
|
dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message2"});
|
||||||
|
|
||||||
|
REQUIRE(test_sink->msg_counter() == 3); // skip 2 messages but log the "skipped.." message before message2
|
||||||
|
}
|
Loading…
Reference in New Issue