func()

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
	}
}