mirror of https://github.com/prometheus/prometheus
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
773 lines
21 KiB
773 lines
21 KiB
// Copyright 2024 The Prometheus Authors |
|
// Licensed under the Apache License, Version 2.0 (the "License"); |
|
// you may not use this file except in compliance with the License. |
|
// You may obtain a copy of the License at |
|
// |
|
// http://www.apache.org/licenses/LICENSE-2.0 |
|
// |
|
// Unless required by applicable law or agreed to in writing, software |
|
// distributed under the License is distributed on an "AS IS" BASIS, |
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
// See the License for the specific language governing permissions and |
|
// limitations under the License. |
|
// Provenance-includes-location: https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/247a9f996e09a83cdc25addf70c05e42b8b30186/pkg/translator/prometheusremotewrite/histograms_test.go |
|
// Provenance-includes-license: Apache-2.0 |
|
// Provenance-includes-copyright: Copyright The OpenTelemetry Authors. |
|
|
|
package prometheusremotewrite |
|
|
|
import ( |
|
"context" |
|
"fmt" |
|
"testing" |
|
"time" |
|
|
|
"github.com/prometheus/common/model" |
|
"github.com/prometheus/prometheus/prompb" |
|
"github.com/stretchr/testify/assert" |
|
"github.com/stretchr/testify/require" |
|
"go.opentelemetry.io/collector/pdata/pcommon" |
|
"go.opentelemetry.io/collector/pdata/pmetric" |
|
|
|
prometheustranslator "github.com/prometheus/prometheus/storage/remote/otlptranslator/prometheus" |
|
) |
|
|
|
type expectedBucketLayout struct { |
|
wantSpans []prompb.BucketSpan |
|
wantDeltas []int64 |
|
} |
|
|
|
func TestConvertBucketsLayout(t *testing.T) { |
|
tests := []struct { |
|
name string |
|
buckets func() pmetric.ExponentialHistogramDataPointBuckets |
|
wantLayout map[int32]expectedBucketLayout |
|
}{ |
|
{ |
|
name: "zero offset", |
|
buckets: func() pmetric.ExponentialHistogramDataPointBuckets { |
|
b := pmetric.NewExponentialHistogramDataPointBuckets() |
|
b.SetOffset(0) |
|
b.BucketCounts().FromRaw([]uint64{4, 3, 2, 1}) |
|
return b |
|
}, |
|
wantLayout: map[int32]expectedBucketLayout{ |
|
0: { |
|
wantSpans: []prompb.BucketSpan{ |
|
{ |
|
Offset: 1, |
|
Length: 4, |
|
}, |
|
}, |
|
wantDeltas: []int64{4, -1, -1, -1}, |
|
}, |
|
1: { |
|
wantSpans: []prompb.BucketSpan{ |
|
{ |
|
Offset: 1, |
|
Length: 2, |
|
}, |
|
}, |
|
// 4+3, 2+1 = 7, 3 =delta= 7, -4 |
|
wantDeltas: []int64{7, -4}, |
|
}, |
|
2: { |
|
wantSpans: []prompb.BucketSpan{ |
|
{ |
|
Offset: 1, |
|
Length: 1, |
|
}, |
|
}, |
|
// 4+3+2+1 = 10 =delta= 10 |
|
wantDeltas: []int64{10}, |
|
}, |
|
}, |
|
}, |
|
{ |
|
name: "offset 1", |
|
buckets: func() pmetric.ExponentialHistogramDataPointBuckets { |
|
b := pmetric.NewExponentialHistogramDataPointBuckets() |
|
b.SetOffset(1) |
|
b.BucketCounts().FromRaw([]uint64{4, 3, 2, 1}) |
|
return b |
|
}, |
|
wantLayout: map[int32]expectedBucketLayout{ |
|
0: { |
|
wantSpans: []prompb.BucketSpan{ |
|
{ |
|
Offset: 2, |
|
Length: 4, |
|
}, |
|
}, |
|
wantDeltas: []int64{4, -1, -1, -1}, |
|
}, |
|
1: { |
|
wantSpans: []prompb.BucketSpan{ |
|
{ |
|
Offset: 1, |
|
Length: 3, |
|
}, |
|
}, |
|
wantDeltas: []int64{4, 1, -4}, // 0+4, 3+2, 1+0 = 4, 5, 1 |
|
}, |
|
2: { |
|
wantSpans: []prompb.BucketSpan{ |
|
{ |
|
Offset: 1, |
|
Length: 2, |
|
}, |
|
}, |
|
wantDeltas: []int64{9, -8}, // 0+4+3+2, 1+0+0+0 = 9, 1 |
|
}, |
|
}, |
|
}, |
|
{ |
|
name: "positive offset", |
|
buckets: func() pmetric.ExponentialHistogramDataPointBuckets { |
|
b := pmetric.NewExponentialHistogramDataPointBuckets() |
|
b.SetOffset(4) |
|
b.BucketCounts().FromRaw([]uint64{4, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}) |
|
return b |
|
}, |
|
wantLayout: map[int32]expectedBucketLayout{ |
|
0: { |
|
wantSpans: []prompb.BucketSpan{ |
|
{ |
|
Offset: 5, |
|
Length: 4, |
|
}, |
|
{ |
|
Offset: 12, |
|
Length: 1, |
|
}, |
|
}, |
|
wantDeltas: []int64{4, -2, -2, 2, -1}, |
|
}, |
|
1: { |
|
wantSpans: []prompb.BucketSpan{ |
|
{ |
|
Offset: 3, |
|
Length: 2, |
|
}, |
|
{ |
|
Offset: 6, |
|
Length: 1, |
|
}, |
|
}, |
|
// Downscale: |
|
// 4+2, 0+2, 0+0, 0+0, 0+0, 0+0, 0+0, 0+0, 1+0 = 6, 2, 0, 0, 0, 0, 0, 0, 1 |
|
wantDeltas: []int64{6, -4, -1}, |
|
}, |
|
2: { |
|
wantSpans: []prompb.BucketSpan{ |
|
{ |
|
Offset: 2, |
|
Length: 1, |
|
}, |
|
{ |
|
Offset: 3, |
|
Length: 1, |
|
}, |
|
}, |
|
// Downscale: |
|
// 4+2+0+2, 0+0+0+0, 0+0+0+0, 0+0+0+0, 1+0+0+0 = 8, 0, 0, 0, 1 |
|
// Check from scaling from previous: 6+2, 0+0, 0+0, 0+0, 1+0 = 8, 0, 0, 0, 1 |
|
wantDeltas: []int64{8, -7}, |
|
}, |
|
}, |
|
}, |
|
{ |
|
name: "scaledown merges spans", |
|
buckets: func() pmetric.ExponentialHistogramDataPointBuckets { |
|
b := pmetric.NewExponentialHistogramDataPointBuckets() |
|
b.SetOffset(4) |
|
b.BucketCounts().FromRaw([]uint64{4, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1}) |
|
return b |
|
}, |
|
wantLayout: map[int32]expectedBucketLayout{ |
|
0: { |
|
wantSpans: []prompb.BucketSpan{ |
|
{ |
|
Offset: 5, |
|
Length: 4, |
|
}, |
|
{ |
|
Offset: 8, |
|
Length: 1, |
|
}, |
|
}, |
|
wantDeltas: []int64{4, -2, -2, 2, -1}, |
|
}, |
|
1: { |
|
wantSpans: []prompb.BucketSpan{ |
|
{ |
|
Offset: 3, |
|
Length: 2, |
|
}, |
|
{ |
|
Offset: 4, |
|
Length: 1, |
|
}, |
|
}, |
|
// Downscale: |
|
// 4+2, 0+2, 0+0, 0+0, 0+0, 0+0, 1+0 = 6, 2, 0, 0, 0, 0, 1 |
|
wantDeltas: []int64{6, -4, -1}, |
|
}, |
|
2: { |
|
wantSpans: []prompb.BucketSpan{ |
|
{ |
|
Offset: 2, |
|
Length: 4, |
|
}, |
|
}, |
|
// Downscale: |
|
// 4+2+0+2, 0+0+0+0, 0+0+0+0, 1+0+0+0 = 8, 0, 0, 1 |
|
// Check from scaling from previous: 6+2, 0+0, 0+0, 1+0 = 8, 0, 0, 1 |
|
wantDeltas: []int64{8, -8, 0, 1}, |
|
}, |
|
}, |
|
}, |
|
{ |
|
name: "negative offset", |
|
buckets: func() pmetric.ExponentialHistogramDataPointBuckets { |
|
b := pmetric.NewExponentialHistogramDataPointBuckets() |
|
b.SetOffset(-2) |
|
b.BucketCounts().FromRaw([]uint64{3, 1, 0, 0, 0, 1}) |
|
return b |
|
}, |
|
wantLayout: map[int32]expectedBucketLayout{ |
|
0: { |
|
wantSpans: []prompb.BucketSpan{ |
|
{ |
|
Offset: -1, |
|
Length: 2, |
|
}, |
|
{ |
|
Offset: 3, |
|
Length: 1, |
|
}, |
|
}, |
|
wantDeltas: []int64{3, -2, 0}, |
|
}, |
|
1: { |
|
wantSpans: []prompb.BucketSpan{ |
|
{ |
|
Offset: 0, |
|
Length: 3, |
|
}, |
|
}, |
|
// Downscale: |
|
// 3+1, 0+0, 0+1 = 4, 0, 1 |
|
wantDeltas: []int64{4, -4, 1}, |
|
}, |
|
2: { |
|
wantSpans: []prompb.BucketSpan{ |
|
{ |
|
Offset: 0, |
|
Length: 2, |
|
}, |
|
}, |
|
// Downscale: |
|
// 0+0+3+1, 0+0+0+0 = 4, 1 |
|
wantDeltas: []int64{4, -3}, |
|
}, |
|
}, |
|
}, |
|
{ |
|
name: "buckets with gaps of size 1", |
|
buckets: func() pmetric.ExponentialHistogramDataPointBuckets { |
|
b := pmetric.NewExponentialHistogramDataPointBuckets() |
|
b.SetOffset(-2) |
|
b.BucketCounts().FromRaw([]uint64{3, 1, 0, 1, 0, 1}) |
|
return b |
|
}, |
|
wantLayout: map[int32]expectedBucketLayout{ |
|
0: { |
|
wantSpans: []prompb.BucketSpan{ |
|
{ |
|
Offset: -1, |
|
Length: 6, |
|
}, |
|
}, |
|
wantDeltas: []int64{3, -2, -1, 1, -1, 1}, |
|
}, |
|
1: { |
|
wantSpans: []prompb.BucketSpan{ |
|
{ |
|
Offset: 0, |
|
Length: 3, |
|
}, |
|
}, |
|
// Downscale: |
|
// 3+1, 0+1, 0+1 = 4, 1, 1 |
|
wantDeltas: []int64{4, -3, 0}, |
|
}, |
|
2: { |
|
wantSpans: []prompb.BucketSpan{ |
|
{ |
|
Offset: 0, |
|
Length: 2, |
|
}, |
|
}, |
|
// Downscale: |
|
// 0+0+3+1, 0+1+0+1 = 4, 2 |
|
wantDeltas: []int64{4, -2}, |
|
}, |
|
}, |
|
}, |
|
{ |
|
name: "buckets with gaps of size 2", |
|
buckets: func() pmetric.ExponentialHistogramDataPointBuckets { |
|
b := pmetric.NewExponentialHistogramDataPointBuckets() |
|
b.SetOffset(-2) |
|
b.BucketCounts().FromRaw([]uint64{3, 0, 0, 1, 0, 0, 1}) |
|
return b |
|
}, |
|
wantLayout: map[int32]expectedBucketLayout{ |
|
0: { |
|
wantSpans: []prompb.BucketSpan{ |
|
{ |
|
Offset: -1, |
|
Length: 7, |
|
}, |
|
}, |
|
wantDeltas: []int64{3, -3, 0, 1, -1, 0, 1}, |
|
}, |
|
1: { |
|
wantSpans: []prompb.BucketSpan{ |
|
{ |
|
Offset: 0, |
|
Length: 4, |
|
}, |
|
}, |
|
// Downscale: |
|
// 3+0, 0+1, 0+0, 0+1 = 3, 1, 0, 1 |
|
wantDeltas: []int64{3, -2, -1, 1}, |
|
}, |
|
2: { |
|
wantSpans: []prompb.BucketSpan{ |
|
{ |
|
Offset: 0, |
|
Length: 3, |
|
}, |
|
}, |
|
// Downscale: |
|
// 0+0+3+0, 0+1+0+0, 1+0+0+0 = 3, 1, 1 |
|
wantDeltas: []int64{3, -2, 0}, |
|
}, |
|
}, |
|
}, |
|
{ |
|
name: "zero buckets", |
|
buckets: pmetric.NewExponentialHistogramDataPointBuckets, |
|
wantLayout: map[int32]expectedBucketLayout{ |
|
0: { |
|
wantSpans: nil, |
|
wantDeltas: nil, |
|
}, |
|
1: { |
|
wantSpans: nil, |
|
wantDeltas: nil, |
|
}, |
|
2: { |
|
wantSpans: nil, |
|
wantDeltas: nil, |
|
}, |
|
}, |
|
}, |
|
} |
|
for _, tt := range tests { |
|
for scaleDown, wantLayout := range tt.wantLayout { |
|
t.Run(fmt.Sprintf("%s-scaleby-%d", tt.name, scaleDown), func(t *testing.T) { |
|
gotSpans, gotDeltas := convertBucketsLayout(tt.buckets(), scaleDown) |
|
assert.Equal(t, wantLayout.wantSpans, gotSpans) |
|
assert.Equal(t, wantLayout.wantDeltas, gotDeltas) |
|
}) |
|
} |
|
} |
|
} |
|
|
|
func BenchmarkConvertBucketLayout(b *testing.B) { |
|
scenarios := []struct { |
|
gap int |
|
}{ |
|
{gap: 0}, |
|
{gap: 1}, |
|
{gap: 2}, |
|
{gap: 3}, |
|
} |
|
|
|
for _, scenario := range scenarios { |
|
buckets := pmetric.NewExponentialHistogramDataPointBuckets() |
|
buckets.SetOffset(0) |
|
for i := 0; i < 1000; i++ { |
|
if i%(scenario.gap+1) == 0 { |
|
buckets.BucketCounts().Append(10) |
|
} else { |
|
buckets.BucketCounts().Append(0) |
|
} |
|
} |
|
b.Run(fmt.Sprintf("gap %d", scenario.gap), func(b *testing.B) { |
|
for i := 0; i < b.N; i++ { |
|
convertBucketsLayout(buckets, 0) |
|
} |
|
}) |
|
} |
|
} |
|
|
|
func TestExponentialToNativeHistogram(t *testing.T) { |
|
tests := []struct { |
|
name string |
|
exponentialHist func() pmetric.ExponentialHistogramDataPoint |
|
wantNativeHist func() prompb.Histogram |
|
wantErrMessage string |
|
}{ |
|
{ |
|
name: "convert exp. to native histogram", |
|
exponentialHist: func() pmetric.ExponentialHistogramDataPoint { |
|
pt := pmetric.NewExponentialHistogramDataPoint() |
|
pt.SetStartTimestamp(pcommon.NewTimestampFromTime(time.UnixMilli(100))) |
|
pt.SetTimestamp(pcommon.NewTimestampFromTime(time.UnixMilli(500))) |
|
pt.SetCount(4) |
|
pt.SetSum(10.1) |
|
pt.SetScale(1) |
|
pt.SetZeroCount(1) |
|
|
|
pt.Positive().BucketCounts().FromRaw([]uint64{1, 1}) |
|
pt.Positive().SetOffset(1) |
|
|
|
pt.Negative().BucketCounts().FromRaw([]uint64{1, 1}) |
|
pt.Negative().SetOffset(1) |
|
|
|
return pt |
|
}, |
|
wantNativeHist: func() prompb.Histogram { |
|
return prompb.Histogram{ |
|
Count: &prompb.Histogram_CountInt{CountInt: 4}, |
|
Sum: 10.1, |
|
Schema: 1, |
|
ZeroThreshold: defaultZeroThreshold, |
|
ZeroCount: &prompb.Histogram_ZeroCountInt{ZeroCountInt: 1}, |
|
NegativeSpans: []prompb.BucketSpan{{Offset: 2, Length: 2}}, |
|
NegativeDeltas: []int64{1, 0}, |
|
PositiveSpans: []prompb.BucketSpan{{Offset: 2, Length: 2}}, |
|
PositiveDeltas: []int64{1, 0}, |
|
Timestamp: 500, |
|
} |
|
}, |
|
}, |
|
{ |
|
name: "convert exp. to native histogram with no sum", |
|
exponentialHist: func() pmetric.ExponentialHistogramDataPoint { |
|
pt := pmetric.NewExponentialHistogramDataPoint() |
|
pt.SetStartTimestamp(pcommon.NewTimestampFromTime(time.UnixMilli(100))) |
|
pt.SetTimestamp(pcommon.NewTimestampFromTime(time.UnixMilli(500))) |
|
|
|
pt.SetCount(4) |
|
pt.SetScale(1) |
|
pt.SetZeroCount(1) |
|
|
|
pt.Positive().BucketCounts().FromRaw([]uint64{1, 1}) |
|
pt.Positive().SetOffset(1) |
|
|
|
pt.Negative().BucketCounts().FromRaw([]uint64{1, 1}) |
|
pt.Negative().SetOffset(1) |
|
|
|
return pt |
|
}, |
|
wantNativeHist: func() prompb.Histogram { |
|
return prompb.Histogram{ |
|
Count: &prompb.Histogram_CountInt{CountInt: 4}, |
|
Schema: 1, |
|
ZeroThreshold: defaultZeroThreshold, |
|
ZeroCount: &prompb.Histogram_ZeroCountInt{ZeroCountInt: 1}, |
|
NegativeSpans: []prompb.BucketSpan{{Offset: 2, Length: 2}}, |
|
NegativeDeltas: []int64{1, 0}, |
|
PositiveSpans: []prompb.BucketSpan{{Offset: 2, Length: 2}}, |
|
PositiveDeltas: []int64{1, 0}, |
|
Timestamp: 500, |
|
} |
|
}, |
|
}, |
|
{ |
|
name: "invalid negative scale", |
|
exponentialHist: func() pmetric.ExponentialHistogramDataPoint { |
|
pt := pmetric.NewExponentialHistogramDataPoint() |
|
pt.SetScale(-10) |
|
return pt |
|
}, |
|
wantErrMessage: "cannot convert exponential to native histogram." + |
|
" Scale must be >= -4, was -10", |
|
}, |
|
{ |
|
name: "no downscaling at scale 8", |
|
exponentialHist: func() pmetric.ExponentialHistogramDataPoint { |
|
pt := pmetric.NewExponentialHistogramDataPoint() |
|
pt.SetTimestamp(pcommon.NewTimestampFromTime(time.UnixMilli(500))) |
|
pt.SetCount(6) |
|
pt.SetSum(10.1) |
|
pt.SetScale(8) |
|
pt.SetZeroCount(1) |
|
|
|
pt.Positive().BucketCounts().FromRaw([]uint64{1, 1, 1}) |
|
pt.Positive().SetOffset(1) |
|
|
|
pt.Negative().BucketCounts().FromRaw([]uint64{1, 1, 1}) |
|
pt.Negative().SetOffset(2) |
|
return pt |
|
}, |
|
wantNativeHist: func() prompb.Histogram { |
|
return prompb.Histogram{ |
|
Count: &prompb.Histogram_CountInt{CountInt: 6}, |
|
Sum: 10.1, |
|
Schema: 8, |
|
ZeroThreshold: defaultZeroThreshold, |
|
ZeroCount: &prompb.Histogram_ZeroCountInt{ZeroCountInt: 1}, |
|
PositiveSpans: []prompb.BucketSpan{{Offset: 2, Length: 3}}, |
|
PositiveDeltas: []int64{1, 0, 0}, // 1, 1, 1 |
|
NegativeSpans: []prompb.BucketSpan{{Offset: 3, Length: 3}}, |
|
NegativeDeltas: []int64{1, 0, 0}, // 1, 1, 1 |
|
Timestamp: 500, |
|
} |
|
}, |
|
}, |
|
{ |
|
name: "downsample if scale is more than 8", |
|
exponentialHist: func() pmetric.ExponentialHistogramDataPoint { |
|
pt := pmetric.NewExponentialHistogramDataPoint() |
|
pt.SetTimestamp(pcommon.NewTimestampFromTime(time.UnixMilli(500))) |
|
pt.SetCount(6) |
|
pt.SetSum(10.1) |
|
pt.SetScale(9) |
|
pt.SetZeroCount(1) |
|
|
|
pt.Positive().BucketCounts().FromRaw([]uint64{1, 1, 1}) |
|
pt.Positive().SetOffset(1) |
|
|
|
pt.Negative().BucketCounts().FromRaw([]uint64{1, 1, 1}) |
|
pt.Negative().SetOffset(2) |
|
return pt |
|
}, |
|
wantNativeHist: func() prompb.Histogram { |
|
return prompb.Histogram{ |
|
Count: &prompb.Histogram_CountInt{CountInt: 6}, |
|
Sum: 10.1, |
|
Schema: 8, |
|
ZeroThreshold: defaultZeroThreshold, |
|
ZeroCount: &prompb.Histogram_ZeroCountInt{ZeroCountInt: 1}, |
|
PositiveSpans: []prompb.BucketSpan{{Offset: 1, Length: 2}}, |
|
PositiveDeltas: []int64{1, 1}, // 0+1, 1+1 = 1, 2 |
|
NegativeSpans: []prompb.BucketSpan{{Offset: 2, Length: 2}}, |
|
NegativeDeltas: []int64{2, -1}, // 1+1, 1+0 = 2, 1 |
|
Timestamp: 500, |
|
} |
|
}, |
|
}, |
|
} |
|
for _, tt := range tests { |
|
t.Run(tt.name, func(t *testing.T) { |
|
validateExponentialHistogramCount(t, tt.exponentialHist()) // Sanity check. |
|
got, annots, err := exponentialToNativeHistogram(tt.exponentialHist()) |
|
if tt.wantErrMessage != "" { |
|
assert.ErrorContains(t, err, tt.wantErrMessage) |
|
return |
|
} |
|
|
|
require.NoError(t, err) |
|
require.Empty(t, annots) |
|
assert.Equal(t, tt.wantNativeHist(), got) |
|
validateNativeHistogramCount(t, got) |
|
}) |
|
} |
|
} |
|
|
|
func validateExponentialHistogramCount(t *testing.T, h pmetric.ExponentialHistogramDataPoint) { |
|
actualCount := uint64(0) |
|
for _, bucket := range h.Positive().BucketCounts().AsRaw() { |
|
actualCount += bucket |
|
} |
|
for _, bucket := range h.Negative().BucketCounts().AsRaw() { |
|
actualCount += bucket |
|
} |
|
require.Equal(t, h.Count(), actualCount, "exponential histogram count mismatch") |
|
} |
|
|
|
func validateNativeHistogramCount(t *testing.T, h prompb.Histogram) { |
|
require.NotNil(t, h.Count) |
|
require.IsType(t, &prompb.Histogram_CountInt{}, h.Count) |
|
want := h.Count.(*prompb.Histogram_CountInt).CountInt |
|
var ( |
|
actualCount uint64 |
|
prevBucket int64 |
|
) |
|
for _, delta := range h.PositiveDeltas { |
|
prevBucket += delta |
|
actualCount += uint64(prevBucket) |
|
} |
|
prevBucket = 0 |
|
for _, delta := range h.NegativeDeltas { |
|
prevBucket += delta |
|
actualCount += uint64(prevBucket) |
|
} |
|
assert.Equal(t, want, actualCount, "native histogram count mismatch") |
|
} |
|
|
|
func TestPrometheusConverter_addExponentialHistogramDataPoints(t *testing.T) { |
|
tests := []struct { |
|
name string |
|
metric func() pmetric.Metric |
|
wantSeries func() map[uint64]*prompb.TimeSeries |
|
}{ |
|
{ |
|
name: "histogram data points with same labels", |
|
metric: func() pmetric.Metric { |
|
metric := pmetric.NewMetric() |
|
metric.SetName("test_hist") |
|
metric.SetEmptyExponentialHistogram().SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) |
|
|
|
pt := metric.ExponentialHistogram().DataPoints().AppendEmpty() |
|
pt.SetCount(7) |
|
pt.SetScale(1) |
|
pt.Positive().SetOffset(-1) |
|
pt.Positive().BucketCounts().FromRaw([]uint64{4, 2}) |
|
pt.Exemplars().AppendEmpty().SetDoubleValue(1) |
|
pt.Attributes().PutStr("attr", "test_attr") |
|
|
|
pt = metric.ExponentialHistogram().DataPoints().AppendEmpty() |
|
pt.SetCount(4) |
|
pt.SetScale(1) |
|
pt.Positive().SetOffset(-1) |
|
pt.Positive().BucketCounts().FromRaw([]uint64{4, 2, 1}) |
|
pt.Exemplars().AppendEmpty().SetDoubleValue(2) |
|
pt.Attributes().PutStr("attr", "test_attr") |
|
|
|
return metric |
|
}, |
|
wantSeries: func() map[uint64]*prompb.TimeSeries { |
|
labels := []prompb.Label{ |
|
{Name: model.MetricNameLabel, Value: "test_hist"}, |
|
{Name: "attr", Value: "test_attr"}, |
|
} |
|
return map[uint64]*prompb.TimeSeries{ |
|
timeSeriesSignature(labels): { |
|
Labels: labels, |
|
Histograms: []prompb.Histogram{ |
|
{ |
|
Count: &prompb.Histogram_CountInt{CountInt: 7}, |
|
Schema: 1, |
|
ZeroThreshold: defaultZeroThreshold, |
|
ZeroCount: &prompb.Histogram_ZeroCountInt{ZeroCountInt: 0}, |
|
PositiveSpans: []prompb.BucketSpan{{Offset: 0, Length: 2}}, |
|
PositiveDeltas: []int64{4, -2}, |
|
}, |
|
{ |
|
Count: &prompb.Histogram_CountInt{CountInt: 4}, |
|
Schema: 1, |
|
ZeroThreshold: defaultZeroThreshold, |
|
ZeroCount: &prompb.Histogram_ZeroCountInt{ZeroCountInt: 0}, |
|
PositiveSpans: []prompb.BucketSpan{{Offset: 0, Length: 3}}, |
|
PositiveDeltas: []int64{4, -2, -1}, |
|
}, |
|
}, |
|
Exemplars: []prompb.Exemplar{ |
|
{Value: 1}, |
|
{Value: 2}, |
|
}, |
|
}, |
|
} |
|
}, |
|
}, |
|
{ |
|
name: "histogram data points with different labels", |
|
metric: func() pmetric.Metric { |
|
metric := pmetric.NewMetric() |
|
metric.SetName("test_hist") |
|
metric.SetEmptyExponentialHistogram().SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) |
|
|
|
pt := metric.ExponentialHistogram().DataPoints().AppendEmpty() |
|
pt.SetCount(7) |
|
pt.SetScale(1) |
|
pt.Positive().SetOffset(-1) |
|
pt.Positive().BucketCounts().FromRaw([]uint64{4, 2}) |
|
pt.Exemplars().AppendEmpty().SetDoubleValue(1) |
|
pt.Attributes().PutStr("attr", "test_attr") |
|
|
|
pt = metric.ExponentialHistogram().DataPoints().AppendEmpty() |
|
pt.SetCount(4) |
|
pt.SetScale(1) |
|
pt.Negative().SetOffset(-1) |
|
pt.Negative().BucketCounts().FromRaw([]uint64{4, 2, 1}) |
|
pt.Exemplars().AppendEmpty().SetDoubleValue(2) |
|
pt.Attributes().PutStr("attr", "test_attr_two") |
|
|
|
return metric |
|
}, |
|
wantSeries: func() map[uint64]*prompb.TimeSeries { |
|
labels := []prompb.Label{ |
|
{Name: model.MetricNameLabel, Value: "test_hist"}, |
|
{Name: "attr", Value: "test_attr"}, |
|
} |
|
labelsAnother := []prompb.Label{ |
|
{Name: model.MetricNameLabel, Value: "test_hist"}, |
|
{Name: "attr", Value: "test_attr_two"}, |
|
} |
|
|
|
return map[uint64]*prompb.TimeSeries{ |
|
timeSeriesSignature(labels): { |
|
Labels: labels, |
|
Histograms: []prompb.Histogram{ |
|
{ |
|
Count: &prompb.Histogram_CountInt{CountInt: 7}, |
|
Schema: 1, |
|
ZeroThreshold: defaultZeroThreshold, |
|
ZeroCount: &prompb.Histogram_ZeroCountInt{ZeroCountInt: 0}, |
|
PositiveSpans: []prompb.BucketSpan{{Offset: 0, Length: 2}}, |
|
PositiveDeltas: []int64{4, -2}, |
|
}, |
|
}, |
|
Exemplars: []prompb.Exemplar{ |
|
{Value: 1}, |
|
}, |
|
}, |
|
timeSeriesSignature(labelsAnother): { |
|
Labels: labelsAnother, |
|
Histograms: []prompb.Histogram{ |
|
{ |
|
Count: &prompb.Histogram_CountInt{CountInt: 4}, |
|
Schema: 1, |
|
ZeroThreshold: defaultZeroThreshold, |
|
ZeroCount: &prompb.Histogram_ZeroCountInt{ZeroCountInt: 0}, |
|
NegativeSpans: []prompb.BucketSpan{{Offset: 0, Length: 3}}, |
|
NegativeDeltas: []int64{4, -2, -1}, |
|
}, |
|
}, |
|
Exemplars: []prompb.Exemplar{ |
|
{Value: 2}, |
|
}, |
|
}, |
|
} |
|
}, |
|
}, |
|
} |
|
for _, tt := range tests { |
|
t.Run(tt.name, func(t *testing.T) { |
|
metric := tt.metric() |
|
|
|
converter := NewPrometheusConverter() |
|
annots, err := converter.addExponentialHistogramDataPoints( |
|
context.Background(), |
|
metric.ExponentialHistogram().DataPoints(), |
|
pcommon.NewResource(), |
|
Settings{ |
|
ExportCreatedMetric: true, |
|
}, |
|
prometheustranslator.BuildCompliantName(metric, "", true), |
|
) |
|
require.NoError(t, err) |
|
require.Empty(t, annots) |
|
|
|
assert.Equal(t, tt.wantSeries(), converter.unique) |
|
assert.Empty(t, converter.conflicts) |
|
}) |
|
} |
|
}
|
|
|