Skip to content

Commit

Permalink
fix(parsers.prometheus): histogram infinity bucket must be allways pr…
Browse files Browse the repository at this point in the history
…esent (#11490) (#11486)
  • Loading branch information
mmolnar authored Jul 15, 2022
1 parent 6c7b3b3 commit 2ac311c
Show file tree
Hide file tree
Showing 2 changed files with 176 additions and 0 deletions.
15 changes: 15 additions & 0 deletions plugins/parsers/prometheus/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ func makeBuckets(m *dto.Metric, tags map[string]string, metricName string, metri
met := metric.New("prometheus", tags, fields, t, common.ValueType(metricType))
metrics = append(metrics, met)

infSeen := false
for _, b := range m.GetHistogram().Bucket {
newTags := tags
fields = make(map[string]interface{})
Expand All @@ -155,6 +156,20 @@ func makeBuckets(m *dto.Metric, tags map[string]string, metricName string, metri

histogramMetric := metric.New("prometheus", newTags, fields, t, common.ValueType(metricType))
metrics = append(metrics, histogramMetric)
if math.IsInf(b.GetUpperBound(), +1) {
infSeen = true
}
}
// Infinity bucket is required for proper function of histogram in prometheus
if !infSeen {
newTags := tags
newTags["le"] = "+Inf"

fields = make(map[string]interface{})
fields[metricName+"_bucket"] = float64(m.GetHistogram().GetSampleCount())

histogramInfMetric := metric.New("prometheus", newTags, fields, t, common.ValueType(metricType))
metrics = append(metrics, histogramInfMetric)
}
return metrics
}
Expand Down
161 changes: 161 additions & 0 deletions plugins/parsers/prometheus/parser_test.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package prometheus

import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/httptest"
"testing"
"time"

dto "github.com/prometheus/client_model/go"
"github.com/stretchr/testify/require"

"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/parsers/prometheus/common"
"github.com/influxdata/telegraf/testutil"
)

Expand Down Expand Up @@ -46,6 +49,32 @@ apiserver_request_latencies_bucket{resource="bindings",verb="POST",le="+Inf"} 20
apiserver_request_latencies_sum{resource="bindings",verb="POST"} 1.02726334e+08
apiserver_request_latencies_count{resource="bindings",verb="POST"} 2025
`
validUniqueHistogramJSON = `{
"name": "apiserver_request_latencies",
"help": "Response latency distribution in microseconds for each verb, resource and client.",
"type": "HISTOGRAM",
"metric": [
{
"label": [
{"name": "resource", "value": "bindings"},
{"name": "verb", "value": "POST"}
],
"histogram": {
"sample_count": 2025,
"sample_sum": 1.02726334e+08,
"bucket": [
{"cumulative_count": 1994,"upper_bound": 125000},
{"cumulative_count": 1997,"upper_bound": 250000},
{"cumulative_count": 2000,"upper_bound": 500000},
{"cumulative_count": 2005,"upper_bound": 1e+06},
{"cumulative_count": 2012,"upper_bound": 2e+06},
{"cumulative_count": 2017,"upper_bound": 4e+06},
{"cumulative_count": 2024,"upper_bound": 8e+06}
]
}
}
]
}`
)

func TestParsingValidGauge(t *testing.T) {
Expand Down Expand Up @@ -473,3 +502,135 @@ func TestParserProtobufHeader(t *testing.T) {
}
testutil.RequireMetricsEqual(t, expected, metrics, testutil.IgnoreTime(), testutil.SortMetrics())
}

func TestHistogramInfBucketPresence(t *testing.T) {
expected := []telegraf.Metric{
testutil.MustMetric(
"prometheus",
map[string]string{
"verb": "POST",
"resource": "bindings",
},
map[string]interface{}{
"apiserver_request_latencies_count": float64(2025.0),
"apiserver_request_latencies_sum": float64(1.02726334e+08),
},
time.Unix(0, 0),
telegraf.Histogram,
),
testutil.MustMetric(
"prometheus",
map[string]string{
"verb": "POST",
"resource": "bindings",
"le": "125000",
},
map[string]interface{}{
"apiserver_request_latencies_bucket": float64(1994.0),
},
time.Unix(0, 0),
telegraf.Histogram,
),
testutil.MustMetric(
"prometheus",
map[string]string{
"verb": "POST",
"resource": "bindings",
"le": "250000",
},
map[string]interface{}{
"apiserver_request_latencies_bucket": float64(1997.0),
},
time.Unix(0, 0),
telegraf.Histogram,
),
testutil.MustMetric(
"prometheus",
map[string]string{
"verb": "POST",
"resource": "bindings",
"le": "500000",
},
map[string]interface{}{
"apiserver_request_latencies_bucket": float64(2000.0),
},
time.Unix(0, 0),
telegraf.Histogram,
),
testutil.MustMetric(
"prometheus",
map[string]string{
"verb": "POST",
"resource": "bindings",
"le": "1e+06",
},
map[string]interface{}{
"apiserver_request_latencies_bucket": float64(2005.0),
},
time.Unix(0, 0),
telegraf.Histogram,
),
testutil.MustMetric(
"prometheus",
map[string]string{
"verb": "POST",
"resource": "bindings",
"le": "2e+06",
},
map[string]interface{}{
"apiserver_request_latencies_bucket": float64(2012.0),
},
time.Unix(0, 0),
telegraf.Histogram,
),
testutil.MustMetric(
"prometheus",
map[string]string{
"verb": "POST",
"resource": "bindings",
"le": "4e+06",
},
map[string]interface{}{
"apiserver_request_latencies_bucket": float64(2017.0),
},
time.Unix(0, 0),
telegraf.Histogram,
),
testutil.MustMetric(
"prometheus",
map[string]string{
"verb": "POST",
"resource": "bindings",
"le": "8e+06",
},
map[string]interface{}{
"apiserver_request_latencies_bucket": float64(2024.0),
},
time.Unix(0, 0),
telegraf.Histogram,
),
testutil.MustMetric(
"prometheus",
map[string]string{
"verb": "POST",
"resource": "bindings",
"le": "+Inf",
},
map[string]interface{}{
"apiserver_request_latencies_bucket": float64(2025.0),
},
time.Unix(0, 0),
telegraf.Histogram,
),
}

var metricFamily dto.MetricFamily
err := json.Unmarshal([]byte(validUniqueHistogramJSON), &metricFamily)
require.NoError(t, err)

m := metricFamily.Metric[0]
tags := common.MakeLabels(m, map[string]string{})
metrics := makeBuckets(m, tags, *metricFamily.Name, metricFamily.GetType(), time.Now())

testutil.RequireMetricsEqual(t, expected, metrics, testutil.IgnoreTime(), testutil.SortMetrics())
}

0 comments on commit 2ac311c

Please sign in to comment.