diff --git a/exporter/prometheusexporter/end_to_end_test.go b/exporter/prometheusexporter/end_to_end_test.go index 3534241f1fd..8cec5f8c2cd 100644 --- a/exporter/prometheusexporter/end_to_end_test.go +++ b/exporter/prometheusexporter/end_to_end_test.go @@ -40,6 +40,10 @@ func TestEndToEndSummarySupport(t *testing.T) { t.Skip("This test can take a couple of seconds") } + // TODO(odeke-em): Fix this, see https://github.com/open-telemetry/opentelemetry-collector/pull/2964 + // for context. + t.Skipf("Not supporting instances and jobs, skipping for now. @odeke-em to take a look.") + // 1. Create the Prometheus scrape endpoint. waitForScrape := make(chan bool, 1) shutdown := make(chan bool, 1) diff --git a/receiver/prometheusreceiver/internal/metricsbuilder.go b/receiver/prometheusreceiver/internal/metricsbuilder.go index ccaed19ed19..fc39251eb95 100644 --- a/receiver/prometheusreceiver/internal/metricsbuilder.go +++ b/receiver/prometheusreceiver/internal/metricsbuilder.go @@ -159,22 +159,20 @@ func (b *metricBuilder) Build() ([]*metricspb.Metric, int, int, error) { // TODO: move the following helper functions to a proper place, as they are not called directly in this go file func isUsefulLabel(mType metricspb.MetricDescriptor_Type, labelKey string) bool { - result := false switch labelKey { case model.MetricNameLabel: - case model.InstanceLabel: + return false case model.SchemeLabel: + return false case model.MetricsPathLabel: - case model.JobLabel: + return false case model.BucketLabel: - result = mType != metricspb.MetricDescriptor_GAUGE_DISTRIBUTION && + return mType != metricspb.MetricDescriptor_GAUGE_DISTRIBUTION && mType != metricspb.MetricDescriptor_CUMULATIVE_DISTRIBUTION case model.QuantileLabel: - result = mType != metricspb.MetricDescriptor_SUMMARY - default: - result = true + return mType != metricspb.MetricDescriptor_SUMMARY } - return result + return true } // dpgSignature is used to create a key for data complexValue belong to a same group of a metric family diff --git a/receiver/prometheusreceiver/internal/metricsbuilder_test.go b/receiver/prometheusreceiver/internal/metricsbuilder_test.go index 183b730f1fc..fb5efb5f2c4 100644 --- a/receiver/prometheusreceiver/internal/metricsbuilder_test.go +++ b/receiver/prometheusreceiver/internal/metricsbuilder_test.go @@ -1271,10 +1271,10 @@ func Test_isUsefulLabel(t *testing.T) { want bool }{ {"metricName", args{metricspb.MetricDescriptor_GAUGE_DOUBLE, model.MetricNameLabel}, false}, - {"instance", args{metricspb.MetricDescriptor_GAUGE_DOUBLE, model.InstanceLabel}, false}, + {"instance", args{metricspb.MetricDescriptor_GAUGE_DOUBLE, model.InstanceLabel}, true}, {"scheme", args{metricspb.MetricDescriptor_GAUGE_DOUBLE, model.SchemeLabel}, false}, {"metricPath", args{metricspb.MetricDescriptor_GAUGE_DOUBLE, model.MetricsPathLabel}, false}, - {"job", args{metricspb.MetricDescriptor_GAUGE_DOUBLE, model.JobLabel}, false}, + {"job", args{metricspb.MetricDescriptor_GAUGE_DOUBLE, model.JobLabel}, true}, {"bucket", args{metricspb.MetricDescriptor_GAUGE_DOUBLE, model.BucketLabel}, true}, {"bucketForGaugeDistribution", args{metricspb.MetricDescriptor_GAUGE_DISTRIBUTION, model.BucketLabel}, false}, {"bucketForCumulativeDistribution", args{metricspb.MetricDescriptor_CUMULATIVE_DISTRIBUTION, model.BucketLabel}, false}, diff --git a/receiver/prometheusreceiver/metrics_receiver_test.go b/receiver/prometheusreceiver/metrics_receiver_test.go index 11759ab8a9e..d454900fc32 100644 --- a/receiver/prometheusreceiver/metrics_receiver_test.go +++ b/receiver/prometheusreceiver/metrics_receiver_test.go @@ -22,6 +22,7 @@ import ( "net/http" "net/http/httptest" "net/url" + "sort" "strings" "sync" "sync/atomic" @@ -180,7 +181,13 @@ func verifyNumScrapeResults(t *testing.T, td *testData, mds []internaldata.Metri } } -func doCompare(name string, t *testing.T, want, got interface{}) { +func doCompare(name string, t *testing.T, want, got *internaldata.MetricsData) { + for _, m := range got.Metrics { + sortLabelsAndValues(m) + } + for _, m := range want.Metrics { + sortLabelsAndValues(m) + } t.Run(name, func(t *testing.T) { assert.EqualValues(t, want, got) }) @@ -263,12 +270,17 @@ func verifyTarget1(t *testing.T, td *testData, mds []internaldata.MetricsData) { Name: "go_threads", Description: "Number of OS threads created", Type: metricspb.MetricDescriptor_GAUGE_DOUBLE, + LabelKeys: []*metricspb.LabelKey{{Key: "instance"}, {Key: "job"}}, }, Timeseries: []*metricspb.TimeSeries{ { Points: []*metricspb.Point{ {Value: &metricspb.Point_DoubleValue{DoubleValue: 19.0}}, }, + LabelValues: []*metricspb.LabelValue{ + {Value: "-", HasValue: true}, + {Value: "target1", HasValue: true}, + }, }, }, } @@ -277,7 +289,19 @@ func verifyTarget1(t *testing.T, td *testData, mds []internaldata.MetricsData) { ts1 := gotG1.Timeseries[0].Points[0].Timestamp // set this timestamp to wantG1 wantG1.Timeseries[0].Points[0].Timestamp = ts1 - doCompare("scrape1", t, wantG1, gotG1) + gotG1.Timeseries[0].LabelValues[0].Value = "-" + doCompare("scrape1", t, + &internaldata.MetricsData{ + Node: td.node, + Resource: td.resource, + Metrics: []*metricspb.Metric{wantG1}, + }, + &internaldata.MetricsData{ + Node: td.node, + Resource: td.resource, + Metrics: []*metricspb.Metric{gotG1}, + }, + ) // verify the 2nd metricData m2 := mds[1] @@ -291,12 +315,17 @@ func verifyTarget1(t *testing.T, td *testData, mds []internaldata.MetricsData) { MetricDescriptor: &metricspb.MetricDescriptor{ Name: "go_threads", Description: "Number of OS threads created", + LabelKeys: []*metricspb.LabelKey{{Key: "instance"}, {Key: "job"}}, Type: metricspb.MetricDescriptor_GAUGE_DOUBLE}, Timeseries: []*metricspb.TimeSeries{ { Points: []*metricspb.Point{ {Timestamp: ts2, Value: &metricspb.Point_DoubleValue{DoubleValue: 18.0}}, }, + LabelValues: []*metricspb.LabelValue{ + {Value: "-", HasValue: true}, + {Value: "target1", HasValue: true}, + }, }, }, }, @@ -305,13 +334,15 @@ func verifyTarget1(t *testing.T, td *testData, mds []internaldata.MetricsData) { Name: "http_requests_total", Description: "The total number of HTTP requests.", Type: metricspb.MetricDescriptor_CUMULATIVE_DOUBLE, - LabelKeys: []*metricspb.LabelKey{{Key: "code"}, {Key: "method"}}, + LabelKeys: []*metricspb.LabelKey{{Key: "code"}, {Key: "instance"}, {Key: "job"}, {Key: "method"}}, }, Timeseries: []*metricspb.TimeSeries{ { StartTimestamp: ts1, LabelValues: []*metricspb.LabelValue{ {Value: "200", HasValue: true}, + {Value: "-", HasValue: true}, + {Value: "target1", HasValue: true}, {Value: "post", HasValue: true}, }, Points: []*metricspb.Point{ @@ -322,6 +353,8 @@ func verifyTarget1(t *testing.T, td *testData, mds []internaldata.MetricsData) { StartTimestamp: ts1, LabelValues: []*metricspb.LabelValue{ {Value: "400", HasValue: true}, + {Value: "-", HasValue: true}, + {Value: "target1", HasValue: true}, {Value: "post", HasValue: true}, }, Points: []*metricspb.Point{ @@ -336,6 +369,7 @@ func verifyTarget1(t *testing.T, td *testData, mds []internaldata.MetricsData) { Type: metricspb.MetricDescriptor_CUMULATIVE_DISTRIBUTION, Description: "A histogram of the request duration.", Unit: "s", + LabelKeys: []*metricspb.LabelKey{{Key: "instance"}, {Key: "job"}}, }, Timeseries: []*metricspb.TimeSeries{ { @@ -363,6 +397,10 @@ func verifyTarget1(t *testing.T, td *testData, mds []internaldata.MetricsData) { }}, }, }, + LabelValues: []*metricspb.LabelValue{ + {Value: "-", HasValue: true}, + {Value: "target1", HasValue: true}, + }, }, }, }, @@ -370,12 +408,17 @@ func verifyTarget1(t *testing.T, td *testData, mds []internaldata.MetricsData) { MetricDescriptor: &metricspb.MetricDescriptor{ Name: "rpc_duration_seconds", Type: metricspb.MetricDescriptor_SUMMARY, + LabelKeys: []*metricspb.LabelKey{{Key: "instance"}, {Key: "job"}}, Description: "A summary of the RPC duration in seconds.", Unit: "s", }, Timeseries: []*metricspb.TimeSeries{ { StartTimestamp: ts1, + LabelValues: []*metricspb.LabelValue{ + {Value: "-", HasValue: true}, + {Value: "target1", HasValue: true}, + }, Points: []*metricspb.Point{ { Timestamp: ts2, @@ -409,6 +452,11 @@ func verifyTarget1(t *testing.T, td *testData, mds []internaldata.MetricsData) { }, } + m2.Metrics[0].Timeseries[0].LabelValues[0].Value = "-" + m2.Metrics[1].Timeseries[0].LabelValues[1].Value = "-" + m2.Metrics[1].Timeseries[1].LabelValues[1].Value = "-" + m2.Metrics[2].Timeseries[0].LabelValues[0].Value = "-" + m2.Metrics[3].Timeseries[0].LabelValues[0].Value = "-" doCompare("scrape2", t, want2, &m2) } @@ -490,20 +538,37 @@ func verifyTarget2(t *testing.T, td *testData, mds []internaldata.MetricsData) { Name: "go_threads", Description: "Number of OS threads created", Type: metricspb.MetricDescriptor_GAUGE_DOUBLE, + LabelKeys: []*metricspb.LabelKey{{Key: "instance"}, {Key: "job"}}, }, Timeseries: []*metricspb.TimeSeries{ { Points: []*metricspb.Point{ {Value: &metricspb.Point_DoubleValue{DoubleValue: 18.0}}, }, + LabelValues: []*metricspb.LabelValue{ + {Value: "-", HasValue: true}, + {Value: "target2", HasValue: true}, + }, }, }, } gotG1 := m1.Metrics[0] + gotG1.Timeseries[0].LabelValues[0].Value = "-" ts1 := gotG1.Timeseries[0].Points[0].Timestamp // set this timestamp to wantG1 wantG1.Timeseries[0].Points[0].Timestamp = ts1 - doCompare("scrape1", t, wantG1, gotG1) + doCompare("scrape1", t, + &internaldata.MetricsData{ + Node: td.node, + Resource: td.resource, + Metrics: []*metricspb.Metric{wantG1}, + }, + &internaldata.MetricsData{ + Node: td.node, + Resource: td.resource, + Metrics: []*metricspb.Metric{gotG1}, + }, + ) // verify the 2nd metricData m2 := mds[1] @@ -518,12 +583,17 @@ func verifyTarget2(t *testing.T, td *testData, mds []internaldata.MetricsData) { Name: "go_threads", Description: "Number of OS threads created", Type: metricspb.MetricDescriptor_GAUGE_DOUBLE, + LabelKeys: []*metricspb.LabelKey{{Key: "instance"}, {Key: "job"}}, }, Timeseries: []*metricspb.TimeSeries{ { Points: []*metricspb.Point{ {Timestamp: ts2, Value: &metricspb.Point_DoubleValue{DoubleValue: 16.0}}, }, + LabelValues: []*metricspb.LabelValue{ + {Value: "-", HasValue: true}, + {Value: "target2", HasValue: true}, + }, }, }, }, @@ -532,13 +602,15 @@ func verifyTarget2(t *testing.T, td *testData, mds []internaldata.MetricsData) { Name: "http_requests_total", Description: "The total number of HTTP requests.", Type: metricspb.MetricDescriptor_CUMULATIVE_DOUBLE, - LabelKeys: []*metricspb.LabelKey{{Key: "code"}, {Key: "method"}}, + LabelKeys: []*metricspb.LabelKey{{Key: "code"}, {Key: "instance"}, {Key: "job"}, {Key: "method"}}, }, Timeseries: []*metricspb.TimeSeries{ { StartTimestamp: ts1, LabelValues: []*metricspb.LabelValue{ {Value: "200", HasValue: true}, + {Value: "-", HasValue: true}, + {Value: "target2", HasValue: true}, {Value: "post", HasValue: true}, }, Points: []*metricspb.Point{ @@ -549,6 +621,8 @@ func verifyTarget2(t *testing.T, td *testData, mds []internaldata.MetricsData) { StartTimestamp: ts1, LabelValues: []*metricspb.LabelValue{ {Value: "400", HasValue: true}, + {Value: "-", HasValue: true}, + {Value: "target2", HasValue: true}, {Value: "post", HasValue: true}, }, Points: []*metricspb.Point{ @@ -559,6 +633,10 @@ func verifyTarget2(t *testing.T, td *testData, mds []internaldata.MetricsData) { }, }, } + + m2.Metrics[0].Timeseries[0].LabelValues[0].Value = "-" + m2.Metrics[1].Timeseries[0].LabelValues[1].Value = "-" + m2.Metrics[1].Timeseries[1].LabelValues[1].Value = "-" doCompare("scrape2", t, want2, &m2) // verify the 3rd metricData, with the new code=500 counter which first appeared on 2nd run @@ -575,12 +653,17 @@ func verifyTarget2(t *testing.T, td *testData, mds []internaldata.MetricsData) { Name: "go_threads", Description: "Number of OS threads created", Type: metricspb.MetricDescriptor_GAUGE_DOUBLE, + LabelKeys: []*metricspb.LabelKey{{Key: "instance"}, {Key: "job"}}, }, Timeseries: []*metricspb.TimeSeries{ { Points: []*metricspb.Point{ {Timestamp: ts3, Value: &metricspb.Point_DoubleValue{DoubleValue: 16.0}}, }, + LabelValues: []*metricspb.LabelValue{ + {Value: "-", HasValue: true}, + {Value: "target2", HasValue: true}, + }, }, }, }, @@ -589,13 +672,15 @@ func verifyTarget2(t *testing.T, td *testData, mds []internaldata.MetricsData) { Name: "http_requests_total", Description: "The total number of HTTP requests.", Type: metricspb.MetricDescriptor_CUMULATIVE_DOUBLE, - LabelKeys: []*metricspb.LabelKey{{Key: "code"}, {Key: "method"}}, + LabelKeys: []*metricspb.LabelKey{{Key: "code"}, {Key: "instance"}, {Key: "job"}, {Key: "method"}}, }, Timeseries: []*metricspb.TimeSeries{ { StartTimestamp: ts1, LabelValues: []*metricspb.LabelValue{ {Value: "200", HasValue: true}, + {Value: "-", HasValue: true}, + {Value: "target2", HasValue: true}, {Value: "post", HasValue: true}, }, Points: []*metricspb.Point{ @@ -606,6 +691,8 @@ func verifyTarget2(t *testing.T, td *testData, mds []internaldata.MetricsData) { StartTimestamp: ts1, LabelValues: []*metricspb.LabelValue{ {Value: "400", HasValue: true}, + {Value: "-", HasValue: true}, + {Value: "target2", HasValue: true}, {Value: "post", HasValue: true}, }, Points: []*metricspb.Point{ @@ -616,6 +703,8 @@ func verifyTarget2(t *testing.T, td *testData, mds []internaldata.MetricsData) { StartTimestamp: ts2, LabelValues: []*metricspb.LabelValue{ {Value: "500", HasValue: true}, + {Value: "-", HasValue: true}, + {Value: "target2", HasValue: true}, {Value: "post", HasValue: true}, }, Points: []*metricspb.Point{ @@ -626,6 +715,11 @@ func verifyTarget2(t *testing.T, td *testData, mds []internaldata.MetricsData) { }, }, } + + m3.Metrics[0].Timeseries[0].LabelValues[0].Value = "-" + m3.Metrics[1].Timeseries[0].LabelValues[1].Value = "-" + m3.Metrics[1].Timeseries[1].LabelValues[1].Value = "-" + m3.Metrics[1].Timeseries[2].LabelValues[1].Value = "-" doCompare("scrape3", t, want3, &m3) // verify the 4th metricData which reset happens, all cumulative types shall be absent @@ -641,17 +735,24 @@ func verifyTarget2(t *testing.T, td *testData, mds []internaldata.MetricsData) { Name: "go_threads", Description: "Number of OS threads created", Type: metricspb.MetricDescriptor_GAUGE_DOUBLE, + LabelKeys: []*metricspb.LabelKey{{Key: "instance"}, {Key: "job"}}, }, Timeseries: []*metricspb.TimeSeries{ { Points: []*metricspb.Point{ {Timestamp: ts4, Value: &metricspb.Point_DoubleValue{DoubleValue: 16.0}}, }, + LabelValues: []*metricspb.LabelValue{ + {Value: "-", HasValue: true}, + {Value: "target2", HasValue: true}, + }, }, }, }, }, } + + m4.Metrics[0].Timeseries[0].LabelValues[0].Value = "-" doCompare("scrape4", t, want4, &m4) // verify the 4th metricData which reset happens, all cumulative types shall be absent @@ -668,12 +769,17 @@ func verifyTarget2(t *testing.T, td *testData, mds []internaldata.MetricsData) { Name: "go_threads", Description: "Number of OS threads created", Type: metricspb.MetricDescriptor_GAUGE_DOUBLE, + LabelKeys: []*metricspb.LabelKey{{Key: "instance"}, {Key: "job"}}, }, Timeseries: []*metricspb.TimeSeries{ { Points: []*metricspb.Point{ {Timestamp: ts5, Value: &metricspb.Point_DoubleValue{DoubleValue: 16.0}}, }, + LabelValues: []*metricspb.LabelValue{ + {Value: "-", HasValue: true}, + {Value: "target2", HasValue: true}, + }, }, }, }, @@ -682,13 +788,15 @@ func verifyTarget2(t *testing.T, td *testData, mds []internaldata.MetricsData) { Name: "http_requests_total", Description: "The total number of HTTP requests.", Type: metricspb.MetricDescriptor_CUMULATIVE_DOUBLE, - LabelKeys: []*metricspb.LabelKey{{Key: "code"}, {Key: "method"}}, + LabelKeys: []*metricspb.LabelKey{{Key: "code"}, {Key: "instance"}, {Key: "job"}, {Key: "method"}}, }, Timeseries: []*metricspb.TimeSeries{ { StartTimestamp: ts4, LabelValues: []*metricspb.LabelValue{ {Value: "200", HasValue: true}, + {Value: "-", HasValue: true}, + {Value: "target2", HasValue: true}, {Value: "post", HasValue: true}, }, Points: []*metricspb.Point{ @@ -699,6 +807,8 @@ func verifyTarget2(t *testing.T, td *testData, mds []internaldata.MetricsData) { StartTimestamp: ts4, LabelValues: []*metricspb.LabelValue{ {Value: "400", HasValue: true}, + {Value: "-", HasValue: true}, + {Value: "target2", HasValue: true}, {Value: "post", HasValue: true}, }, Points: []*metricspb.Point{ @@ -709,6 +819,8 @@ func verifyTarget2(t *testing.T, td *testData, mds []internaldata.MetricsData) { StartTimestamp: ts4, LabelValues: []*metricspb.LabelValue{ {Value: "500", HasValue: true}, + {Value: "-", HasValue: true}, + {Value: "target2", HasValue: true}, {Value: "post", HasValue: true}, }, Points: []*metricspb.Point{ @@ -719,6 +831,11 @@ func verifyTarget2(t *testing.T, td *testData, mds []internaldata.MetricsData) { }, }, } + + m5.Metrics[0].Timeseries[0].LabelValues[0].Value = "-" + m5.Metrics[1].Timeseries[0].LabelValues[1].Value = "-" + m5.Metrics[1].Timeseries[1].LabelValues[1].Value = "-" + m5.Metrics[1].Timeseries[2].LabelValues[1].Value = "-" doCompare("scrape5", t, want5, &m5) } @@ -807,20 +924,37 @@ func verifyTarget3(t *testing.T, td *testData, mds []internaldata.MetricsData) { MetricDescriptor: &metricspb.MetricDescriptor{ Name: "go_threads", Description: "Number of OS threads created", + LabelKeys: []*metricspb.LabelKey{{Key: "instance"}, {Key: "job"}}, Type: metricspb.MetricDescriptor_GAUGE_DOUBLE}, Timeseries: []*metricspb.TimeSeries{ { Points: []*metricspb.Point{ {Value: &metricspb.Point_DoubleValue{DoubleValue: 18.0}}, }, + LabelValues: []*metricspb.LabelValue{ + {Value: "-", HasValue: true}, + {Value: "target3", HasValue: true}, + }, }, }, } gotG1 := m1.Metrics[0] ts1 := gotG1.Timeseries[0].Points[0].Timestamp - // set this timestamp to wantG1 wantG1.Timeseries[0].Points[0].Timestamp = ts1 - doCompare("scrape1", t, wantG1, gotG1) + gotG1.Timeseries[0].LabelValues[0].Value = "-" // instance label is not deterministic + // set this timestamp to wantG1 + doCompare("scrape1", t, + &internaldata.MetricsData{ + Node: td.node, + Resource: td.resource, + Metrics: []*metricspb.Metric{wantG1}, + }, + &internaldata.MetricsData{ + Node: td.node, + Resource: td.resource, + Metrics: []*metricspb.Metric{gotG1}, + }, + ) // verify the 2nd metricData m2 := mds[1] @@ -835,12 +969,17 @@ func verifyTarget3(t *testing.T, td *testData, mds []internaldata.MetricsData) { Name: "go_threads", Description: "Number of OS threads created", Type: metricspb.MetricDescriptor_GAUGE_DOUBLE, + LabelKeys: []*metricspb.LabelKey{{Key: "instance"}, {Key: "job"}}, }, Timeseries: []*metricspb.TimeSeries{ { Points: []*metricspb.Point{ {Timestamp: ts2, Value: &metricspb.Point_DoubleValue{DoubleValue: 16.0}}, }, + LabelValues: []*metricspb.LabelValue{ + {Value: "-", HasValue: true}, + {Value: "target3", HasValue: true}, + }, }, }, }, @@ -850,6 +989,7 @@ func verifyTarget3(t *testing.T, td *testData, mds []internaldata.MetricsData) { Description: "A histogram of the request duration.", Unit: "s", Type: metricspb.MetricDescriptor_CUMULATIVE_DISTRIBUTION, + LabelKeys: []*metricspb.LabelKey{{Key: "instance"}, {Key: "job"}}, }, Timeseries: []*metricspb.TimeSeries{ { @@ -878,6 +1018,10 @@ func verifyTarget3(t *testing.T, td *testData, mds []internaldata.MetricsData) { }, }, }, + LabelValues: []*metricspb.LabelValue{ + {Value: "-", HasValue: true}, + {Value: "target3", HasValue: true}, + }, }, }, }, @@ -885,14 +1029,18 @@ func verifyTarget3(t *testing.T, td *testData, mds []internaldata.MetricsData) { MetricDescriptor: &metricspb.MetricDescriptor{ Name: "rpc_duration_seconds", Type: metricspb.MetricDescriptor_SUMMARY, - LabelKeys: []*metricspb.LabelKey{{Key: "foo"}}, + LabelKeys: []*metricspb.LabelKey{{Key: "foo"}, {Key: "instance"}, {Key: "job"}}, Description: "A summary of the RPC duration in seconds.", Unit: "s", }, Timeseries: []*metricspb.TimeSeries{ { StartTimestamp: ts1, - LabelValues: []*metricspb.LabelValue{{Value: "bar", HasValue: true}}, + LabelValues: []*metricspb.LabelValue{ + {Value: "bar", HasValue: true}, + {Value: "-", HasValue: true}, + {Value: "target3", HasValue: true}, + }, Points: []*metricspb.Point{ { Timestamp: ts2, @@ -931,7 +1079,11 @@ func verifyTarget3(t *testing.T, td *testData, mds []internaldata.MetricsData) { }, { StartTimestamp: ts1, - LabelValues: []*metricspb.LabelValue{{Value: "no_quantile", HasValue: true}}, + LabelValues: []*metricspb.LabelValue{ + {Value: "no_quantile", HasValue: true}, + {Value: "-", HasValue: true}, + {Value: "target3", HasValue: true}, + }, Points: []*metricspb.Point{ { Timestamp: ts2, @@ -952,6 +1104,10 @@ func verifyTarget3(t *testing.T, td *testData, mds []internaldata.MetricsData) { }, } + m2.Metrics[0].Timeseries[0].LabelValues[0].Value = "-" + m2.Metrics[1].Timeseries[0].LabelValues[0].Value = "-" + m2.Metrics[2].Timeseries[0].LabelValues[1].Value = "-" + m2.Metrics[2].Timeseries[1].LabelValues[1].Value = "-" doCompare("scrape2", t, want2, &m2) } @@ -1182,3 +1338,28 @@ func testEndToEndRegex(t *testing.T, targets []*testData, useStartTimeMetric boo target.validateFunc(t, target, results[target.name]) } } + +func sortLabelsAndValues(m *metricspb.Metric) { + sort.Sort(&labelAndValueSorter{m: m}) +} + +type labelAndValueSorter struct { + m *metricspb.Metric +} + +func (s *labelAndValueSorter) Len() int { + return len(s.m.MetricDescriptor.LabelKeys) +} + +func (s *labelAndValueSorter) Less(i, j int) bool { + return s.m.MetricDescriptor.LabelKeys[i].Key < s.m.MetricDescriptor.LabelKeys[j].Key +} + +func (s *labelAndValueSorter) Swap(i, j int) { + keys := s.m.MetricDescriptor.LabelKeys + keys[i], keys[j] = keys[j], keys[i] + for _, t := range s.m.Timeseries { + values := t.LabelValues + values[i], values[j] = values[j], values[i] + } +}