in agent/stats/snapshotter.go [119:229]
func (snapshotter *Snapshotter) computeDeltaForMetricFamily(oldMetricFamily, newMetricFamily *io_prometheus_client.MetricFamily, delta map[string]*io_prometheus_client.MetricFamily) {
if oldMetricFamily == nil && newMetricFamily == nil {
log.Error("both metric families are empty, cannot compute delta")
return
}
// The assumption here is that, the metric family from new snapshot should always exist when computing the
// delta. This is because the metric families from old snapshot should be a subset of the metric families from
// new snapshot.
if newMetricFamily == nil {
log.Debugf("metricFamily from new snapshot must exist to compute the delta")
return
}
metricName := newMetricFamily.GetName()
metricType := newMetricFamily.GetType()
if _, ok := delta[metricName]; !ok {
// Create deltaEntry if it does not exist
delta[metricName] = &io_prometheus_client.MetricFamily{
Name: &metricName,
Type: &metricType,
Metric: make([]*io_prometheus_client.Metric, len(newMetricFamily.Metric)),
}
}
// Create a metric lookup
metricLookup := make(map[string]*io_prometheus_client.Metric)
if oldMetricFamily != nil {
for _, oldMetric := range oldMetricFamily.Metric {
metricKey := generateMetricKey(oldMetric.Label)
metricLookup[metricKey] = oldMetric
}
}
for metricIndex, newMetricFamilyMetric := range newMetricFamily.Metric {
deltaMetric := &io_prometheus_client.Metric{Label: newMetricFamilyMetric.GetLabel()}
metricKey := generateMetricKey(newMetricFamilyMetric.GetLabel())
oldMetric := metricLookup[metricKey]
switch metricType {
case io_prometheus_client.MetricType_COUNTER:
{
newValue := newMetricFamilyMetric.GetCounter().GetValue()
// We only compute delta when the same metric label was matched. Note that the metricKey consists of
// the labels of the metric.
if oldMetric != nil {
oldValue := oldMetric.GetCounter().GetValue()
deltaMetric.Counter = &io_prometheus_client.Counter{Value: proto.Float64(newValue - oldValue)}
} else {
deltaMetric.Counter = &io_prometheus_client.Counter{Value: proto.Float64(newValue), Exemplar: newMetricFamilyMetric.GetCounter().GetExemplar()}
}
}
case io_prometheus_client.MetricType_GAUGE:
{
// We don't need to compute the delta value of Gauge since itself is a metric that represents a single
// numerical value that can arbitrarily go up and down.
newValue := newMetricFamilyMetric.GetGauge().GetValue()
deltaMetric.Gauge = &io_prometheus_client.Gauge{Value: proto.Float64(newValue)}
}
case io_prometheus_client.MetricType_UNTYPED:
fallthrough
case io_prometheus_client.MetricType_SUMMARY:
// Do nothing, we are not expecting Untyped and Summary metric type.
log.Errorf("unsupported metric type for delta computation: %s", metricType)
case io_prometheus_client.MetricType_HISTOGRAM:
{
newMetricFamilyMetricHistogram := newMetricFamilyMetric.GetHistogram()
deltaHistogram := &io_prometheus_client.Histogram{}
if newMetricFamilyMetricHistogram.Bucket != nil {
newBucket := newMetricFamilyMetricHistogram.GetBucket()
deltaHistogram.Bucket = make([]*io_prometheus_client.Bucket, len(newBucket))
for bucketIndex, newBk := range newBucket {
deltaBucket := &io_prometheus_client.Bucket{UpperBound: newBk.UpperBound}
// Make sure the metric with same tags exists in the old metrics and the bucket size remains the
// same before we compute the delta. Otherwise, use the new metric as delta.
// Note that the bucket size should not change, this is just adding a safe check.
if oldMetric != nil && len(oldMetric.GetHistogram().Bucket) == len(newBucket) {
oldBk := oldMetric.GetHistogram().Bucket[bucketIndex]
deltaBucket.CumulativeCount = proto.Uint64(newBk.GetCumulativeCount() - oldBk.GetCumulativeCount())
} else {
deltaBucket.CumulativeCount = proto.Uint64(newBk.GetCumulativeCount())
}
deltaHistogram.Bucket[bucketIndex] = deltaBucket
}
}
if newMetricFamilyMetricHistogram.SampleCount != nil {
newSampleCount := newMetricFamilyMetricHistogram.GetSampleCount()
// We only compute delta when the same metric label was matched. Note that the metricKey consists of
// the labels of the metric.
if oldMetric != nil {
oldSampleCount := oldMetric.GetHistogram().GetSampleCount()
deltaHistogram.SampleCount = proto.Uint64(newSampleCount - oldSampleCount)
} else {
deltaHistogram.SampleCount = proto.Uint64(newSampleCount)
}
}
if newMetricFamilyMetricHistogram.SampleSum != nil {
newSampleSum := newMetricFamilyMetricHistogram.GetSampleSum()
if oldMetric != nil {
oldSampleSum := oldMetric.GetHistogram().GetSampleSum()
deltaHistogram.SampleSum = proto.Float64(newSampleSum - oldSampleSum)
} else {
deltaHistogram.SampleSum = proto.Float64(newSampleSum)
}
}
deltaMetric.Histogram = deltaHistogram
}
}
delta[metricName].Metric[metricIndex] = deltaMetric
}
}