From 1503ae0240747b8224e424c7210dda6193a78984 Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Mon, 17 Oct 2022 21:07:16 +0000 Subject: [PATCH] refactor prometheus exporter to slightly improve performance --- exporters/prometheus/exporter.go | 97 ++++++++------------------------ 1 file changed, 23 insertions(+), 74 deletions(-) diff --git a/exporters/prometheus/exporter.go b/exporters/prometheus/exporter.go index e1fad7e8416..bb2453b7d24 100644 --- a/exporters/prometheus/exporter.go +++ b/exporters/prometheus/exporter.go @@ -86,64 +86,26 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) { // TODO(#3166): convert otel resource to target_info // see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/data-model.md#resource-attributes-1 - for _, metricData := range getMetricData(metrics) { - if metricData.valueType == prometheus.UntypedValue { - m, err := prometheus.NewConstHistogram(metricData.description, metricData.histogramCount, metricData.histogramSum, metricData.histogramBuckets, metricData.attributeValues...) - if err != nil { - otel.Handle(err) - continue - } - ch <- m - } else { - m, err := prometheus.NewConstMetric(metricData.description, metricData.valueType, metricData.value, metricData.attributeValues...) - if err != nil { - otel.Handle(err) - continue - } - ch <- m - } - } -} - -// metricData holds the metadata as well as values for individual data points. -type metricData struct { - // name should include the unit as a suffix (before _total on counters) - // see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/data-model.md#metric-metadata-1 - name string - description *prometheus.Desc - attributeValues []string - valueType prometheus.ValueType - value float64 - histogramCount uint64 - histogramSum float64 - histogramBuckets map[float64]uint64 -} - -func getMetricData(metrics metricdata.ResourceMetrics) []*metricData { - allMetrics := make([]*metricData, 0) for _, scopeMetrics := range metrics.ScopeMetrics { for _, m := range scopeMetrics.Metrics { switch v := m.Data.(type) { case metricdata.Histogram: - allMetrics = append(allMetrics, getHistogramMetricData(v, m)...) + addHistogramMetric(ch, v, m) case metricdata.Sum[int64]: - allMetrics = append(allMetrics, getSumMetricData(v, m)...) + addSumMetric(ch, v, m) case metricdata.Sum[float64]: - allMetrics = append(allMetrics, getSumMetricData(v, m)...) + addSumMetric(ch, v, m) case metricdata.Gauge[int64]: - allMetrics = append(allMetrics, getGaugeMetricData(v, m)...) + addGaugeMetric(ch, v, m) case metricdata.Gauge[float64]: - allMetrics = append(allMetrics, getGaugeMetricData(v, m)...) + addGaugeMetric(ch, v, m) } } } - - return allMetrics } -func getHistogramMetricData(histogram metricdata.Histogram, m metricdata.Metrics) []*metricData { +func addHistogramMetric(ch chan<- prometheus.Metric, histogram metricdata.Histogram, m metricdata.Metrics) { // TODO(https://github.com/open-telemetry/opentelemetry-go/issues/3163): support exemplars - dataPoints := make([]*metricData, 0, len(histogram.DataPoints)) for _, dp := range histogram.DataPoints { keys, values := getAttrs(dp.Attributes) desc := prometheus.NewDesc(sanitizeName(m.Name), m.Description, keys, nil) @@ -154,52 +116,39 @@ func getHistogramMetricData(histogram metricdata.Histogram, m metricdata.Metrics cumulativeCount += dp.BucketCounts[i] buckets[bound] = cumulativeCount } - md := &metricData{ - name: m.Name, - description: desc, - attributeValues: values, - valueType: prometheus.UntypedValue, - histogramCount: dp.Count, - histogramSum: dp.Sum, - histogramBuckets: buckets, + m, err := prometheus.NewConstHistogram(desc, dp.Count, dp.Sum, buckets, values...) + if err != nil { + otel.Handle(err) + continue } - dataPoints = append(dataPoints, md) + ch <- m } - return dataPoints } -func getSumMetricData[N int64 | float64](sum metricdata.Sum[N], m metricdata.Metrics) []*metricData { - dataPoints := make([]*metricData, 0, len(sum.DataPoints)) +func addSumMetric[N int64 | float64](ch chan<- prometheus.Metric, sum metricdata.Sum[N], m metricdata.Metrics) { for _, dp := range sum.DataPoints { keys, values := getAttrs(dp.Attributes) desc := prometheus.NewDesc(sanitizeName(m.Name), m.Description, keys, nil) - md := &metricData{ - name: m.Name, - description: desc, - attributeValues: values, - valueType: prometheus.CounterValue, - value: float64(dp.Value), + m, err := prometheus.NewConstMetric(desc, prometheus.CounterValue, float64(dp.Value), values...) + if err != nil { + otel.Handle(err) + continue } - dataPoints = append(dataPoints, md) + ch <- m } - return dataPoints } -func getGaugeMetricData[N int64 | float64](gauge metricdata.Gauge[N], m metricdata.Metrics) []*metricData { - dataPoints := make([]*metricData, 0, len(gauge.DataPoints)) +func addGaugeMetric[N int64 | float64](ch chan<- prometheus.Metric, gauge metricdata.Gauge[N], m metricdata.Metrics) { for _, dp := range gauge.DataPoints { keys, values := getAttrs(dp.Attributes) desc := prometheus.NewDesc(sanitizeName(m.Name), m.Description, keys, nil) - md := &metricData{ - name: m.Name, - description: desc, - attributeValues: values, - valueType: prometheus.GaugeValue, - value: float64(dp.Value), + m, err := prometheus.NewConstMetric(desc, prometheus.GaugeValue, float64(dp.Value), values...) + if err != nil { + otel.Handle(err) + continue } - dataPoints = append(dataPoints, md) + ch <- m } - return dataPoints } // getAttrs parses the attribute.Set to two lists of matching Prometheus-style