diff --git a/.chloggen/prometheus-metrics-family-fix.yaml b/.chloggen/prometheus-metrics-family-fix.yaml new file mode 100644 index 000000000000..fef45d1d42a7 --- /dev/null +++ b/.chloggen/prometheus-metrics-family-fix.yaml @@ -0,0 +1,4 @@ +change_type: bug_fix +component: prometheusreceiver +note: Fix metrics being grouped into the same metrics family incorrectly +issues: [13117] diff --git a/receiver/prometheusreceiver/internal/transaction.go b/receiver/prometheusreceiver/internal/transaction.go index f9f08eecac90..ab2c9ae876c2 100644 --- a/receiver/prometheusreceiver/internal/transaction.go +++ b/receiver/prometheusreceiver/internal/transaction.go @@ -132,7 +132,10 @@ func (t *transaction) Append(ref storage.SeriesRef, ls labels.Labels, atMs int64 func (t *transaction) getOrCreateMetricFamily(mn string) *metricFamily { curMf, ok := t.families[mn] if !ok { - fn := normalizeMetricName(mn) + fn := mn + if _, ok := t.mc.GetMetadata(mn); !ok { + fn = normalizeMetricName(mn) + } if mf, ok := t.families[fn]; ok && mf.includesMetric(mn) { curMf = mf } else { diff --git a/receiver/prometheusreceiver/metrics_receiver_test.go b/receiver/prometheusreceiver/metrics_receiver_test.go index adec27b3a66f..44fabfe9671c 100644 --- a/receiver/prometheusreceiver/metrics_receiver_test.go +++ b/receiver/prometheusreceiver/metrics_receiver_test.go @@ -1076,6 +1076,15 @@ rpc_duration_seconds_sum{foo="no_quantile"} 101 rpc_duration_seconds_count{foo="no_quantile"} 55 ` +var target4Page1 = ` +# A simple counter +# TYPE foo counter +foo 0 +# Another counter with the same name but also _total suffix +# TYPE foo_total counter +foo_total 1 +` + func verifyTarget3(t *testing.T, td *testData, resourceMetrics []pmetric.ResourceMetrics) { verifyNumValidScrapeResults(t, td, resourceMetrics) m1 := resourceMetrics[0] @@ -1185,6 +1194,42 @@ func verifyTarget3(t *testing.T, td *testData, resourceMetrics []pmetric.Resourc doCompare(t, "scrape2", wantAttributes, m2, e2) } +func verifyTarget4(t *testing.T, td *testData, resourceMetrics []pmetric.ResourceMetrics) { + verifyNumValidScrapeResults(t, td, resourceMetrics) + m1 := resourceMetrics[0] + + // m1 has 2 metrics + 5 internal scraper metrics + assert.Equal(t, 7, metricsCount(m1)) + + wantAttributes := td.attributes + + metrics1 := m1.ScopeMetrics().At(0).Metrics() + ts1 := getTS(metrics1) + e1 := []testExpectation{ + assertMetricPresent("foo", + compareMetricIsMonotonic(true), + []dataPointExpectation{ + { + numberPointComparator: []numberPointComparator{ + compareTimestamp(ts1), + compareDoubleValue(0), + }, + }, + }), + assertMetricPresent("foo_info", + compareMetricIsMonotonic(true), + []dataPointExpectation{ + { + numberPointComparator: []numberPointComparator{ + compareTimestamp(ts1), + compareDoubleValue(1.0), + }, + }, + }), + } + doCompare(t, "scrape-infostatesetmetrics-1", wantAttributes, m1, e1) +} + // TestCoreMetricsEndToEnd end to end test executor func TestCoreMetricsEndToEnd(t *testing.T) { // 1. setup input data @@ -1221,6 +1266,14 @@ func TestCoreMetricsEndToEnd(t *testing.T) { }, validateFunc: verifyTarget3, }, + { + name: "target4", + pages: []mockPrometheusResponse{ + {code: 200, data: target4Page1, useOpenMetrics: false}, + }, + validateFunc: verifyTarget4, + validateScrapes: true, + }, } testComponent(t, targets, false, "") }