#include "counters.h" #include using namespace NMonitoring; class TCountersPrinter: public ICountableConsumer { public: TCountersPrinter(IOutputStream* out) : Out_(out) , Level_(0) { } private: void OnCounter( const TString& labelName, const TString& labelValue, const TCounterForPtr* counter) override { Indent(Out_, Level_) << labelName << ':' << labelValue << " = " << counter->Val() << '\n'; } void OnHistogram( const TString& labelName, const TString& labelValue, IHistogramSnapshotPtr snapshot, bool /*derivative*/) override { Indent(Out_, Level_) << labelName << ':' << labelValue << " = " << *snapshot << '\n'; } void OnGroupBegin( const TString& labelName, const TString& labelValue, const TDynamicCounters*) override { Indent(Out_, Level_++) << labelName << ':' << labelValue << " {\n"; } void OnGroupEnd( const TString&, const TString&, const TDynamicCounters*) override { Indent(Out_, --Level_) << "}\n"; } static IOutputStream& Indent(IOutputStream* out, int level) { for (int i = 0; i < level; i++) { out->Write(" "); } return *out; } private: IOutputStream* Out_; int Level_ = 0; }; Y_UNIT_TEST_SUITE(TDynamicCountersTest) { Y_UNIT_TEST(CountersConsumer) { TDynamicCounterPtr rootGroup(new TDynamicCounters()); auto usersCounter = rootGroup->GetNamedCounter("users", "count"); *usersCounter = 7; auto hostGroup = rootGroup->GetSubgroup("counters", "resources"); auto cpuCounter = hostGroup->GetNamedCounter("resource", "cpu"); *cpuCounter = 30; auto memGroup = hostGroup->GetSubgroup("resource", "mem"); auto usedCounter = memGroup->GetCounter("used"); auto freeCounter = memGroup->GetCounter("free"); *usedCounter = 100; *freeCounter = 28; auto netGroup = hostGroup->GetSubgroup("resource", "net"); auto rxCounter = netGroup->GetCounter("rx", true); auto txCounter = netGroup->GetCounter("tx", true); *rxCounter = 8; *txCounter = 9; TStringStream ss; TCountersPrinter printer(&ss); rootGroup->Accept("root", "counters", printer); UNIT_ASSERT_STRINGS_EQUAL(ss.Str(), "root:counters {\n" " counters:resources {\n" " resource:cpu = 30\n" " resource:mem {\n" " sensor:free = 28\n" " sensor:used = 100\n" " }\n" " resource:net {\n" " sensor:rx = 8\n" " sensor:tx = 9\n" " }\n" " }\n" " users:count = 7\n" "}\n"); } Y_UNIT_TEST(MergeSubgroup) { TDynamicCounterPtr rootGroup(new TDynamicCounters()); auto sensor1 = rootGroup->GetNamedCounter("sensor", "1"); *sensor1 = 1; auto group1 = rootGroup->GetSubgroup("group", "1"); auto sensor2 = group1->GetNamedCounter("sensor", "2"); *sensor2 = 2; auto group2 = group1->GetSubgroup("group", "2"); auto sensor3 = group2->GetNamedCounter("sensor", "3"); *sensor3 = 3; rootGroup->MergeWithSubgroup("group", "1"); TStringStream ss; TCountersPrinter printer(&ss); rootGroup->Accept("root", "counters", printer); UNIT_ASSERT_STRINGS_EQUAL(ss.Str(), "root:counters {\n" " group:2 {\n" " sensor:3 = 3\n" " }\n" " sensor:1 = 1\n" " sensor:2 = 2\n" "}\n"); } Y_UNIT_TEST(ResetCounters) { TDynamicCounterPtr rootGroup(new TDynamicCounters()); auto sensor1 = rootGroup->GetNamedCounter("sensor", "1"); *sensor1 = 1; auto group1 = rootGroup->GetSubgroup("group", "1"); auto sensor2 = group1->GetNamedCounter("sensor", "2"); *sensor2 = 2; auto group2 = group1->GetSubgroup("group", "2"); auto sensor3 = group2->GetNamedCounter("sensor", "3", true); *sensor3 = 3; rootGroup->ResetCounters(true); TStringStream ss1; TCountersPrinter printer1(&ss1); rootGroup->Accept("root", "counters", printer1); UNIT_ASSERT_STRINGS_EQUAL(ss1.Str(), "root:counters {\n" " group:1 {\n" " group:2 {\n" " sensor:3 = 0\n" " }\n" " sensor:2 = 2\n" " }\n" " sensor:1 = 1\n" "}\n"); rootGroup->ResetCounters(); TStringStream ss2; TCountersPrinter printer2(&ss2); rootGroup->Accept("root", "counters", printer2); UNIT_ASSERT_STRINGS_EQUAL(ss2.Str(), "root:counters {\n" " group:1 {\n" " group:2 {\n" " sensor:3 = 0\n" " }\n" " sensor:2 = 0\n" " }\n" " sensor:1 = 0\n" "}\n"); } Y_UNIT_TEST(RemoveCounter) { TDynamicCounterPtr rootGroup(new TDynamicCounters()); rootGroup->GetNamedCounter("label", "1"); rootGroup->GetCounter("2"); rootGroup->GetCounter("3"); rootGroup->GetSubgroup("group", "1"); rootGroup->RemoveNamedCounter("label", "1"); rootGroup->RemoveNamedCounter("label", "5"); rootGroup->RemoveNamedCounter("group", "1"); rootGroup->RemoveCounter("2"); rootGroup->RemoveCounter("5"); TStringStream ss; TCountersPrinter printer(&ss); rootGroup->Accept("root", "counters", printer); UNIT_ASSERT_STRINGS_EQUAL(ss.Str(), "root:counters {\n" " group:1 {\n" " }\n" " sensor:3 = 0\n" "}\n"); } Y_UNIT_TEST(RemoveSubgroup) { TDynamicCounterPtr rootGroup(new TDynamicCounters()); rootGroup->GetSubgroup("group", "1"); rootGroup->GetSubgroup("group", "2"); rootGroup->GetCounter("2"); rootGroup->RemoveSubgroup("group", "1"); rootGroup->RemoveSubgroup("group", "3"); rootGroup->RemoveSubgroup("sensor", "2"); TStringStream ss; TCountersPrinter printer(&ss); rootGroup->Accept("root", "counters", printer); UNIT_ASSERT_STRINGS_EQUAL(ss.Str(), "root:counters {\n" " group:2 {\n" " }\n" " sensor:2 = 0\n" "}\n"); } Y_UNIT_TEST(ExpiringCounters) { TDynamicCounterPtr rootGroup{new TDynamicCounters()}; { auto c = rootGroup->GetExpiringCounter("foo"); auto h = rootGroup->GetExpiringHistogram("bar", ExplicitHistogram({1, 42})); h->Collect(15); TStringStream ss; TCountersPrinter printer(&ss); rootGroup->Accept("root", "counters", printer); UNIT_ASSERT_STRINGS_EQUAL(ss.Str(), "root:counters {\n" " sensor:bar = {1: 0, 42: 1, inf: 0}\n" " sensor:foo = 0\n" "}\n"); } TStringStream ss; TCountersPrinter printer(&ss); rootGroup->Accept("root", "counters", printer); UNIT_ASSERT_STRINGS_EQUAL(ss.Str(), "root:counters {\n" "}\n"); } Y_UNIT_TEST(ExpiringCountersDiesAfterRegistry) { TDynamicCounters::TCounterPtr ptr; { TDynamicCounterPtr rootGroup{new TDynamicCounters()}; ptr = rootGroup->GetExpiringCounter("foo"); TStringStream ss; TCountersPrinter printer(&ss); rootGroup->Accept("root", "counters", printer); UNIT_ASSERT_STRINGS_EQUAL(ss.Str(), "root:counters {\n" " sensor:foo = 0\n" "}\n"); } } Y_UNIT_TEST(HistogramCounter) { TDynamicCounterPtr rootGroup(new TDynamicCounters()); auto h = rootGroup->GetHistogram("timeMillis", ExponentialHistogram(4, 2)); for (i64 i = 1; i < 100; i++) { h->Collect(i); } TStringStream ss; TCountersPrinter printer(&ss); rootGroup->Accept("root", "counters", printer); UNIT_ASSERT_STRINGS_EQUAL(ss.Str(), "root:counters {\n" " sensor:timeMillis = {1: 1, 2: 1, 4: 2, inf: 95}\n" "}\n"); } Y_UNIT_TEST(CounterLookupCounter) { TDynamicCounterPtr rootGroup(new TDynamicCounters()); TDynamicCounters::TCounterPtr lookups = rootGroup->GetCounter("Lookups", true); rootGroup->SetLookupCounter(lookups); // Create subtree and check that counter is inherited TDynamicCounterPtr serviceGroup = rootGroup->GetSubgroup("service", "MyService"); UNIT_ASSERT_VALUES_EQUAL(lookups->Val(), 1); TDynamicCounterPtr subGroup = serviceGroup->GetSubgroup("component", "MyComponent"); UNIT_ASSERT_VALUES_EQUAL(lookups->Val(), 2); auto counter = subGroup->GetNamedCounter("range", "20 msec", true); UNIT_ASSERT_VALUES_EQUAL(lookups->Val(), 3); auto hist = subGroup->GetHistogram("timeMsec", ExponentialHistogram(4, 2)); UNIT_ASSERT_VALUES_EQUAL(lookups->Val(), 4); // Replace the counter for subGroup auto subGroupLookups = rootGroup->GetCounter("LookupsInMyComponent", true); UNIT_ASSERT_VALUES_EQUAL(lookups->Val(), 5); subGroup->SetLookupCounter(subGroupLookups); auto counter2 = subGroup->GetNamedCounter("range", "30 msec", true); UNIT_ASSERT_VALUES_EQUAL(subGroupLookups->Val(), 1); UNIT_ASSERT_VALUES_EQUAL(lookups->Val(), 5); } Y_UNIT_TEST(FindCounters) { TDynamicCounterPtr rootGroup(new TDynamicCounters()); auto counter = rootGroup->FindCounter("counter1"); UNIT_ASSERT(!counter); rootGroup->GetCounter("counter1"); counter = rootGroup->FindCounter("counter1"); UNIT_ASSERT(counter); counter = rootGroup->FindNamedCounter("name", "counter2"); UNIT_ASSERT(!counter); rootGroup->GetNamedCounter("name", "counter2"); counter = rootGroup->FindNamedCounter("name", "counter2"); UNIT_ASSERT(counter); auto histogram = rootGroup->FindHistogram("histogram1"); UNIT_ASSERT(!histogram); rootGroup->GetHistogram("histogram1", ExponentialHistogram(4, 2)); histogram = rootGroup->FindHistogram("histogram1"); UNIT_ASSERT(histogram); histogram = rootGroup->FindNamedHistogram("name", "histogram2"); UNIT_ASSERT(!histogram); rootGroup->GetNamedHistogram("name", "histogram2", ExponentialHistogram(4, 2)); histogram = rootGroup->FindNamedHistogram("name", "histogram2"); UNIT_ASSERT(histogram); } }