Skip to content

Commit 8f8f295

Browse files
committed
Address Copilot review feedback: use exposed target_info name for collision check
1 parent 4cbcfa3 commit 8f8f295

2 files changed

Lines changed: 56 additions & 1 deletion

File tree

‎exporters/prometheus/src/exporter_utils.cc‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,10 @@ std::vector<prometheus_client::MetricFamily> PrometheusExporterUtils::TranslateT
141141
std::unordered_map<std::string, std::size_t> family_index_by_name;
142142
for (std::size_t i = 0; i < output.size(); ++i)
143143
{
144-
family_index_by_name.emplace(output[i].name, i);
144+
std::string exposed_name = output[i].type == prometheus_client::MetricType::Info
145+
? output[i].name + "_info"
146+
: output[i].name;
147+
family_index_by_name.emplace(std::move(exposed_name), i);
145148
}
146149

147150
for (const auto &instrumentation_info : data.scope_metric_data_)

‎exporters/prometheus/test/exporter_utils_test.cc‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,4 +617,56 @@ TEST(PrometheusExporterUtils, MultipleScopesMetricFamilyCollisions)
617617
EXPECT_DOUBLE_EQ(translated[0].metric[1].counter.value, 20.0);
618618
}
619619

620+
TEST(PrometheusExporterUtils, TargetInfoMetricFamilyCollisions)
621+
{
622+
Resource resource = Resource::Create(ResourceAttributes{{"service.name", "test_service"}});
623+
auto scope = InstrumentationScope::Create("scope_1", "1.0.0");
624+
625+
metric_sdk::LastValuePointData target_gauge_point{};
626+
target_gauge_point.value_ = 42.0;
627+
target_gauge_point.is_lastvalue_valid_ = true;
628+
629+
metric_sdk::LastValuePointData target_info_gauge_point{};
630+
target_info_gauge_point.value_ = 99.0;
631+
target_info_gauge_point.is_lastvalue_valid_ = true;
632+
633+
// A unitless gauge named "target" does not collide with the generated Info family
634+
// (which is exposed as "target_info" in Prometheus text format).
635+
metric_sdk::MetricData target_gauge{
636+
metric_sdk::InstrumentDescriptor{"target", "target gauge description", "",
637+
metric_sdk::InstrumentType::kObservableGauge,
638+
metric_sdk::InstrumentValueType::kDouble},
639+
metric_sdk::AggregationTemporality::kCumulative, opentelemetry::common::SystemTimestamp{},
640+
opentelemetry::common::SystemTimestamp{},
641+
std::vector<metric_sdk::PointDataAttributes>{{{}, target_gauge_point}}};
642+
643+
// A gauge named "target_info" collides with the generated Info family exposed as
644+
// "target_info" and is dropped due to type conflict.
645+
metric_sdk::MetricData target_info_gauge{
646+
metric_sdk::InstrumentDescriptor{"target_info", "conflicting target_info gauge", "",
647+
metric_sdk::InstrumentType::kObservableGauge,
648+
metric_sdk::InstrumentValueType::kDouble},
649+
metric_sdk::AggregationTemporality::kCumulative, opentelemetry::common::SystemTimestamp{},
650+
opentelemetry::common::SystemTimestamp{},
651+
std::vector<metric_sdk::PointDataAttributes>{{{}, target_info_gauge_point}}};
652+
653+
metric_sdk::ResourceMetrics data{
654+
&resource,
655+
std::vector<metric_sdk::ScopeMetrics>{
656+
{scope.get(), std::vector<metric_sdk::MetricData>{target_gauge, target_info_gauge}}}};
657+
658+
auto translated = PrometheusExporterUtils::TranslateToPrometheus(
659+
data, /*populate_target_info=*/true, /*without_otel_scope=*/false,
660+
/*without_units=*/false, /*without_type_suffix=*/false);
661+
662+
ASSERT_EQ(translated.size(), 2U);
663+
EXPECT_EQ(translated[0].name, "target");
664+
EXPECT_EQ(translated[0].type, prometheus_client::MetricType::Info);
665+
EXPECT_EQ(translated[1].name, "target");
666+
EXPECT_EQ(translated[1].help, "target gauge description");
667+
EXPECT_EQ(translated[1].type, prometheus_client::MetricType::Gauge);
668+
ASSERT_EQ(translated[1].metric.size(), 1U);
669+
EXPECT_DOUBLE_EQ(translated[1].metric[0].gauge.value, 42.0);
670+
}
671+
620672
OPENTELEMETRY_END_NAMESPACE

0 commit comments

Comments
 (0)