func()

in exporter/collector/googlemanagedprometheus/extra_metrics.go [149:257]


func (c Config) addTargetInfoMetric(m pmetric.Metrics) {
	if !c.ExtraMetricsConfig.EnableTargetInfo {
		return
	}
	ids := make(map[resourceID]struct{})
	rms := m.ResourceMetrics()
	// loop over input (original) resource metrics
	for i := 0; i < rms.Len(); i++ {
		rm := rms.At(i)
		getResourceAttr := func(attr string) string {
			if v, ok := rm.Resource().Attributes().Get(attr); ok {
				return v.AsString()
			}
			return ""
		}

		// Keep track of the most recent time in this resource's metrics
		// Use that time for the timestamp of the new metric
		latestTime := time.Time{}
		for j := 0; j < rm.ScopeMetrics().Len(); j++ {
			for k := 0; k < rm.ScopeMetrics().At(j).Metrics().Len(); k++ {
				metric := rm.ScopeMetrics().At(j).Metrics().At(k)

				switch metric.Type() {
				case pmetric.MetricTypeSum:
					sum := metric.Sum()
					points := sum.DataPoints()
					for x := 0; x < points.Len(); x++ {
						if latestTime.Before(points.At(x).Timestamp().AsTime()) {
							latestTime = points.At(x).Timestamp().AsTime()
						}
					}
				case pmetric.MetricTypeGauge:
					gauge := metric.Gauge()
					points := gauge.DataPoints()
					for x := 0; x < points.Len(); x++ {
						if latestTime.Before(points.At(x).Timestamp().AsTime()) {
							latestTime = points.At(x).Timestamp().AsTime()
						}
					}
				case pmetric.MetricTypeSummary:
					summary := metric.Summary()
					points := summary.DataPoints()
					for x := 0; x < points.Len(); x++ {
						if latestTime.Before(points.At(x).Timestamp().AsTime()) {
							latestTime = points.At(x).Timestamp().AsTime()
						}
					}
				case pmetric.MetricTypeHistogram:
					hist := metric.Histogram()
					points := hist.DataPoints()
					for x := 0; x < points.Len(); x++ {
						if latestTime.Before(points.At(x).Timestamp().AsTime()) {
							latestTime = points.At(x).Timestamp().AsTime()
						}
					}
				case pmetric.MetricTypeExponentialHistogram:
					eh := metric.ExponentialHistogram()
					points := eh.DataPoints()
					for x := 0; x < points.Len(); x++ {
						if latestTime.Before(points.At(x).Timestamp().AsTime()) {
							latestTime = points.At(x).Timestamp().AsTime()
						}
					}
				}
			}
		}

		id := resourceID{
			serviceName:       getResourceAttr(semconv.AttributeServiceName),
			serviceNamespace:  getResourceAttr(semconv.AttributeServiceNamespace),
			serviceInstanceID: getResourceAttr(semconv.AttributeServiceInstanceID),
		}
		if _, ok := ids[id]; ok {
			// We've already added a resource with the same ID before, so skip this one.
			continue
		}
		ids[id] = struct{}{}

		// create the target_info metric as a Gauge with value 1
		targetInfoMetric := rm.ScopeMetrics().AppendEmpty().Metrics().AppendEmpty()
		targetInfoMetric.SetName("target_info")

		dataPoint := targetInfoMetric.SetEmptyGauge().DataPoints().AppendEmpty()
		dataPoint.SetIntValue(1)
		dataPoint.SetTimestamp(pcommon.NewTimestampFromTime(latestTime))

		// copy Resource attributes to the metric except for service.name, service.namespace, and service.instance.id
		// because those three attributes (if present) will be copied to resource attributes.
		// See https://opentelemetry.io/docs/specs/otel/compatibility/prometheus_and_openmetrics/#resource-attributes-1
		// Also drop reserved GMP labels (location, cluster, namespace, job, service_namespace, instance).
		// Other "fallback" attributes which could become `job` or `instance` in the absence of those three
		// (such as k8s.pod.name or faas.name) will be duplicated as a resource attribute and metric label.
		rm.Resource().Attributes().Range(func(k string, v pcommon.Value) bool {
			if k != semconv.AttributeServiceName &&
				k != semconv.AttributeServiceNamespace &&
				k != semconv.AttributeServiceInstanceID &&
				k != locationLabel &&
				k != clusterLabel &&
				k != namespaceLabel &&
				k != jobLabel &&
				k != serviceNamespaceLabel &&
				k != instanceLabel {
				dataPoint.Attributes().PutStr(k, v.AsString())
			}
			return true
		})
	}
}