123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407 |
- // Copyright The OpenTelemetry Authors
- // SPDX-License-Identifier: Apache-2.0
- package prometheusreceiver
- import (
- "fmt"
- "math"
- "testing"
- "github.com/prometheus/prometheus/model/value"
- "github.com/stretchr/testify/assert"
- "go.opentelemetry.io/collector/pdata/pcommon"
- "go.opentelemetry.io/collector/pdata/pmetric"
- )
- var staleNaNsPage1 = `
- # HELP go_threads Number of OS threads created
- # TYPE go_threads gauge
- go_threads 19
- # HELP http_requests_total The total number of HTTP requests.
- # TYPE http_requests_total counter
- http_requests_total{method="post",code="200"} 100
- http_requests_total{method="post",code="400"} 5
- # HELP http_request_duration_seconds A histogram of the request duration.
- # TYPE http_request_duration_seconds histogram
- http_request_duration_seconds_bucket{le="0.05"} 1000
- http_request_duration_seconds_bucket{le="0.5"} 1500
- http_request_duration_seconds_bucket{le="1"} 2000
- http_request_duration_seconds_bucket{le="+Inf"} 2500
- http_request_duration_seconds_sum 5000
- http_request_duration_seconds_count 2500
- # HELP rpc_duration_seconds A summary of the RPC duration in seconds.
- # TYPE rpc_duration_seconds summary
- rpc_duration_seconds{quantile="0.01"} 1
- rpc_duration_seconds{quantile="0.9"} 5
- rpc_duration_seconds{quantile="0.99"} 8
- rpc_duration_seconds_sum 5000
- rpc_duration_seconds_count 1000
- `
- var (
- totalScrapes = 10
- )
- // TestStaleNaNs validates that staleness marker gets generated when the timeseries is no longer present
- func TestStaleNaNs(t *testing.T) {
- var mockResponses []mockPrometheusResponse
- for i := 0; i < totalScrapes; i++ {
- if i%2 == 0 {
- mockResponses = append(mockResponses, mockPrometheusResponse{
- code: 200,
- data: staleNaNsPage1,
- })
- } else {
- mockResponses = append(mockResponses, mockPrometheusResponse{
- code: 500,
- data: "",
- })
- }
- }
- targets := []*testData{
- {
- name: "target1",
- pages: mockResponses,
- validateFunc: verifyStaleNaNs,
- validateScrapes: true,
- },
- }
- testComponent(t, targets, nil)
- }
- func verifyStaleNaNs(t *testing.T, td *testData, resourceMetrics []pmetric.ResourceMetrics) {
- verifyNumTotalScrapeResults(t, td, resourceMetrics)
- metrics1 := resourceMetrics[0].ScopeMetrics().At(0).Metrics()
- ts := getTS(metrics1)
- for i := 0; i < totalScrapes; i++ {
- if i%2 == 0 {
- verifyStaleNaNsSuccessfulScrape(t, td, resourceMetrics[i], ts, i+1)
- } else {
- verifyStaleNaNsFailedScrape(t, td, resourceMetrics[i], ts, i+1)
- }
- }
- }
- func verifyStaleNaNsSuccessfulScrape(t *testing.T, td *testData, resourceMetric pmetric.ResourceMetrics, startTimestamp pcommon.Timestamp, iteration int) {
- // m1 has 4 metrics + 5 internal scraper metrics
- assert.Equal(t, 9, metricsCount(resourceMetric))
- wantAttributes := td.attributes // should want attribute be part of complete target or each scrape?
- metrics1 := resourceMetric.ScopeMetrics().At(0).Metrics()
- ts1 := getTS(metrics1)
- e1 := []testExpectation{
- assertMetricPresent("go_threads",
- compareMetricType(pmetric.MetricTypeGauge),
- compareMetricUnit(""),
- []dataPointExpectation{
- {
- numberPointComparator: []numberPointComparator{
- compareTimestamp(ts1),
- compareDoubleValue(19),
- },
- },
- }),
- assertMetricPresent("http_requests_total",
- compareMetricType(pmetric.MetricTypeSum),
- compareMetricUnit(""),
- []dataPointExpectation{
- {
- numberPointComparator: []numberPointComparator{
- compareStartTimestamp(startTimestamp),
- compareTimestamp(ts1),
- compareDoubleValue(100),
- compareAttributes(map[string]string{"method": "post", "code": "200"}),
- },
- },
- {
- numberPointComparator: []numberPointComparator{
- compareStartTimestamp(startTimestamp),
- compareTimestamp(ts1),
- compareDoubleValue(5),
- compareAttributes(map[string]string{"method": "post", "code": "400"}),
- },
- },
- }),
- assertMetricPresent("http_request_duration_seconds",
- compareMetricType(pmetric.MetricTypeHistogram),
- compareMetricUnit(""),
- []dataPointExpectation{
- {
- histogramPointComparator: []histogramPointComparator{
- compareHistogramStartTimestamp(startTimestamp),
- compareHistogramTimestamp(ts1),
- compareHistogram(2500, 5000, []float64{0.05, 0.5, 1}, []uint64{1000, 500, 500, 500}),
- },
- },
- }),
- assertMetricPresent("rpc_duration_seconds",
- compareMetricType(pmetric.MetricTypeSummary),
- compareMetricUnit(""),
- []dataPointExpectation{
- {
- summaryPointComparator: []summaryPointComparator{
- compareSummaryStartTimestamp(startTimestamp),
- compareSummaryTimestamp(ts1),
- compareSummary(1000, 5000, [][]float64{{0.01, 1}, {0.9, 5}, {0.99, 8}}),
- },
- },
- }),
- }
- doCompare(t, fmt.Sprintf("validScrape-scrape-%d", iteration), wantAttributes, resourceMetric, e1)
- }
- func verifyStaleNaNsFailedScrape(t *testing.T, td *testData, resourceMetric pmetric.ResourceMetrics, startTimestamp pcommon.Timestamp, iteration int) {
- // m1 has 4 metrics + 5 internal scraper metrics
- assert.Equal(t, 9, metricsCount(resourceMetric))
- wantAttributes := td.attributes
- allMetrics := getMetrics(resourceMetric)
- assertUp(t, 0, allMetrics)
- metrics1 := resourceMetric.ScopeMetrics().At(0).Metrics()
- ts1 := getTS(metrics1)
- e1 := []testExpectation{
- assertMetricPresent("go_threads",
- compareMetricType(pmetric.MetricTypeGauge),
- compareMetricUnit(""),
- []dataPointExpectation{
- {
- numberPointComparator: []numberPointComparator{
- compareTimestamp(ts1),
- assertNumberPointFlagNoRecordedValue(),
- },
- },
- }),
- assertMetricPresent("http_requests_total",
- compareMetricType(pmetric.MetricTypeSum),
- compareMetricUnit(""),
- []dataPointExpectation{
- {
- numberPointComparator: []numberPointComparator{
- compareStartTimestamp(startTimestamp),
- compareTimestamp(ts1),
- assertNumberPointFlagNoRecordedValue(),
- },
- },
- {
- numberPointComparator: []numberPointComparator{
- compareStartTimestamp(startTimestamp),
- compareTimestamp(ts1),
- assertNumberPointFlagNoRecordedValue(),
- },
- },
- }),
- assertMetricPresent("http_request_duration_seconds",
- compareMetricType(pmetric.MetricTypeHistogram),
- compareMetricUnit(""),
- []dataPointExpectation{
- {
- histogramPointComparator: []histogramPointComparator{
- compareHistogramStartTimestamp(startTimestamp),
- compareHistogramTimestamp(ts1),
- assertHistogramPointFlagNoRecordedValue(),
- },
- },
- }),
- assertMetricPresent("rpc_duration_seconds",
- compareMetricType(pmetric.MetricTypeSummary),
- compareMetricUnit(""),
- []dataPointExpectation{
- {
- summaryPointComparator: []summaryPointComparator{
- compareSummaryStartTimestamp(startTimestamp),
- compareSummaryTimestamp(ts1),
- assertSummaryPointFlagNoRecordedValue(),
- },
- },
- }),
- }
- doCompare(t, fmt.Sprintf("failedScrape-scrape-%d", iteration), wantAttributes, resourceMetric, e1)
- }
- // Prometheus gauge metric can be set to NaN, a use case could be when value 0 is not representable
- // Prometheus summary metric quantiles can have NaN after getting expired
- var normalNaNsPage1 = `
- # HELP go_threads Number of OS threads created
- # TYPE go_threads gauge
- go_threads NaN
- # HELP redis_connected_clients Redis connected clients
- redis_connected_clients{name="rough-snowflake-web",port="6380"} NaN
- # HELP rpc_duration_seconds A summary of the RPC duration in seconds.
- # TYPE rpc_duration_seconds summary
- rpc_duration_seconds{quantile="0.01"} NaN
- rpc_duration_seconds{quantile="0.9"} NaN
- rpc_duration_seconds{quantile="0.99"} NaN
- rpc_duration_seconds_sum 5000
- rpc_duration_seconds_count 1000
- `
- // TestNormalNaNs validates the output of receiver when testdata contains NaN values
- func TestNormalNaNs(t *testing.T) {
- // 1. setup input data
- targets := []*testData{
- {
- name: "target1",
- pages: []mockPrometheusResponse{
- {code: 200, data: normalNaNsPage1},
- },
- validateFunc: verifyNormalNaNs,
- },
- }
- testComponent(t, targets, nil)
- }
- func verifyNormalNaNs(t *testing.T, td *testData, resourceMetrics []pmetric.ResourceMetrics) {
- verifyNumValidScrapeResults(t, td, resourceMetrics)
- m1 := resourceMetrics[0]
- // m1 has 3 metrics + 5 internal scraper metrics
- assert.Equal(t, 8, metricsCount(m1))
- wantAttributes := td.attributes
- metrics1 := m1.ScopeMetrics().At(0).Metrics()
- ts1 := getTS(metrics1)
- e1 := []testExpectation{
- assertMetricPresent("go_threads",
- compareMetricType(pmetric.MetricTypeGauge),
- compareMetricUnit(""),
- []dataPointExpectation{
- {
- numberPointComparator: []numberPointComparator{
- compareTimestamp(ts1),
- assertNormalNan(),
- },
- },
- }),
- assertMetricPresent("redis_connected_clients",
- compareMetricType(pmetric.MetricTypeGauge),
- compareMetricUnit(""),
- []dataPointExpectation{
- {
- numberPointComparator: []numberPointComparator{
- compareTimestamp(ts1),
- compareAttributes(map[string]string{"name": "rough-snowflake-web", "port": "6380"}),
- assertNormalNan(),
- },
- },
- }),
- assertMetricPresent("rpc_duration_seconds",
- compareMetricType(pmetric.MetricTypeSummary),
- compareMetricUnit(""),
- []dataPointExpectation{
- {
- summaryPointComparator: []summaryPointComparator{
- compareSummaryStartTimestamp(ts1),
- compareSummaryTimestamp(ts1),
- compareSummary(1000, 5000, [][]float64{{0.01, math.Float64frombits(value.NormalNaN)},
- {0.9, math.Float64frombits(value.NormalNaN)}, {0.99, math.Float64frombits(value.NormalNaN)}}),
- },
- },
- }),
- }
- doCompare(t, "scrape-NormalNaN-1", wantAttributes, m1, e1)
- }
- var infPage1 = `
- # HELP go_threads Number of OS threads created
- # TYPE go_threads gauge
- go_threads +Inf
- # HELP redis_connected_clients Redis connected clients
- redis_connected_clients{name="rough-snowflake-web",port="6380"} -Inf
- # HELP http_requests_total The total number of HTTP requests.
- # TYPE http_requests_total counter
- http_requests_total{method="post",code="200"} +Inf
- # HELP rpc_duration_seconds A summary of the RPC duration in seconds.
- # TYPE rpc_duration_seconds summary
- rpc_duration_seconds{quantile="0.01"} +Inf
- rpc_duration_seconds{quantile="0.9"} +Inf
- rpc_duration_seconds{quantile="0.99"} +Inf
- rpc_duration_seconds_sum 5000
- rpc_duration_seconds_count 1000
- `
- func TestInfValues(t *testing.T) {
- // 1. setup input data
- targets := []*testData{
- {
- name: "target1",
- pages: []mockPrometheusResponse{
- {code: 200, data: infPage1},
- },
- validateFunc: verifyInfValues,
- },
- }
- testComponent(t, targets, nil)
- }
- func verifyInfValues(t *testing.T, td *testData, resourceMetrics []pmetric.ResourceMetrics) {
- verifyNumValidScrapeResults(t, td, resourceMetrics)
- m1 := resourceMetrics[0]
- // m1 has 4 metrics + 5 internal scraper metrics
- assert.Equal(t, 9, metricsCount(m1))
- wantAttributes := td.attributes
- metrics1 := m1.ScopeMetrics().At(0).Metrics()
- ts1 := getTS(metrics1)
- e1 := []testExpectation{
- assertMetricPresent("go_threads",
- compareMetricType(pmetric.MetricTypeGauge),
- compareMetricUnit(""),
- []dataPointExpectation{
- {
- numberPointComparator: []numberPointComparator{
- compareTimestamp(ts1),
- compareDoubleValue(math.Inf(1)),
- },
- },
- }),
- assertMetricPresent("redis_connected_clients",
- compareMetricType(pmetric.MetricTypeGauge),
- compareMetricUnit(""),
- []dataPointExpectation{
- {
- numberPointComparator: []numberPointComparator{
- compareTimestamp(ts1),
- compareAttributes(map[string]string{"name": "rough-snowflake-web", "port": "6380"}),
- compareDoubleValue(math.Inf(-1)),
- },
- },
- }),
- assertMetricPresent("http_requests_total",
- compareMetricType(pmetric.MetricTypeSum),
- compareMetricUnit(""),
- []dataPointExpectation{
- {
- numberPointComparator: []numberPointComparator{
- compareStartTimestamp(ts1),
- compareTimestamp(ts1),
- compareDoubleValue(math.Inf(1)),
- compareAttributes(map[string]string{"method": "post", "code": "200"}),
- },
- },
- }),
- assertMetricPresent("rpc_duration_seconds",
- compareMetricType(pmetric.MetricTypeSummary),
- compareMetricUnit(""),
- []dataPointExpectation{
- {
- summaryPointComparator: []summaryPointComparator{
- compareSummaryStartTimestamp(ts1),
- compareSummaryTimestamp(ts1),
- compareSummary(1000, 5000, [][]float64{{0.01, math.Inf(1)}, {0.9, math.Inf(1)}, {0.99, math.Inf(1)}}),
- },
- },
- }),
- }
- doCompare(t, "scrape-InfValues-1", wantAttributes, m1, e1)
- }
|