// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include #include #include #include #include namespace metrics { namespace { struct SubSubMetricSet : public MetricSet { int incVal; LongCountMetric count1; LongCountMetric count2; SumMetric countSum; DoubleValueMetric value1; DoubleValueMetric value2; SumMetric valueSum; DoubleAverageMetric average1; DoubleAverageMetric average2; SumMetric averageSum; SubSubMetricSet(vespalib::stringref name, MetricSet* owner = 0); ~SubSubMetricSet(); MetricSet* clone(std::vector &ownerList, CopyType copyType, metrics::MetricSet* owner, bool includeUnused) const override; void incValues(); }; SubSubMetricSet::SubSubMetricSet(vespalib::stringref name, MetricSet* owner) : MetricSet(name, {}, "", owner), incVal(1), count1("count1", {}, "", this), count2("count2", {}, "", this), countSum("countSum", {}, "", this), value1("value1", {}, "", this), value2("value2", {}, "", this), valueSum("valueSum", {}, "", this), average1("average1", {}, "", this), average2("average2", {}, "", this), averageSum("averageSum", {}, "", this) { countSum.addMetricToSum(count1); countSum.addMetricToSum(count2); valueSum.addMetricToSum(value1); valueSum.addMetricToSum(value2); averageSum.addMetricToSum(average1); averageSum.addMetricToSum(average2); } SubSubMetricSet::~SubSubMetricSet() = default; MetricSet* SubSubMetricSet::clone(std::vector &ownerList, CopyType copyType, metrics::MetricSet* owner, bool includeUnused) const { if (copyType == INACTIVE) { return MetricSet::clone(ownerList, INACTIVE, owner, includeUnused); } return (SubSubMetricSet*) (new SubSubMetricSet( getName(), owner)) ->assignValues(*this); } void SubSubMetricSet::incValues() { count1.inc(incVal); count2.inc(incVal); value1.set(incVal); value2.set(incVal); average1.set(incVal); average2.set(incVal); } struct SubMetricSet : public MetricSet { SubSubMetricSet set1; SubSubMetricSet set2; SumMetric setSum; SubMetricSet(vespalib::stringref name, MetricSet* owner = 0); ~SubMetricSet(); MetricSet* clone(std::vector &ownerList, CopyType copyType, metrics::MetricSet* owner, bool includeUnused) const override; void incValues(); }; SubMetricSet::SubMetricSet(vespalib::stringref name, MetricSet* owner) : MetricSet(name, {}, "", owner), set1("set1", this), set2("set2", this), setSum("setSum", {}, "", this) { setSum.addMetricToSum(set1); setSum.addMetricToSum(set2); } SubMetricSet::~SubMetricSet() = default; MetricSet* SubMetricSet::clone(std::vector &ownerList, CopyType copyType, metrics::MetricSet* owner, bool includeUnused) const { if (copyType == INACTIVE) { return MetricSet::clone(ownerList, INACTIVE, owner, includeUnused); } return (SubMetricSet*) (new SubMetricSet(getName(), owner)) ->assignValues(*this); } void SubMetricSet::incValues() { set1.incValues(); set2.incValues(); } struct TestMetricSet : public MetricSet { SubMetricSet set1; SubMetricSet set2; SumMetric setSum; TestMetricSet(vespalib::stringref name, MetricSet* owner = 0); ~TestMetricSet(); void incValues(); }; TestMetricSet::TestMetricSet(vespalib::stringref name, MetricSet* owner) : MetricSet(name, {}, "", owner), set1("set1", this), set2("set2", this), setSum("setSum", {}, "", this) { setSum.addMetricToSum(set1); setSum.addMetricToSum(set2); } TestMetricSet::~TestMetricSet() = default; void TestMetricSet::incValues() { set1.incValues(); set2.incValues(); } struct FakeTimer : public MetricManager::Timer { uint32_t _timeInSecs; FakeTimer() : _timeInSecs(1) {} time_t getTime() const override { return _timeInSecs; } }; void ASSERT_VALUE(int32_t value, const MetricSnapshot & snapshot, const char *name) __attribute__((noinline)); void ASSERT_VALUE(int32_t value, const MetricSnapshot & snapshot, const char *name) { const Metric* _metricValue_((snapshot).getMetrics().getMetric(name)); if (_metricValue_ == 0) { FAIL() << ("Metric value '" + std::string(name) + "' not found in snapshot"); } EXPECT_EQ(value, int32_t(_metricValue_->getLongValue("value"))); } } struct SnapshotTest : public ::testing::Test { time_t tick(MetricManager& mgr, time_t currentTime) { return mgr.tick(mgr.getMetricLock(), currentTime); } }; TEST_F(SnapshotTest, test_snapshot_two_days) { TestMetricSet set("test"); FakeTimer* timer; MetricManager mm( std::unique_ptr(timer = new FakeTimer)); { MetricLockGuard lockGuard(mm.getMetricLock()); mm.registerMetric(lockGuard, set); } mm.init(config::ConfigUri("raw:consumer[1]\n" "consumer[0].name \"log\""), false); tick(mm, timer->_timeInSecs * 1000); for (uint32_t days=0; days<2; ++days) { for (uint32_t hour=0; hour<24; ++hour) { for (uint32_t fiveMin=0; fiveMin<12; ++fiveMin) { set.incValues(); timer->_timeInSecs += 5 * 60; tick(mm, timer->_timeInSecs * 1000); } } } // Print all data. Useful for debugging. It's too much to verify // everything, so test will just verify some parts. Add more parts if you // find a failure. /* std::string regex = ".*"; bool verbose = true; std::cout << "\n" << mm.getActiveMetrics().toString(mm, "", regex, verbose) << "\n\n"; std::vector periods(mm.getSnapshotPeriods()); for (uint32_t i=0; i