-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[prometheusremotewriteexporter] Support conversion of OTel Exponentia…
…l Histogram to Prometheus Native Histogram (#17370) Support conversion of OTel Exponential Histogram to Prometheus Native Histogram. pmetric.ExponentialHistogramDataPoint translates to prompb.Histogram as follows: - Exp. Scale -> Nat. Schema: histogram is dropped if Scale -4 < and > 8. - TODO: We can potentially downscale hist to 8 if Scale > 8? (as a separate PR) - Exp. Count -> Nat. Count: if Flags().NoRecordedValue() is false - Exp. Sum_ -> Nat. Sum: if it Sum is set and Flags().NoRecordedValue() is false - Exp. TimeUnixNano -> Nat. Timestamp: TimeUnixNano ns converted Timestamp ms - Exp. ZeroCount -> Nat. ZeroCount - Nat. ZeroThreshold is set to the default value 1e-128, once opentelemetry-proto#441 is merged, we can use Exp. ZeroThreshold to set the value. - Exp. Positive -> Nat. PositiveSpans and Nat. PositiveDeltas. - Exp. Negative -> Nat. NegativeSpans and Nat. NegativeDeltas. - Exp. Min_ and Max_ are not used. - Exp. StartTimeUnixNano is not used. Exp. Exemplars, Labels, and ExponentialHistogramDataPoint will be translated to native hist data structures and will make up one or more prompb.TimeSeries. Link to tracking Issue: Resolves #16207 Testing: Unit tests in pkg/transalator/prometheusremote and exporter/prometheusremotewriteexporter
- Loading branch information
Showing
8 changed files
with
701 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' | ||
change_type: enhancement | ||
|
||
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) | ||
component: prometheusremotewriteexporter | ||
|
||
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). | ||
note: Add support for converting OTLP Exponential Histograms to Prometheus Native Histograms | ||
|
||
# One or more tracking issues related to the change | ||
issues: [16207] | ||
|
||
# (Optional) One or more lines of additional information to render under the primary note. | ||
# These lines will be padded with 2 spaces and then inserted directly into the document. | ||
# Use pipe (|) for multiline entries. | ||
subtext: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
// Copyright The OpenTelemetry 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. | ||
|
||
package prometheusremotewrite // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheusremotewrite" | ||
|
||
import ( | ||
"fmt" | ||
"math" | ||
|
||
"github.com/prometheus/common/model" | ||
"github.com/prometheus/prometheus/model/value" | ||
"github.com/prometheus/prometheus/prompb" | ||
"go.opentelemetry.io/collector/pdata/pcommon" | ||
"go.opentelemetry.io/collector/pdata/pmetric" | ||
) | ||
|
||
const defaultZeroThreshold = 1e-128 | ||
|
||
func addSingleExponentialHistogramDataPoint( | ||
metric string, | ||
pt pmetric.ExponentialHistogramDataPoint, | ||
resource pcommon.Resource, | ||
settings Settings, | ||
series map[string]*prompb.TimeSeries, | ||
) error { | ||
labels := createAttributes( | ||
resource, | ||
pt.Attributes(), | ||
settings.ExternalLabels, | ||
model.MetricNameLabel, metric, | ||
) | ||
|
||
sig := timeSeriesSignature( | ||
pmetric.MetricTypeExponentialHistogram.String(), | ||
&labels, | ||
) | ||
ts, ok := series[sig] | ||
if !ok { | ||
ts = &prompb.TimeSeries{ | ||
Labels: labels, | ||
} | ||
series[sig] = ts | ||
} | ||
|
||
histogram, err := exponentialToNativeHistogram(pt) | ||
if err != nil { | ||
return err | ||
} | ||
ts.Histograms = append(ts.Histograms, histogram) | ||
|
||
exemplars := getPromExemplars[pmetric.ExponentialHistogramDataPoint](pt) | ||
ts.Exemplars = append(ts.Exemplars, exemplars...) | ||
|
||
return nil | ||
} | ||
|
||
// exponentialToNativeHistogram translates OTel Exponential Histogram data point | ||
// to Prometheus Native Histogram. | ||
func exponentialToNativeHistogram(p pmetric.ExponentialHistogramDataPoint) (prompb.Histogram, error) { | ||
scale := p.Scale() | ||
if scale < -4 || scale > 8 { | ||
return prompb.Histogram{}, | ||
fmt.Errorf("cannot convert exponential to native histogram."+ | ||
" Scale must be <= 8 and >= -4, was %d", scale) | ||
// TODO: downscale to 8 if scale > 8 | ||
} | ||
|
||
pSpans, pDeltas := convertBucketsLayout(p.Positive()) | ||
nSpans, nDeltas := convertBucketsLayout(p.Negative()) | ||
|
||
h := prompb.Histogram{ | ||
Schema: scale, | ||
|
||
ZeroCount: &prompb.Histogram_ZeroCountInt{ZeroCountInt: p.ZeroCount()}, | ||
// TODO use zero_threshold, if set, see | ||
// https://github.com/open-telemetry/opentelemetry-proto/pull/441 | ||
ZeroThreshold: defaultZeroThreshold, | ||
|
||
PositiveSpans: pSpans, | ||
PositiveDeltas: pDeltas, | ||
NegativeSpans: nSpans, | ||
NegativeDeltas: nDeltas, | ||
|
||
Timestamp: convertTimeStamp(p.Timestamp()), | ||
} | ||
|
||
if p.Flags().NoRecordedValue() { | ||
h.Sum = math.Float64frombits(value.StaleNaN) | ||
h.Count = &prompb.Histogram_CountInt{CountInt: value.StaleNaN} | ||
} else { | ||
if p.HasSum() { | ||
h.Sum = p.Sum() | ||
} | ||
h.Count = &prompb.Histogram_CountInt{CountInt: p.Count()} | ||
} | ||
return h, nil | ||
} | ||
|
||
// convertBucketsLayout translates OTel Exponential Histogram dense buckets | ||
// representation to Prometheus Native Histogram sparse bucket representation. | ||
// | ||
// The translation logic is taken from the client_golang `histogram.go#makeBuckets` | ||
// function, see `makeBuckets` https://github.com/prometheus/client_golang/blob/main/prometheus/histogram.go | ||
// The bucket indexes conversion was adjusted, since OTel exp. histogram bucket | ||
// index 0 corresponds to the range (1, base] while Prometheus bucket index 0 | ||
// to the range (base 1]. | ||
func convertBucketsLayout(buckets pmetric.ExponentialHistogramDataPointBuckets) ([]*prompb.BucketSpan, []int64) { | ||
bucketCounts := buckets.BucketCounts() | ||
if bucketCounts.Len() == 0 { | ||
return nil, nil | ||
} | ||
|
||
var ( | ||
spans []*prompb.BucketSpan | ||
deltas []int64 | ||
prevCount int64 | ||
nextBucketIdx int32 | ||
) | ||
|
||
appendDelta := func(count int64) { | ||
spans[len(spans)-1].Length++ | ||
deltas = append(deltas, count-prevCount) | ||
prevCount = count | ||
} | ||
|
||
for i := 0; i < bucketCounts.Len(); i++ { | ||
count := int64(bucketCounts.At(i)) | ||
if count == 0 { | ||
continue | ||
} | ||
|
||
// The offset is adjusted by 1 as described above. | ||
bucketIdx := int32(i) + buckets.Offset() + 1 | ||
delta := bucketIdx - nextBucketIdx | ||
if i == 0 || delta > 2 { | ||
// We have to create a new span, either because we are | ||
// at the very beginning, or because we have found a gap | ||
// of more than two buckets. The constant 2 is copied from the logic in | ||
// https://github.com/prometheus/client_golang/blob/27f0506d6ebbb117b6b697d0552ee5be2502c5f2/prometheus/histogram.go#L1296 | ||
spans = append(spans, &prompb.BucketSpan{ | ||
Offset: delta, | ||
Length: 0, | ||
}) | ||
} else { | ||
// We have found a small gap (or no gap at all). | ||
// Insert empty buckets as needed. | ||
for j := int32(0); j < delta; j++ { | ||
appendDelta(0) | ||
} | ||
} | ||
appendDelta(count) | ||
nextBucketIdx = bucketIdx + 1 | ||
} | ||
|
||
return spans, deltas | ||
} |
Oops, something went wrong.