func translateDistributionValue()

in components/google-built-opentelemetry-collector/exporter/googleservicecontrolexporter/exporter.go [458:516]


func translateDistributionValue(value pmetric.HistogramDataPoint) *scpb.Distribution {
	result := &scpb.Distribution{
		Count: int64(value.Count()),
		BucketOption: &scpb.Distribution_ExplicitBuckets_{
			&scpb.Distribution_ExplicitBuckets{
				Bounds: value.ExplicitBounds().AsRaw(),
			},
		},
		BucketCounts: toInt64Slice(value.BucketCounts().AsRaw()),
	}

	exemplars := value.Exemplars()
	// We compute `sum` from `exemplars`, instead of getting it from `value.Sum()`.
	// Sum is optional in pmetric.HistogramDataPoint.
	// Note that Exemplars are optional as well.
	var sum float64
	for i := 0; i < exemplars.Len(); i++ {
		ex := exemplars.At(i)
		// Service Control only has double value type:
		// https://github.com/googleapis/googleapis/blob/40bad3ea0d48ecf250296ea7438035b8e45227dd/google/api/distribution.proto#L147,
		// so we convert everything to float64.
		var value float64
		switch ex.ValueType() {
		case pmetric.ExemplarValueTypeDouble:
			value = ex.DoubleValue()
		case pmetric.ExemplarValueTypeInt:
			value = float64(ex.IntValue())
		}
		sum += value
		result.Exemplars = append(result.Exemplars, &distribution.Distribution_Exemplar{
			Value:     value,
			Timestamp: timestamppb.New(ex.Timestamp().AsTime()),
		})
	}

	// Service Control API does not like if we set non-zero mean and deviation when count=0:
	// https://github.com/googleapis/google-api-go-client/blob/8a616df18563c9fedaead92873d200cd8c2d0503/servicecontrol/v1/servicecontrol-gen.go#L853
	if value.Count() > 0 {
		if exemplars.Len() > 0 {
			// We can calculate everything ourselves.
			mean := sum / float64(value.Count())
			result.Mean = mean

			// SumOfSquaredDeviation calculation:
			// https://github.com/googleapis/google-api-go-client/blob/8a616df18563c9fedaead92873d200cd8c2d0503/servicecontrol/v1/servicecontrol-gen.go#L860
			var sumDev float64
			for _, exemplar := range result.Exemplars {
				dev := exemplar.Value - mean
				sumDev += dev * dev
			}
			result.SumOfSquaredDeviation = sumDev
		} else {
			// We can only hope that `value.Sum()` is populated, and calculate `result.Mean` from that.
			// There is no way to calculate `result.SumOfSquaredDeviation`.
			result.Mean = value.Sum() / float64(value.Count())
		}
	}
	return result
}