-
Notifications
You must be signed in to change notification settings - Fork 5.3k
metric service: add support for sending tags as labels #16125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -111,7 +111,7 @@ class MetricsServiceSinkTest : public testing::Test { | |
| TEST_F(MetricsServiceSinkTest, CheckSendCall) { | ||
| MetricsServiceSink<envoy::service::metrics::v3::StreamMetricsMessage, | ||
| envoy::service::metrics::v3::StreamMetricsResponse> | ||
| sink(streamer_, false); | ||
| sink(streamer_, false, false); | ||
|
|
||
| auto counter = std::make_shared<NiceMock<Stats::MockCounter>>(); | ||
| counter->name_ = "test_counter"; | ||
|
|
@@ -137,7 +137,7 @@ TEST_F(MetricsServiceSinkTest, CheckSendCall) { | |
| TEST_F(MetricsServiceSinkTest, CheckStatsCount) { | ||
| MetricsServiceSink<envoy::service::metrics::v3::StreamMetricsMessage, | ||
| envoy::service::metrics::v3::StreamMetricsResponse> | ||
| sink(streamer_, false); | ||
| sink(streamer_, false, false); | ||
|
|
||
| auto counter = std::make_shared<NiceMock<Stats::MockCounter>>(); | ||
| counter->name_ = "test_counter"; | ||
|
|
@@ -168,7 +168,7 @@ TEST_F(MetricsServiceSinkTest, CheckStatsCount) { | |
| TEST_F(MetricsServiceSinkTest, ReportCountersValues) { | ||
| MetricsServiceSink<envoy::service::metrics::v3::StreamMetricsMessage, | ||
| envoy::service::metrics::v3::StreamMetricsResponse> | ||
| sink(streamer_, false); | ||
| sink(streamer_, false, false); | ||
|
|
||
| auto counter = std::make_shared<NiceMock<Stats::MockCounter>>(); | ||
| counter->name_ = "test_counter"; | ||
|
|
@@ -187,7 +187,7 @@ TEST_F(MetricsServiceSinkTest, ReportCountersValues) { | |
| TEST_F(MetricsServiceSinkTest, ReportCountersAsDeltas) { | ||
| MetricsServiceSink<envoy::service::metrics::v3::StreamMetricsMessage, | ||
| envoy::service::metrics::v3::StreamMetricsResponse> | ||
| sink(streamer_, true); | ||
| sink(streamer_, true, false); | ||
|
|
||
| auto counter = std::make_shared<NiceMock<Stats::MockCounter>>(); | ||
| counter->name_ = "test_counter"; | ||
|
|
@@ -202,6 +202,86 @@ TEST_F(MetricsServiceSinkTest, ReportCountersAsDeltas) { | |
| sink.flush(snapshot_); | ||
| } | ||
|
|
||
| // Test the behavior of tag emission based on the emit_tags_as_label flag. | ||
| TEST_F(MetricsServiceSinkTest, ReportMetricsWithTags) { | ||
| auto counter = std::make_shared<NiceMock<Stats::MockCounter>>(); | ||
| counter->name_ = "full-counter-name"; | ||
| counter->value_ = 100; | ||
| counter->used_ = true; | ||
| counter->setTagExtractedName("tag-counter-name"); | ||
| counter->setTags({{"a", "b"}}); | ||
| snapshot_.counters_.push_back({1, *counter}); | ||
|
|
||
| auto gauge = std::make_shared<NiceMock<Stats::MockGauge>>(); | ||
| gauge->name_ = "full-gauge-name"; | ||
| gauge->value_ = 100; | ||
| gauge->used_ = true; | ||
| gauge->setTagExtractedName("tag-gauge-name"); | ||
| gauge->setTags({{"a", "b"}}); | ||
| snapshot_.gauges_.push_back({*gauge}); | ||
|
|
||
| auto histogram = std::make_shared<NiceMock<Stats::MockParentHistogram>>(); | ||
| histogram->name_ = "full-histogram-name"; | ||
| histogram->used_ = true; | ||
| histogram->setTagExtractedName("tag-histogram-name"); | ||
| histogram->setTags({{"a", "b"}}); | ||
| snapshot_.histograms_.push_back({*histogram}); | ||
|
|
||
| { | ||
| // When the emit_tags flag is false, we don't emit the tags and use the full name. | ||
| MetricsServiceSink<envoy::service::metrics::v3::StreamMetricsMessage, | ||
| envoy::service::metrics::v3::StreamMetricsResponse> | ||
| sink(streamer_, true, false); | ||
|
|
||
| EXPECT_CALL(*streamer_, send(_)).WillOnce(Invoke([](MetricsPtr&& metrics) { | ||
| EXPECT_EQ(4, metrics->size()); | ||
|
|
||
| EXPECT_EQ("full-counter-name", (*metrics)[0].name()); | ||
| EXPECT_EQ(0, (*metrics)[0].metric(0).label().size()); | ||
|
|
||
| EXPECT_EQ("full-gauge-name", (*metrics)[1].name()); | ||
| EXPECT_EQ(0, (*metrics)[1].metric(0).label().size()); | ||
|
|
||
| EXPECT_EQ("full-histogram-name", (*metrics)[2].name()); | ||
| EXPECT_EQ(0, (*metrics)[2].metric(0).label().size()); | ||
|
|
||
| EXPECT_EQ("full-histogram-name", (*metrics)[3].name()); | ||
| EXPECT_EQ(0, (*metrics)[3].metric(0).label().size()); | ||
| })); | ||
| sink.flush(snapshot_); | ||
| } | ||
|
|
||
| io::prometheus::client::LabelPair expected_label_pair; | ||
| expected_label_pair.set_name("a"); | ||
| expected_label_pair.set_value("b"); | ||
|
|
||
| // When the emit_tags flag is true, we emit the tags as labels and use the tag extracted name. | ||
| MetricsServiceSink<envoy::service::metrics::v3::StreamMetricsMessage, | ||
| envoy::service::metrics::v3::StreamMetricsResponse> | ||
| sink(streamer_, true, true); | ||
|
|
||
| EXPECT_CALL(*streamer_, send(_)).WillOnce(Invoke([&expected_label_pair](MetricsPtr&& metrics) { | ||
| EXPECT_EQ(4, metrics->size()); | ||
|
|
||
| EXPECT_EQ("tag-counter-name", (*metrics)[0].name()); | ||
| EXPECT_EQ(1, (*metrics)[0].metric(0).label().size()); | ||
| EXPECT_TRUE(TestUtility::protoEqual(expected_label_pair, (*metrics)[0].metric(0).label()[0])); | ||
|
|
||
| EXPECT_EQ("tag-gauge-name", (*metrics)[1].name()); | ||
| EXPECT_EQ(1, (*metrics)[1].metric(0).label().size()); | ||
| EXPECT_TRUE(TestUtility::protoEqual(expected_label_pair, (*metrics)[0].metric(0).label()[0])); | ||
|
|
||
| EXPECT_EQ("tag-histogram-name", (*metrics)[2].name()); | ||
| EXPECT_EQ(1, (*metrics)[2].metric(0).label().size()); | ||
| EXPECT_TRUE(TestUtility::protoEqual(expected_label_pair, (*metrics)[0].metric(0).label()[0])); | ||
|
|
||
| EXPECT_EQ("tag-histogram-name", (*metrics)[3].name()); | ||
| EXPECT_EQ(1, (*metrics)[3].metric(0).label().size()); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. check the labels are the ones we expect also? |
||
| EXPECT_TRUE(TestUtility::protoEqual(expected_label_pair, (*metrics)[0].metric(0).label()[0])); | ||
| })); | ||
| sink.flush(snapshot_); | ||
| } | ||
|
|
||
| } // namespace | ||
| } // namespace MetricsService | ||
| } // namespace StatSinks | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm. I'm wondering if this is going to be a perf issue as constructing the tag array is going to take symbol table locks and do some string-building, with those strings then being copied again below.
It might be slightly better to use metric::iterateTagStatNames but we'd still need to convert to strings here. Maybe this transformation should be cached somehow in the MetricsFlusher object?
Maybe leave a note here to take a look at the perf implications of this later? The reason I'm concerned about this is that it looks like this is called on every flush, each with its own value, but it's re-creating a bunch of metadata for each stat that doesn't change. It'd be nice to factor that repeated computation out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah let me leave a note here to look into the perf of this.
I think there are two options that could be explored: 1) cache just the symbol -> string conversion just to avoid the locks on the symbol table or 2) cache the entire prom Metric per stat. I'm not sure how much 2) gains us over 1) since we'll need to copy the proto completely anyways, so it might just result in a lot of wasted space keeping all these protos stored in memory? At least with 1) we get the benefit of space savings if a symbol is reused between stats. In any case I will leave this as a TODO for now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. One minor concern to note also is that if we add a cache, it could retain storage for stats that belong to deleted scopes, thus leaking. We can fix all that but it's definitely a separate PR.