func()

in collector/otlp/metrics.go [302:381]


func (t *OltpMetricWriter) addOltpExpHistogramPoints(ctx context.Context, name string, points []*metricsv1.ExponentialHistogramDataPoint, wr *prompb.WriteRequest) error {
	for _, point := range points {
		timestamp := unixNanoToUnixMillis(point.TimeUnixNano)

		// Add count series
		series := newSeries(fmt.Sprintf("%s_count", name), point.Attributes)
		series.Samples = []*prompb.Sample{
			{
				Timestamp: timestamp,
				Value:     float64(point.Count),
			},
		}
		if err := t.addSeriesAndFlushIfNecessary(ctx, wr, series); err != nil {
			return err
		}

		// Add sum series, if present
		if point.Sum != nil {
			series := newSeries(fmt.Sprintf("%s_sum", name), point.Attributes)
			series.Samples = []*prompb.Sample{
				{
					Timestamp: timestamp,
					Value:     float64(*point.Sum),
				},
			}
			if err := t.addSeriesAndFlushIfNecessary(ctx, wr, series); err != nil {
				return err
			}
		}

		// See https://opentelemetry.io/blog/2023/exponential-histograms/
		base := math.Pow(2.0, math.Pow(2.0, float64(point.Scale)))
		if point.Negative != nil {
			buckets := point.Negative
			offset := buckets.Offset
			for i := int32(len(buckets.BucketCounts)) - 1; i >= 0; i-- {
				bucketIdx := i + offset

				// For negative buckets, the "upper bound" is the lower bound of the bucket
				// The lower bound is the higher number.
				upperBound := fmt.Sprintf("%f", math.Pow(-base, float64(bucketIdx)))

				series := newSeries(fmt.Sprintf("%s_bucket", name), point.Attributes)
				series.AppendLabelString("le", upperBound)
				series.AppendSample(timestamp, float64(buckets.BucketCounts[i]))
				if err := t.addSeriesAndFlushIfNecessary(ctx, wr, series); err != nil {
					return err
				}
			}
		}
		// TODO - understand better how to handle point.ZeroCount

		if point.Positive != nil {
			buckets := point.Positive
			offset := buckets.Offset
			for i := int32(0); i < int32(len(buckets.BucketCounts)); i++ {
				bucketIdx := i + offset

				// For positive buckets, the "upper bound" is the higher bound of the bucket
				upperBound := fmt.Sprintf("%f", math.Pow(base, float64(bucketIdx+1)))

				series := newSeries(fmt.Sprintf("%s_bucket", name), point.Attributes)
				series.Labels = append(series.Labels, &prompb.Label{
					Name:  []byte("le"),
					Value: []byte(upperBound),
				})
				series.Samples = []*prompb.Sample{
					{
						Timestamp: timestamp,
						Value:     float64(buckets.BucketCounts[i]),
					},
				}
				if err := t.addSeriesAndFlushIfNecessary(ctx, wr, series); err != nil {
					return err
				}
			}
		}
	}
	return nil
}