From 6814790b56593356d0f22b2d1cda985809c15a6b Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Tue, 18 Oct 2022 14:19:14 +0000 Subject: [PATCH] refactor prometheus exporter to slightly improve performance --- exporters/prometheus/exporter.go | 104 +++++++------------------------ 1 file changed, 23 insertions(+), 81 deletions(-) diff --git a/exporters/prometheus/exporter.go b/exporters/prometheus/exporter.go index 007dc2f50d9..f481df7bada 100644 --- a/exporters/prometheus/exporter.go +++ b/exporters/prometheus/exporter.go @@ -69,13 +69,6 @@ func New(opts ...Option) (*Exporter, error) { // Describe implements prometheus.Collector. func (c *collector) Describe(ch chan<- *prometheus.Desc) { - metrics, err := c.reader.Collect(context.TODO()) - if err != nil { - otel.Handle(err) - } - for _, metricData := range getMetricData(metrics) { - ch <- metricData.description - } } // Collect implements prometheus.Collector. @@ -87,64 +80,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) @@ -155,52 +110,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