diff --git a/internal/otlptext/databuffer.go b/internal/otlptext/databuffer.go index 45dc2031c63..995257e6233 100644 --- a/internal/otlptext/databuffer.go +++ b/internal/otlptext/databuffer.go @@ -17,6 +17,7 @@ package otlptext // import "go.opentelemetry.io/collector/internal/otlptext" import ( "bytes" "fmt" + "math" "strconv" "strings" @@ -78,6 +79,10 @@ func (b *dataBuffer) logMetricDataPoints(m pdata.Metric) { data := m.Histogram() b.logEntry(" -> AggregationTemporality: %s", data.AggregationTemporality().String()) b.logDoubleHistogramDataPoints(data.DataPoints()) + case pdata.MetricDataTypeExponentialHistogram: + data := m.ExponentialHistogram() + b.logEntry(" -> AggregationTemporality: %s", data.AggregationTemporality().String()) + b.logExponentialHistogramDataPoints(data.DataPoints()) case pdata.MetricDataTypeSummary: data := m.Summary() b.logDoubleSummaryDataPoints(data.DataPoints()) @@ -128,6 +133,54 @@ func (b *dataBuffer) logDoubleHistogramDataPoints(ps pdata.HistogramDataPointSli } } +func (b *dataBuffer) logExponentialHistogramDataPoints(ps pdata.ExponentialHistogramDataPointSlice) { + for i := 0; i < ps.Len(); i++ { + p := ps.At(i) + b.logEntry("ExponentialHistogramDataPoints #%d", i) + b.logDataPointAttributes(p.Attributes()) + + b.logEntry("StartTimestamp: %s", p.StartTimestamp()) + b.logEntry("Timestamp: %s", p.Timestamp()) + b.logEntry("Count: %d", p.Count()) + b.logEntry("Sum: %f", p.Sum()) + + scale := int(p.Scale()) + factor := math.Ldexp(math.Ln2, -scale) + // Note: the equation used here, which is + // math.Exp(index * factor) + // reports +Inf as the _lower_ boundary of the bucket nearest + // infinity, which is incorrect and can be addressed in various + // ways. The OTel-Go implementation of this histogram pending + // in https://github.com/open-telemetry/opentelemetry-go/pull/2393 + // uses a lookup table for the last finite boundary, which can be + // easily computed using `math/big` (for scales up to 20). + + negB := p.Negative().BucketCounts() + posB := p.Positive().BucketCounts() + + for i := 0; i < len(negB); i++ { + pos := len(negB) - i - 1 + index := p.Negative().Offset() + int32(pos) + count := p.Negative().BucketCounts()[pos] + lower := math.Exp(float64(index) * factor) + upper := math.Exp(float64(index+1) * factor) + b.logEntry("Bucket (%f, %f], Count: %d", -upper, -lower, count) + } + + if p.ZeroCount() != 0 { + b.logEntry("Bucket [0, 0], Count: %d", p.ZeroCount()) + } + + for pos := 0; pos < len(posB); pos++ { + index := p.Positive().Offset() + int32(pos) + count := p.Positive().BucketCounts()[pos] + lower := math.Exp(float64(index) * factor) + upper := math.Exp(float64(index+1) * factor) + b.logEntry("Bucket [%f, %f), Count: %d", lower, upper, count) + } + } +} + func (b *dataBuffer) logDoubleSummaryDataPoints(ps pdata.SummaryDataPointSlice) { for i := 0; i < ps.Len(); i++ { p := ps.At(i) diff --git a/internal/testdata/metric.go b/internal/testdata/metric.go index a6e8bd5071b..52ffe71e9c6 100644 --- a/internal/testdata/metric.go +++ b/internal/testdata/metric.go @@ -258,17 +258,43 @@ func initExponentialHistogramMetric(hm pdata.Metric) { initMetricAttributes13(hdp0.Attributes()) hdp0.SetStartTimestamp(TestMetricStartTimestamp) hdp0.SetTimestamp(TestMetricTimestamp) - hdp0.SetCount(2) - hdp0.SetSum(15) + hdp0.SetCount(5) + hdp0.SetSum(0.15) hdp0.SetZeroCount(1) - hdp1 := hdps.AppendEmpty() + hdp0.SetScale(1) + + // positive index 1 and 2 are values sqrt(2), 2 at scale 1 + hdp0.Positive().SetOffset(1) + hdp0.Positive().SetBucketCounts([]uint64{1, 1}) + // negative index -1 and 0 are values -1/sqrt(2), -1 at scale 1 + hdp0.Negative().SetOffset(-1) + hdp0.Negative().SetBucketCounts([]uint64{1, 1}) + + // The above will print: + // Bucket (-1.414214, -1.000000], Count: 1 + // Bucket (-1.000000, -0.707107], Count: 1 + // Bucket [0, 0], Count: 1 + // Bucket [0.707107, 1.000000), Count: 1 + // Bucket [1.000000, 1.414214), Count: 1 + hdp1 := hdps.AppendEmpty() initMetricAttributes2(hdp1.Attributes()) hdp1.SetStartTimestamp(TestMetricStartTimestamp) hdp1.SetTimestamp(TestMetricTimestamp) - hdp1.SetCount(2) - hdp1.SetSum(15) + hdp1.SetCount(3) + hdp1.SetSum(1.25) hdp1.SetZeroCount(1) + hdp1.SetScale(-1) + + // index -1 and 0 are values 0.25, 1 at scale -1 + hdp1.Positive().SetOffset(-1) + hdp1.Positive().SetBucketCounts([]uint64{1, 1}) + + // The above will print: + // Bucket [0, 0], Count: 1 + // Bucket [0.250000, 1.000000), Count: 1 + // Bucket [1.000000, 4.000000), Count: 1 + exemplar := hdp1.Exemplars().AppendEmpty() exemplar.SetTimestamp(TestMetricExemplarTimestamp) exemplar.SetDoubleVal(15)