summaryrefslogtreecommitdiffstats
path: root/metrics/src/tests/metricmanagertest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'metrics/src/tests/metricmanagertest.cpp')
-rw-r--r--metrics/src/tests/metricmanagertest.cpp184
1 files changed, 160 insertions, 24 deletions
diff --git a/metrics/src/tests/metricmanagertest.cpp b/metrics/src/tests/metricmanagertest.cpp
index be63bed5bec..e5e39bd9dcb 100644
--- a/metrics/src/tests/metricmanagertest.cpp
+++ b/metrics/src/tests/metricmanagertest.cpp
@@ -5,19 +5,21 @@
#include <vespa/metrics/metricmanager.h>
#include <vespa/metrics/state_api_adapter.h>
#include <vespa/metrics/textwriter.h>
+#include <vespa/metrics/prometheus_writer.h>
#include <vespa/vespalib/data/slime/slime.h>
-#include <vespa/vespalib/gtest/gtest.h>
#include <vespa/vespalib/stllike/asciistream.h>
-#include <vespa/vespalib/util/size_literals.h>
#include <vespa/vespalib/util/time.h>
#include <vespa/vespalib/data/simple_buffer.h>
#include <vespa/vespalib/util/atomic.h>
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
#include <mutex>
#include <thread>
#include <vespa/log/log.h>
LOG_SETUP(".test.metricmanager");
+using namespace ::testing;
using namespace vespalib::atomic;
using config::ConfigUri;
@@ -41,16 +43,16 @@ struct SubMetricSet : public MetricSet
DoubleValueMetric val2;
SumMetric<DoubleValueMetric> valsum;
- SubMetricSet(const Metric::String & name, MetricSet* owner);
- ~SubMetricSet();
+ explicit SubMetricSet(const Metric::String& name, MetricSet* owner = nullptr);
+ ~SubMetricSet() override;
};
-SubMetricSet::SubMetricSet(const Metric::String & name, MetricSet* owner)
- : MetricSet(name, {{"sub"}}, "sub desc", owner),
- val1("val1", {{"tag4"},{"snaptest"}}, "val1 desc", this),
+SubMetricSet::SubMetricSet(const Metric::String& name, MetricSet* owner)
+ : MetricSet(name, {{"partofsum"}, {"sub"}}, "sub desc", owner),
+ val1("val1", {{"tag4"}, {"snaptest"}}, "val1 desc", this),
val2("val2", {{"tag5"}}, "val2 desc", this),
- valsum("valsum", {{"tag4"},{"snaptest"}}, "valsum desc", this)
+ valsum("valsum", {{"tag4"}, {"snaptest"}}, "valsum desc", this)
{
valsum.addMetricToSum(val1);
valsum.addMetricToSum(val2);
@@ -65,7 +67,7 @@ struct MultiSubMetricSet
SubMetricSet b;
SumMetric<MetricSet> sum;
- MultiSubMetricSet(MetricSet* owner);
+ explicit MultiSubMetricSet(MetricSet* owner);
~MultiSubMetricSet();
};
@@ -156,13 +158,6 @@ getMatchedMetrics(const vespalib::string& config)
mm.init(ConfigUri(config));
MetricNameVisitor visitor;
- /** Take a copy to verify clone works.
- std::list<Metric::SP> ownerList;
- MetricSet::UP copy(dynamic_cast<MetricSet*>(
- mm.getMetrics().clone(ownerList)));
- mm.visit(*copy, visitor, "consumer");
- */
-
MetricLockGuard g(mm.getMetricLock());
mm.visit(g, mm.getActiveMetrics(g), visitor, "consumer");
const MetricManager::ConsumerSpec * consumerSpec = mm.getConsumerSpec(g, "consumer");
@@ -386,8 +381,8 @@ struct BriefValuePrinter : public MetricVisitor {
bool waitForTimeProcessed(const MetricManager& mm, time_point::duration processtime, uint32_t timeout = 120)
{
- uint32_t lastchance = time(0) + timeout;
- while (time(0) < lastchance) {
+ uint32_t lastchance = time(nullptr) + timeout;
+ while (time(nullptr) < lastchance) {
if (mm.getLastProcessedTime() >= time_point(processtime)) return true;
mm.timeChangedNotification();
std::this_thread::sleep_for(10ms);
@@ -705,6 +700,16 @@ struct MetricSnapshotTestFixture
}
return ss.str();
}
+
+ std::string render_last_snapshot_as_prometheus() const {
+ vespalib::asciistream os;
+ PrometheusWriter writer(os);
+ {
+ MetricLockGuard lockGuard(manager.getMetricLock());
+ manager.visit(lockGuard, manager.getMetricSnapshot(lockGuard, 300s, false), writer, "snapper");
+ }
+ return os.str();
+ }
};
class JsonMetricWrapper
@@ -762,7 +767,7 @@ struct DimensionTestMetricSet : MetricSet
DoubleValueMetric val1;
LongCountMetric val2;
- DimensionTestMetricSet(MetricSet* owner = nullptr);
+ explicit DimensionTestMetricSet(MetricSet* owner = nullptr);
~DimensionTestMetricSet() override;
};
@@ -801,7 +806,7 @@ struct NestedDimensionTestMetricSet : MetricSet
DimensionTestMetricSet nestedSet;
NestedDimensionTestMetricSet();
- ~NestedDimensionTestMetricSet();
+ ~NestedDimensionTestMetricSet() override;
};
NestedDimensionTestMetricSet::NestedDimensionTestMetricSet()
@@ -839,7 +844,7 @@ struct DimensionOverridableTestMetricSet : MetricSet
{
DoubleValueMetric val;
- DimensionOverridableTestMetricSet(const std::string& dimValue, MetricSet* owner = nullptr);
+ explicit DimensionOverridableTestMetricSet(const std::string& dimValue, MetricSet* owner = nullptr);
~DimensionOverridableTestMetricSet() override;
};
@@ -855,7 +860,7 @@ struct SameNamesTestMetricSet : MetricSet
DimensionOverridableTestMetricSet set2;
SameNamesTestMetricSet();
- ~SameNamesTestMetricSet();
+ ~SameNamesTestMetricSet() override;
};
SameNamesTestMetricSet::SameNamesTestMetricSet()
@@ -894,14 +899,14 @@ TEST_F(MetricManagerTest, test_text_output)
MetricLockGuard lockGuard(mm.getMetricLock());
mm.registerMetric(lockGuard, mySet.set);
}
- // Adding metrics to have some values in them
+ // Adding metrics to have some values in them
mySet.val6.addValue(2);
mySet.val9.val1.addValue(4);
mySet.val10.count.inc();
mySet.val10.a.val1.addValue(7);
mySet.val10.a.val2.addValue(2);
mySet.val10.b.val1.addValue(1);
- // Initialize metric manager to get snapshots created.
+ // Initialize metric manager to get snapshots created.
mm.init(ConfigUri("raw:"
"consumer[2]\n"
"consumer[0].name snapper\n"
@@ -953,6 +958,137 @@ TEST_F(MetricManagerTest, text_output_supports_dimensions)
EXPECT_EQ(expected, actual);
}
+TEST_F(MetricManagerTest, prometheus_output_groups_related_time_series) {
+ SameNamesTestMetricSet mset;
+ MetricSnapshotTestFixture fixture(*this, mset);
+
+ mset.set1.val.addValue(2);
+ mset.set1.val.addValue(3);
+ mset.set2.val.addValue(5);
+ mset.set2.val.addValue(7);
+
+ fixture.takeSnapshotsOnce();
+ std::string actual = fixture.render_last_snapshot_as_prometheus();
+ std::string expected(R"(# NOTE: THIS API IS NOT INTENDED FOR PUBLIC USE
+# TYPE outer_temp_val_count untyped
+outer_temp_val_count{foo="bar",fancy="stuff"} 2 1300000
+outer_temp_val_count{foo="baz",fancy="stuff"} 2 1300000
+# TYPE outer_temp_val_max untyped
+outer_temp_val_max{foo="bar",fancy="stuff"} 3 1300000
+outer_temp_val_max{foo="baz",fancy="stuff"} 7 1300000
+# TYPE outer_temp_val_min untyped
+outer_temp_val_min{foo="bar",fancy="stuff"} 2 1300000
+outer_temp_val_min{foo="baz",fancy="stuff"} 5 1300000
+# TYPE outer_temp_val_sum untyped
+outer_temp_val_sum{foo="bar",fancy="stuff"} 5 1300000
+outer_temp_val_sum{foo="baz",fancy="stuff"} 12 1300000
+)");
+ EXPECT_EQ(expected, actual);
+}
+
+struct MetricSetWrapper : MetricSet {
+ MultiSubMetricSet sub;
+
+ MetricSetWrapper();
+ ~MetricSetWrapper() override;
+};
+
+MetricSetWrapper::MetricSetWrapper()
+ : MetricSet("top_level", {}, "stuff and junk", nullptr),
+ sub(this)
+{
+}
+
+MetricSetWrapper::~MetricSetWrapper() = default;
+
+TEST_F(MetricManagerTest, prometheus_output_only_emits_sum_metric_aggregate_values) {
+ MetricSetWrapper mset;
+ MetricSnapshotTestFixture fixture(*this, mset);
+
+ mset.sub.a.val1.addValue(21);
+ mset.sub.a.val2.addValue(17);
+ mset.sub.b.val1.addValue(7);
+ mset.sub.b.val2.addValue(3);
+
+ fixture.takeSnapshotsOnce();
+ std::string actual = fixture.render_last_snapshot_as_prometheus();
+ std::string expected = R"(# NOTE: THIS API IS NOT INTENDED FOR PUBLIC USE
+# TYPE top_level_multisub_sum_val1_count untyped
+top_level_multisub_sum_val1_count 2 1300000
+# TYPE top_level_multisub_sum_val1_max untyped
+top_level_multisub_sum_val1_max 21 1300000
+# TYPE top_level_multisub_sum_val1_min untyped
+top_level_multisub_sum_val1_min 7 1300000
+# TYPE top_level_multisub_sum_val1_sum untyped
+top_level_multisub_sum_val1_sum 56 1300000
+# TYPE top_level_multisub_sum_val2_count untyped
+top_level_multisub_sum_val2_count 2 1300000
+# TYPE top_level_multisub_sum_val2_max untyped
+top_level_multisub_sum_val2_max 17 1300000
+# TYPE top_level_multisub_sum_val2_min untyped
+top_level_multisub_sum_val2_min 3 1300000
+# TYPE top_level_multisub_sum_val2_sum untyped
+top_level_multisub_sum_val2_sum 40 1300000
+# TYPE top_level_multisub_sum_valsum_count untyped
+top_level_multisub_sum_valsum_count 4 1300000
+# TYPE top_level_multisub_sum_valsum_max untyped
+top_level_multisub_sum_valsum_max 21 1300000
+# TYPE top_level_multisub_sum_valsum_min untyped
+top_level_multisub_sum_valsum_min 3 1300000
+# TYPE top_level_multisub_sum_valsum_sum untyped
+top_level_multisub_sum_valsum_sum 192 1300000
+)";
+ EXPECT_EQ(expected, actual);
+}
+
+TEST_F(MetricManagerTest, prometheus_output_can_emit_inf_values_verbatim) {
+ SameNamesTestMetricSet mset;
+ MetricSnapshotTestFixture fixture(*this, mset);
+
+ // We have explicit guards against setting Inf/NaN directly, so we have to fudge the numbers
+ // a bit to get +/- Inf by saturating additions towards infinity. TODO how to test NaN...? :o
+ mset.set1.val.addValue(std::numeric_limits<double>::max());
+ mset.set1.val.addValue(std::numeric_limits<double>::max());
+ mset.set2.val.addValue(std::numeric_limits<double>::lowest());
+ mset.set2.val.addValue(std::numeric_limits<double>::lowest());
+
+ fixture.takeSnapshotsOnce();
+ std::string actual = fixture.render_last_snapshot_as_prometheus();
+ EXPECT_THAT(actual, HasSubstr("outer_temp_val_sum{foo=\"bar\",fancy=\"stuff\"} +Inf 1300000\n"));
+ EXPECT_THAT(actual, HasSubstr("outer_temp_val_sum{foo=\"baz\",fancy=\"stuff\"} -Inf 1300000\n"));
+}
+
+struct SneakyNamesMetricSet : public MetricSet {
+ DoubleValueMetric val1;
+ DoubleValueMetric val2;
+
+ SneakyNamesMetricSet();
+ ~SneakyNamesMetricSet() override;
+};
+
+
+SneakyNamesMetricSet::SneakyNamesMetricSet()
+ : MetricSet("sneaky/path", {}, "sub desc", nullptr),
+ val1("a.name", {{"foo.bar", "blah\nbaz\"zoid\\"}}, "", this),
+ val2("another-name", {}, "", this)
+{
+}
+
+SneakyNamesMetricSet::~SneakyNamesMetricSet() = default;
+
+TEST_F(MetricManagerTest, prometheus_output_normalizes_and_escapes_names_and_labels) {
+ SneakyNamesMetricSet mset;
+ MetricSnapshotTestFixture fixture(*this, mset);
+
+ mset.val1.addValue(123);
+ mset.val2.addValue(42);
+
+ fixture.takeSnapshotsOnce();
+ std::string actual = fixture.render_last_snapshot_as_prometheus();
+ EXPECT_THAT(actual, HasSubstr(R"(sneaky_path_a_name_count{foo_bar="blah\nbaz\"zoid\\"} 1 1300000)"));
+ EXPECT_THAT(actual, HasSubstr("sneaky_path_another_name_count 1 1300000"));
+}
+
namespace {
struct MyUpdateHook : public UpdateHook {
std::ostringstream& _output;