Skip to content

Commit

Permalink
otelcol.exporter.prometheus: Make histogram counts cumulative for Pro…
Browse files Browse the repository at this point in the history
…metheus (#4196)
  • Loading branch information
grcevski authored and clayton-cornell committed Aug 14, 2023
1 parent 590aeea commit 3ee0aeb
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ Main (unreleased)

- Fixes several issues with statsd exporter. (@jcreixell, @marctc)

- Fixes a bug in conversion of OpenTelemetry histograms when exported to Prometheus. (@grcevski)

### Other changes

- Mongodb integration has been disabled for the time being due to licensing issues. (@jcreixell)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ package convert
import (
"context"
"fmt"
"math"
"sort"
"strconv"
"sync"
"time"
Expand Down Expand Up @@ -458,11 +460,36 @@ func (conv *Converter) consumeHistogram(app storage.Appender, memResource *memor
}
}

// Sort the histogram by bounds ascending
bSize := int(math.Min(float64(dp.ExplicitBounds().Len()), float64(dp.BucketCounts().Len())))
buckets := make(map[float64]uint64, bSize)
bounds := make([]float64, 0, bSize)
for i := 0; i < dp.ExplicitBounds().Len() && i < dp.BucketCounts().Len(); i++ {
bound := dp.ExplicitBounds().At(i)
buckets[bound] = dp.BucketCounts().At(i)
bounds = append(bounds, bound)
}

sort.Float64s(bounds)

// Calculate cumulative count values. Prometheus expects cummulative bucket counts for histograms.
// This has nothing to do with temporality, it doesn't affect cummulative vs delta histograms, it
// simply matches the format of bucket counts expected by Prometheus.
var c uint64 = 0
for i := 0; i < len(bounds); i++ {
bound := bounds[i]
c += buckets[bound]
buckets[bound] = c
}

// Process the boundaries. The number of buckets = number of explicit
// bounds + 1.
for i := 0; i < dp.ExplicitBounds().Len() && i < dp.BucketCounts().Len(); i++ {
bound := dp.ExplicitBounds().At(i)
count := dp.BucketCounts().At(i)
count, ok := buckets[bound]
if !ok {
count = dp.BucketCounts().At(i)
}

bucketLabel := labels.Label{
Name: model.BucketLabel,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,41 @@ func TestConverter(t *testing.T) {
# TYPE test_metric_seconds histogram
test_metric_seconds_bucket{le="0.25"} 0
test_metric_seconds_bucket{le="0.5"} 111
test_metric_seconds_bucket{le="0.75"} 0
test_metric_seconds_bucket{le="1.0"} 222
test_metric_seconds_bucket{le="0.75"} 111
test_metric_seconds_bucket{le="1.0"} 333
test_metric_seconds_bucket{le="+Inf"} 333
test_metric_seconds_sum 100.0
test_metric_seconds_count 333
`,
},
{
name: "Histogram out-of-order bounds",
input: `{
"resource_metrics": [{
"scope_metrics": [{
"metrics": [{
"name": "test_metric_seconds",
"histogram": {
"aggregation_temporality": 2,
"data_points": [{
"start_time_unix_nano": 1000000000,
"time_unix_nano": 1000000000,
"count": 333,
"sum": 100,
"bucket_counts": [0, 111, 0, 222],
"explicit_bounds": [0.5, 1.0, 0.25, 0.75]
}]
}
}]
}]
}]
}`,
expect: `
# TYPE test_metric_seconds histogram
test_metric_seconds_bucket{le="0.25"} 0
test_metric_seconds_bucket{le="0.5"} 0
test_metric_seconds_bucket{le="0.75"} 222
test_metric_seconds_bucket{le="1.0"} 333
test_metric_seconds_bucket{le="+Inf"} 333
test_metric_seconds_sum 100.0
test_metric_seconds_count 333
Expand Down

0 comments on commit 3ee0aeb

Please sign in to comment.