From 78b1d28174bbb40863710383ef4f97c028cb07da Mon Sep 17 00:00:00 2001 From: Juraj Michalek Date: Sat, 30 Sep 2023 10:19:03 +0200 Subject: [PATCH 01/20] feat: prometheus remote write send metadata --- .../prometheusremotewriteexporter/exporter.go | 9 ++- .../prometheusremotewriteexporter/helper.go | 16 ++++-- .../otlp_to_openmetrics_metadata.go | 57 +++++++++++++++++++ 3 files changed, 74 insertions(+), 8 deletions(-) create mode 100644 pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go diff --git a/exporter/prometheusremotewriteexporter/exporter.go b/exporter/prometheusremotewriteexporter/exporter.go index 865abcc06636..46e8faa77e56 100644 --- a/exporter/prometheusremotewriteexporter/exporter.go +++ b/exporter/prometheusremotewriteexporter/exporter.go @@ -130,12 +130,15 @@ func (prwe *prwExporter) PushMetrics(ctx context.Context, md pmetric.Metrics) er case <-prwe.closeChan: return errors.New("shutdown has been called") default: + + m := prometheusremotewrite.OtelMetricsToMetadata(md) + tsMap, err := prometheusremotewrite.FromMetrics(md, prwe.exporterSettings) if err != nil { err = consumererror.NewPermanent(err) } // Call export even if a conversion error, since there may be points that were successfully converted. - return multierr.Combine(err, prwe.handleExport(ctx, tsMap)) + return multierr.Combine(err, prwe.handleExport(ctx, tsMap, m)) } } @@ -151,14 +154,14 @@ func validateAndSanitizeExternalLabels(cfg *Config) (map[string]string, error) { return sanitizedLabels, nil } -func (prwe *prwExporter) handleExport(ctx context.Context, tsMap map[string]*prompb.TimeSeries) error { +func (prwe *prwExporter) handleExport(ctx context.Context, tsMap map[string]*prompb.TimeSeries, m []prompb.MetricMetadata) error { // There are no metrics to export, so return. if len(tsMap) == 0 { return nil } // Calls the helper function to convert and batch the TsMap to the desired format - requests, err := batchTimeSeries(tsMap, prwe.maxBatchSizeBytes) + requests, err := batchTimeSeries(tsMap, prwe.maxBatchSizeBytes, m) if err != nil { return err } diff --git a/exporter/prometheusremotewriteexporter/helper.go b/exporter/prometheusremotewriteexporter/helper.go index b468609380c8..362ff66cff28 100644 --- a/exporter/prometheusremotewriteexporter/helper.go +++ b/exporter/prometheusremotewriteexporter/helper.go @@ -11,7 +11,7 @@ import ( ) // batchTimeSeries splits series into multiple batch write requests. -func batchTimeSeries(tsMap map[string]*prompb.TimeSeries, maxBatchByteSize int) ([]*prompb.WriteRequest, error) { +func batchTimeSeries(tsMap map[string]*prompb.TimeSeries, maxBatchByteSize int, m []prompb.MetricMetadata) ([]*prompb.WriteRequest, error) { if len(tsMap) == 0 { return nil, errors.New("invalid tsMap: cannot be empty map") } @@ -20,12 +20,17 @@ func batchTimeSeries(tsMap map[string]*prompb.TimeSeries, maxBatchByteSize int) tsArray := make([]prompb.TimeSeries, 0, len(tsMap)) sizeOfCurrentBatch := 0 + sizeOfM := 0 + for _, mi := range m { + sizeOfM += mi.Size() + } + i := 0 for _, v := range tsMap { sizeOfSeries := v.Size() - if sizeOfCurrentBatch+sizeOfSeries >= maxBatchByteSize { - wrapped := convertTimeseriesToRequest(tsArray) + if sizeOfCurrentBatch+sizeOfSeries+sizeOfM >= maxBatchByteSize { + wrapped := convertTimeseriesToRequest(tsArray, m) requests = append(requests, wrapped) tsArray = make([]prompb.TimeSeries, 0, len(tsMap)-i) @@ -38,14 +43,14 @@ func batchTimeSeries(tsMap map[string]*prompb.TimeSeries, maxBatchByteSize int) } if len(tsArray) != 0 { - wrapped := convertTimeseriesToRequest(tsArray) + wrapped := convertTimeseriesToRequest(tsArray, m) requests = append(requests, wrapped) } return requests, nil } -func convertTimeseriesToRequest(tsArray []prompb.TimeSeries) *prompb.WriteRequest { +func convertTimeseriesToRequest(tsArray []prompb.TimeSeries, m []prompb.MetricMetadata) *prompb.WriteRequest { // the remote_write endpoint only requires the timeseries. // otlp defines it's own way to handle metric metadata return &prompb.WriteRequest{ @@ -54,6 +59,7 @@ func convertTimeseriesToRequest(tsArray []prompb.TimeSeries) *prompb.WriteReques // * https://github.com/open-telemetry/wg-prometheus/issues/10 // * https://github.com/open-telemetry/opentelemetry-collector/issues/2315 Timeseries: orderBySampleTimestamp(tsArray), + Metadata: m, } } diff --git a/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go b/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go new file mode 100644 index 000000000000..b22afe8faa05 --- /dev/null +++ b/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go @@ -0,0 +1,57 @@ +package prometheusremotewrite + +import ( + prometheustranslator "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheus" + "github.com/prometheus/prometheus/prompb" + "go.opentelemetry.io/collector/pdata/pmetric" +) + +func otelMetricTypeToPromMetricType(otelMetric pmetric.Metric) prompb.MetricMetadata_MetricType { + switch otelMetric.Type() { + case pmetric.MetricTypeGauge: + return prompb.MetricMetadata_GAUGE + case pmetric.MetricTypeSum: + metricType := prompb.MetricMetadata_GAUGE + if otelMetric.Sum().IsMonotonic() { + metricType = prompb.MetricMetadata_COUNTER + } + return metricType + case pmetric.MetricTypeHistogram: + return prompb.MetricMetadata_HISTOGRAM + case pmetric.MetricTypeSummary: + return prompb.MetricMetadata_SUMMARY + case pmetric.MetricTypeExponentialHistogram: + return prompb.MetricMetadata_HISTOGRAM + } + return prompb.MetricMetadata_UNKNOWN +} + +func OtelMetricsToMetadata(md pmetric.Metrics) []prompb.MetricMetadata { + resourceMetricsSlice := md.ResourceMetrics() + + metadataLength := 0 + for i := 0; i < resourceMetricsSlice.Len(); i++ { + metadataLength += resourceMetricsSlice.At(i).ScopeMetrics().Len() + } + var metadata = make([]prompb.MetricMetadata, 0, metadataLength) + for i := 0; i < resourceMetricsSlice.Len(); i++ { + resourceMetrics := resourceMetricsSlice.At(i) + scopeMetricsSlice := resourceMetrics.ScopeMetrics() + + for j := 0; j < scopeMetricsSlice.Len(); j++ { + scopeMetrics := scopeMetricsSlice.At(j) + for k := 0; k < scopeMetrics.Metrics().Len(); k++ { + metric := scopeMetrics.Metrics().At(k) + entry := prompb.MetricMetadata{ + Type: otelMetricTypeToPromMetricType(metric), + MetricFamilyName: prometheustranslator.BuildCompliantName(metric, "", true), // TODO expose addMetricSuffixes in configuration + Help: metric.Description(), + Unit: metric.Unit(), + } + metadata = append(metadata, entry) + } + } + } + + return metadata +} From 14d0c3b662dcd9e060c7f4d61d9c8b1d5c63d176 Mon Sep 17 00:00:00 2001 From: Juraj Michalek Date: Mon, 9 Oct 2023 22:23:47 +0200 Subject: [PATCH 02/20] chore: added config option for sending medatada --- .../prometheusremotewriteexporter/config.go | 3 +++ .../prometheusremotewriteexporter/exporter.go | 11 ++++++++--- .../prometheusremotewriteexporter/helper.go | 19 ++++++++++++++++--- .../prometheusremotewrite/metrics_to_prw.go | 1 + .../otlp_to_openmetrics_metadata.go | 4 ++-- 5 files changed, 30 insertions(+), 8 deletions(-) diff --git a/exporter/prometheusremotewriteexporter/config.go b/exporter/prometheusremotewriteexporter/config.go index 22b0b3a969d9..2ceeffcae326 100644 --- a/exporter/prometheusremotewriteexporter/config.go +++ b/exporter/prometheusremotewriteexporter/config.go @@ -48,6 +48,9 @@ type Config struct { // AddMetricSuffixes controls whether unit and type suffixes are added to metrics on export AddMetricSuffixes bool `mapstructure:"add_metric_suffixes"` + + // AddMetricSuffixes controls whether unit and type suffixes are added to metrics on export + SendMetadata bool `mapstructure:"send_metadata"` } type CreatedMetric struct { diff --git a/exporter/prometheusremotewriteexporter/exporter.go b/exporter/prometheusremotewriteexporter/exporter.go index 46e8faa77e56..bb94b77d4c5e 100644 --- a/exporter/prometheusremotewriteexporter/exporter.go +++ b/exporter/prometheusremotewriteexporter/exporter.go @@ -77,6 +77,7 @@ func newPRWExporter(cfg *Config, set exporter.CreateSettings) (*prwExporter, err DisableTargetInfo: !cfg.TargetInfo.Enabled, ExportCreatedMetric: cfg.CreatedMetric.Enabled, AddMetricSuffixes: cfg.AddMetricSuffixes, + SendMetadata: true, }, } if cfg.WAL == nil { @@ -131,14 +132,18 @@ func (prwe *prwExporter) PushMetrics(ctx context.Context, md pmetric.Metrics) er return errors.New("shutdown has been called") default: - m := prometheusremotewrite.OtelMetricsToMetadata(md) - tsMap, err := prometheusremotewrite.FromMetrics(md, prwe.exporterSettings) if err != nil { err = consumererror.NewPermanent(err) } + + if prwe.exporterSettings.SendMetadata { + m := prometheusremotewrite.OtelMetricsToMetadata(md, prwe.exporterSettings.AddMetricSuffixes) + // Call export even if a conversion error, since there may be points that were successfully converted. + return multierr.Combine(err, prwe.handleExport(ctx, tsMap, m)) + } // Call export even if a conversion error, since there may be points that were successfully converted. - return multierr.Combine(err, prwe.handleExport(ctx, tsMap, m)) + return multierr.Combine(err, prwe.handleExport(ctx, tsMap, nil)) } } diff --git a/exporter/prometheusremotewriteexporter/helper.go b/exporter/prometheusremotewriteexporter/helper.go index 362ff66cff28..f943622cd8a7 100644 --- a/exporter/prometheusremotewriteexporter/helper.go +++ b/exporter/prometheusremotewriteexporter/helper.go @@ -21,8 +21,10 @@ func batchTimeSeries(tsMap map[string]*prompb.TimeSeries, maxBatchByteSize int, sizeOfCurrentBatch := 0 sizeOfM := 0 - for _, mi := range m { - sizeOfM += mi.Size() + if m != nil { + for _, mi := range m { + sizeOfM += mi.Size() + } } i := 0 @@ -53,13 +55,24 @@ func batchTimeSeries(tsMap map[string]*prompb.TimeSeries, maxBatchByteSize int, func convertTimeseriesToRequest(tsArray []prompb.TimeSeries, m []prompb.MetricMetadata) *prompb.WriteRequest { // the remote_write endpoint only requires the timeseries. // otlp defines it's own way to handle metric metadata + + if m != nil { + return &prompb.WriteRequest{ + // Prometheus requires time series to be sorted by Timestamp to avoid out of order problems. + // See: + // * https://github.com/open-telemetry/wg-prometheus/issues/10 + // * https://github.com/open-telemetry/opentelemetry-collector/issues/2315 + Timeseries: orderBySampleTimestamp(tsArray), + Metadata: m, + } + } + return &prompb.WriteRequest{ // Prometheus requires time series to be sorted by Timestamp to avoid out of order problems. // See: // * https://github.com/open-telemetry/wg-prometheus/issues/10 // * https://github.com/open-telemetry/opentelemetry-collector/issues/2315 Timeseries: orderBySampleTimestamp(tsArray), - Metadata: m, } } diff --git a/pkg/translator/prometheusremotewrite/metrics_to_prw.go b/pkg/translator/prometheusremotewrite/metrics_to_prw.go index 2889a4e9640a..c189f299d037 100644 --- a/pkg/translator/prometheusremotewrite/metrics_to_prw.go +++ b/pkg/translator/prometheusremotewrite/metrics_to_prw.go @@ -21,6 +21,7 @@ type Settings struct { DisableTargetInfo bool ExportCreatedMetric bool AddMetricSuffixes bool + SendMetadata bool } // FromMetrics converts pmetric.Metrics to prometheus remote write format. diff --git a/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go b/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go index b22afe8faa05..852aab1c47e7 100644 --- a/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go +++ b/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go @@ -26,7 +26,7 @@ func otelMetricTypeToPromMetricType(otelMetric pmetric.Metric) prompb.MetricMeta return prompb.MetricMetadata_UNKNOWN } -func OtelMetricsToMetadata(md pmetric.Metrics) []prompb.MetricMetadata { +func OtelMetricsToMetadata(md pmetric.Metrics, addMetricSuffixes bool) []prompb.MetricMetadata { resourceMetricsSlice := md.ResourceMetrics() metadataLength := 0 @@ -44,7 +44,7 @@ func OtelMetricsToMetadata(md pmetric.Metrics) []prompb.MetricMetadata { metric := scopeMetrics.Metrics().At(k) entry := prompb.MetricMetadata{ Type: otelMetricTypeToPromMetricType(metric), - MetricFamilyName: prometheustranslator.BuildCompliantName(metric, "", true), // TODO expose addMetricSuffixes in configuration + MetricFamilyName: prometheustranslator.BuildCompliantName(metric, "", addMetricSuffixes), Help: metric.Description(), Unit: metric.Unit(), } From 54fc6994404a076c4c93c38a2af180917ae40277 Mon Sep 17 00:00:00 2001 From: Juraj Michalek Date: Mon, 9 Oct 2023 22:41:34 +0200 Subject: [PATCH 03/20] chore: send metadata in separate requests --- .../prometheusremotewriteexporter/exporter.go | 2 +- .../prometheusremotewriteexporter/helper.go | 53 ++++++++++++++----- .../otlp_to_openmetrics_metadata.go | 6 +-- 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/exporter/prometheusremotewriteexporter/exporter.go b/exporter/prometheusremotewriteexporter/exporter.go index bb94b77d4c5e..701a14327c67 100644 --- a/exporter/prometheusremotewriteexporter/exporter.go +++ b/exporter/prometheusremotewriteexporter/exporter.go @@ -159,7 +159,7 @@ func validateAndSanitizeExternalLabels(cfg *Config) (map[string]string, error) { return sanitizedLabels, nil } -func (prwe *prwExporter) handleExport(ctx context.Context, tsMap map[string]*prompb.TimeSeries, m []prompb.MetricMetadata) error { +func (prwe *prwExporter) handleExport(ctx context.Context, tsMap map[string]*prompb.TimeSeries, m []*prompb.MetricMetadata) error { // There are no metrics to export, so return. if len(tsMap) == 0 { return nil diff --git a/exporter/prometheusremotewriteexporter/helper.go b/exporter/prometheusremotewriteexporter/helper.go index f943622cd8a7..c7187bf004d3 100644 --- a/exporter/prometheusremotewriteexporter/helper.go +++ b/exporter/prometheusremotewriteexporter/helper.go @@ -11,28 +11,21 @@ import ( ) // batchTimeSeries splits series into multiple batch write requests. -func batchTimeSeries(tsMap map[string]*prompb.TimeSeries, maxBatchByteSize int, m []prompb.MetricMetadata) ([]*prompb.WriteRequest, error) { +func batchTimeSeries(tsMap map[string]*prompb.TimeSeries, maxBatchByteSize int, m []*prompb.MetricMetadata) ([]*prompb.WriteRequest, error) { if len(tsMap) == 0 { return nil, errors.New("invalid tsMap: cannot be empty map") } - requests := make([]*prompb.WriteRequest, 0, len(tsMap)) + requests := make([]*prompb.WriteRequest, 0, len(tsMap)+len(m)) tsArray := make([]prompb.TimeSeries, 0, len(tsMap)) sizeOfCurrentBatch := 0 - sizeOfM := 0 - if m != nil { - for _, mi := range m { - sizeOfM += mi.Size() - } - } - i := 0 for _, v := range tsMap { sizeOfSeries := v.Size() - if sizeOfCurrentBatch+sizeOfSeries+sizeOfM >= maxBatchByteSize { - wrapped := convertTimeseriesToRequest(tsArray, m) + if sizeOfCurrentBatch+sizeOfSeries >= maxBatchByteSize { + wrapped := convertTimeseriesToRequest(tsArray, nil) requests = append(requests, wrapped) tsArray = make([]prompb.TimeSeries, 0, len(tsMap)-i) @@ -45,7 +38,31 @@ func batchTimeSeries(tsMap map[string]*prompb.TimeSeries, maxBatchByteSize int, } if len(tsArray) != 0 { - wrapped := convertTimeseriesToRequest(tsArray, m) + wrapped := convertTimeseriesToRequest(tsArray, nil) + requests = append(requests, wrapped) + } + + mArray := make([]prompb.MetricMetadata, 0, len(m)) + sizeOfCurrentBatch = 0 + i = 0 + for _, v := range m { + sizeOfM := v.Size() + + if sizeOfCurrentBatch+sizeOfM >= maxBatchByteSize { + wrapped := convertTimeseriesToRequest(nil, mArray) + requests = append(requests, wrapped) + + mArray = make([]prompb.MetricMetadata, 0, len(m)-i) + sizeOfCurrentBatch = 0 + } + + mArray = append(mArray, *v) + sizeOfCurrentBatch += sizeOfM + i++ + } + + if len(mArray) != 0 { + wrapped := convertTimeseriesToRequest(nil, mArray) requests = append(requests, wrapped) } @@ -56,7 +73,7 @@ func convertTimeseriesToRequest(tsArray []prompb.TimeSeries, m []prompb.MetricMe // the remote_write endpoint only requires the timeseries. // otlp defines it's own way to handle metric metadata - if m != nil { + if m != nil && tsArray != nil { return &prompb.WriteRequest{ // Prometheus requires time series to be sorted by Timestamp to avoid out of order problems. // See: @@ -67,6 +84,16 @@ func convertTimeseriesToRequest(tsArray []prompb.TimeSeries, m []prompb.MetricMe } } + if m != nil { + return &prompb.WriteRequest{ + // Prometheus requires time series to be sorted by Timestamp to avoid out of order problems. + // See: + // * https://github.com/open-telemetry/wg-prometheus/issues/10 + // * https://github.com/open-telemetry/opentelemetry-collector/issues/2315 + Metadata: m, + } + } + return &prompb.WriteRequest{ // Prometheus requires time series to be sorted by Timestamp to avoid out of order problems. // See: diff --git a/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go b/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go index 852aab1c47e7..1ebcaa93f0b7 100644 --- a/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go +++ b/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go @@ -26,14 +26,14 @@ func otelMetricTypeToPromMetricType(otelMetric pmetric.Metric) prompb.MetricMeta return prompb.MetricMetadata_UNKNOWN } -func OtelMetricsToMetadata(md pmetric.Metrics, addMetricSuffixes bool) []prompb.MetricMetadata { +func OtelMetricsToMetadata(md pmetric.Metrics, addMetricSuffixes bool) []*prompb.MetricMetadata { resourceMetricsSlice := md.ResourceMetrics() metadataLength := 0 for i := 0; i < resourceMetricsSlice.Len(); i++ { metadataLength += resourceMetricsSlice.At(i).ScopeMetrics().Len() } - var metadata = make([]prompb.MetricMetadata, 0, metadataLength) + var metadata = make([]*prompb.MetricMetadata, 0, metadataLength) for i := 0; i < resourceMetricsSlice.Len(); i++ { resourceMetrics := resourceMetricsSlice.At(i) scopeMetricsSlice := resourceMetrics.ScopeMetrics() @@ -48,7 +48,7 @@ func OtelMetricsToMetadata(md pmetric.Metrics, addMetricSuffixes bool) []prompb. Help: metric.Description(), Unit: metric.Unit(), } - metadata = append(metadata, entry) + metadata = append(metadata, &entry) } } } From 3343077a3df2423f3525b9de5d60a2d2ea65c070 Mon Sep 17 00:00:00 2001 From: Juraj Michalek Date: Sat, 28 Oct 2023 20:57:30 +0200 Subject: [PATCH 04/20] chore: ran make goporto to make the pipeline pass --- .../prometheusremotewrite/otlp_to_openmetrics_metadata.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go b/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go index 1ebcaa93f0b7..19c282f38151 100644 --- a/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go +++ b/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go @@ -1,4 +1,4 @@ -package prometheusremotewrite +package prometheusremotewrite // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheusremotewrite" import ( prometheustranslator "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheus" From 0d27a442930846b7de03b3771970479e0d96ecd8 Mon Sep 17 00:00:00 2001 From: Juraj Michalek Date: Sat, 28 Oct 2023 22:34:15 +0200 Subject: [PATCH 05/20] chore: add missing license to the file --- .../prometheusremotewrite/otlp_to_openmetrics_metadata.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go b/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go index 19c282f38151..43ff8c17c3ed 100644 --- a/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go +++ b/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + package prometheusremotewrite // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheusremotewrite" import ( From 44c22dd1a6d5f3c7965394721de0403ceac98e57 Mon Sep 17 00:00:00 2001 From: Juraj Michalek Date: Sun, 29 Oct 2023 10:51:31 +0100 Subject: [PATCH 06/20] chore: more fixes for pipeline failing --- exporter/prometheusremotewriteexporter/exporter_test.go | 4 ++-- exporter/prometheusremotewriteexporter/helper_test.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/exporter/prometheusremotewriteexporter/exporter_test.go b/exporter/prometheusremotewriteexporter/exporter_test.go index 2a317cebb91d..9bcfcac1a2a0 100644 --- a/exporter/prometheusremotewriteexporter/exporter_test.go +++ b/exporter/prometheusremotewriteexporter/exporter_test.go @@ -368,7 +368,7 @@ func runExportPipeline(ts *prompb.TimeSeries, endpoint *url.URL) error { return err } - return prwe.handleExport(context.Background(), testmap) + return prwe.handleExport(context.Background(), testmap, nil) } // Test_PushMetrics checks the number of TimeSeries received by server and the number of metrics dropped is the same as @@ -919,7 +919,7 @@ func TestWALOnExporterRoundTrip(t *testing.T) { "timeseries1": ts1, "timeseries2": ts2, } - errs := prwe.handleExport(ctx, tsMap) + errs := prwe.handleExport(ctx, tsMap, nil) assert.NoError(t, errs) // Shutdown after we've written to the WAL. This ensures that our // exported data in-flight will flushed flushed to the WAL before exiting. diff --git a/exporter/prometheusremotewriteexporter/helper_test.go b/exporter/prometheusremotewriteexporter/helper_test.go index 9528607a6fd9..1b838ec0a46b 100644 --- a/exporter/prometheusremotewriteexporter/helper_test.go +++ b/exporter/prometheusremotewriteexporter/helper_test.go @@ -57,7 +57,7 @@ func Test_batchTimeSeries(t *testing.T) { // run tests for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - requests, err := batchTimeSeries(tt.tsMap, tt.maxBatchByteSize) + requests, err := batchTimeSeries(tt.tsMap, tt.maxBatchByteSize, nil) if tt.returnErr { assert.Error(t, err) return @@ -116,7 +116,7 @@ func TestEnsureTimeseriesPointsAreSortedByTimestamp(t *testing.T) { }, }, } - got := convertTimeseriesToRequest(outOfOrder) + got := convertTimeseriesToRequest(outOfOrder, nil) // We must ensure that the resulting Timeseries' sample points are sorted by Timestamp. want := &prompb.WriteRequest{ From afae26f5d952d27f0edbe482f00ba99c7b8070cf Mon Sep 17 00:00:00 2001 From: Juraj Michalek Date: Sun, 29 Oct 2023 11:35:24 +0100 Subject: [PATCH 07/20] chore: more fixes for pipeline failing --- .../prometheusremotewrite/otlp_to_openmetrics_metadata.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go b/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go index 43ff8c17c3ed..995465da47f0 100644 --- a/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go +++ b/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go @@ -4,9 +4,10 @@ package prometheusremotewrite // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheusremotewrite" import ( - prometheustranslator "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheus" "github.com/prometheus/prometheus/prompb" "go.opentelemetry.io/collector/pdata/pmetric" + + prometheustranslator "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheus" ) func otelMetricTypeToPromMetricType(otelMetric pmetric.Metric) prompb.MetricMetadata_MetricType { From 4663b680de4920e56dcbd07fb32edb855108d00d Mon Sep 17 00:00:00 2001 From: Juraj Michalek Date: Thu, 9 Nov 2023 12:02:08 +0100 Subject: [PATCH 08/20] chore: disable sending metadata by default --- exporter/prometheusremotewriteexporter/exporter.go | 2 +- exporter/prometheusremotewriteexporter/factory.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/exporter/prometheusremotewriteexporter/exporter.go b/exporter/prometheusremotewriteexporter/exporter.go index 701a14327c67..eef1a3c6de92 100644 --- a/exporter/prometheusremotewriteexporter/exporter.go +++ b/exporter/prometheusremotewriteexporter/exporter.go @@ -77,7 +77,7 @@ func newPRWExporter(cfg *Config, set exporter.CreateSettings) (*prwExporter, err DisableTargetInfo: !cfg.TargetInfo.Enabled, ExportCreatedMetric: cfg.CreatedMetric.Enabled, AddMetricSuffixes: cfg.AddMetricSuffixes, - SendMetadata: true, + SendMetadata: cfg.SendMetadata, }, } if cfg.WAL == nil { diff --git a/exporter/prometheusremotewriteexporter/factory.go b/exporter/prometheusremotewriteexporter/factory.go index 63135b9b8cb5..f90aa41b21ac 100644 --- a/exporter/prometheusremotewriteexporter/factory.go +++ b/exporter/prometheusremotewriteexporter/factory.go @@ -81,6 +81,7 @@ func createDefaultConfig() component.Config { Multiplier: backoff.DefaultMultiplier, }, AddMetricSuffixes: true, + SendMetadata: false, HTTPClientSettings: confighttp.HTTPClientSettings{ Endpoint: "http://some.url:9411/api/prom/push", // We almost read 0 bytes, so no need to tune ReadBufferSize. From dfa93e0f6d1d42bd5e222ec8b20bde79a0bef33c Mon Sep 17 00:00:00 2001 From: Juraj Michalek Date: Thu, 9 Nov 2023 12:09:41 +0100 Subject: [PATCH 09/20] chore: update remote write exporter readme --- exporter/prometheusremotewriteexporter/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/exporter/prometheusremotewriteexporter/README.md b/exporter/prometheusremotewriteexporter/README.md index f15b3c4b76e8..f6dacf9da748 100644 --- a/exporter/prometheusremotewriteexporter/README.md +++ b/exporter/prometheusremotewriteexporter/README.md @@ -52,6 +52,7 @@ The following settings can be optionally configured: - *Note the following headers cannot be changed: `Content-Encoding`, `Content-Type`, `X-Prometheus-Remote-Write-Version`, and `User-Agent`.* - `namespace`: prefix attached to each exported metric name. - `add_metric_suffixes`: If set to false, type and unit suffixes will not be added to metrics. Default: true. +- `send_metadata`: If set to true, prometheus metadata will generated and sent. Default: false. - `remote_write_queue`: fine tuning for queueing and sending of the outgoing remote writes. - `enabled`: enable the sending queue (default: `true`) - `queue_size`: number of OTLP metrics that can be queued. Ignored if `enabled` is `false` (default: `10000`) From 2c724f90fa05a4b3e88ccd7ed2d39948f776cc45 Mon Sep 17 00:00:00 2001 From: Juraj Michalek Date: Thu, 9 Nov 2023 15:27:55 +0100 Subject: [PATCH 10/20] chore: added unit tests --- .../otlp_to_openmetrics_metadata_test.go | 234 ++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata_test.go diff --git a/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata_test.go b/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata_test.go new file mode 100644 index 000000000000..fee41fbf6291 --- /dev/null +++ b/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata_test.go @@ -0,0 +1,234 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package prometheusremotewrite // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheusremotewrite" +import ( + "testing" + "time" + + "github.com/prometheus/prometheus/prompb" + "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/pmetric" + + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/testdata" + prometheustranslator "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheus" +) + +func TestOtelMetricTypeToPromMetricType(t *testing.T) { + ts := uint64(time.Now().UnixNano()) + tests := []struct { + name string + metric func() pmetric.Metric + want prompb.MetricMetadata_MetricType + }{ + { + name: "gauge", + metric: func() pmetric.Metric { + return getIntGaugeMetric( + "test", + pcommon.NewMap(), + 1, ts, + ) + }, + want: prompb.MetricMetadata_GAUGE, + }, + { + name: "sum", + metric: func() pmetric.Metric { + return getIntSumMetric( + "test", + pcommon.NewMap(), + pmetric.AggregationTemporalityCumulative, + 1, ts, + ) + }, + want: prompb.MetricMetadata_GAUGE, + }, + { + name: "monotonic cumulative", + metric: func() pmetric.Metric { + metric := pmetric.NewMetric() + metric.SetName("test_sum") + metric.SetEmptySum().SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) + metric.SetEmptySum().SetIsMonotonic(true) + + dp := metric.Sum().DataPoints().AppendEmpty() + dp.SetDoubleValue(1) + + return metric + }, + want: prompb.MetricMetadata_COUNTER, + }, + { + name: "cumulative histogram", + metric: func() pmetric.Metric { + m := getHistogramMetric("", pcommon.NewMap(), pmetric.AggregationTemporalityCumulative, 0, 0, 0, []float64{}, []uint64{}) + return m + }, + want: prompb.MetricMetadata_HISTOGRAM, + }, + { + name: "cumulative exponential histogram", + metric: func() pmetric.Metric { + metric := pmetric.NewMetric() + h := metric.SetEmptyExponentialHistogram() + h.SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) + return metric + }, + want: prompb.MetricMetadata_HISTOGRAM, + }, + { + name: "summary with start time", + metric: func() pmetric.Metric { + metric := pmetric.NewMetric() + metric.SetName("test_summary") + metric.SetEmptySummary() + + dp := metric.Summary().DataPoints().AppendEmpty() + dp.SetTimestamp(pcommon.Timestamp(ts)) + dp.SetStartTimestamp(pcommon.Timestamp(ts)) + + return metric + }, + want: prompb.MetricMetadata_SUMMARY, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + metric := tt.metric() + + metricType := otelMetricTypeToPromMetricType(metric) + + assert.Equal(t, tt.want, metricType) + }) + } +} + +func TestOtelMetricsToMetadata(t *testing.T) { + ts := uint64(time.Now().UnixNano()) + tests := []struct { + name string + metrics pmetric.Metrics + want []*prompb.MetricMetadata + }{ + { + name: "all types§", + metrics: GenerateMetricsAllTypesNoDataPointsHelpAndUnit(), + want: []*prompb.MetricMetadata{ + { + Type: prompb.MetricMetadata_GAUGE, + MetricFamilyName: prometheustranslator.BuildCompliantName(getIntGaugeMetric( + testdata.TestGaugeDoubleMetricName, + pcommon.NewMap(), + 1, ts, + ), "", false), + Help: "gauge description", + Unit: "testing_unit", + }, + { + Type: prompb.MetricMetadata_GAUGE, + MetricFamilyName: prometheustranslator.BuildCompliantName(getIntGaugeMetric( + testdata.TestGaugeIntMetricName, + pcommon.NewMap(), + 1, ts, + ), "", false), + Help: "gauge description", + Unit: "testing_unit", + }, + { + Type: prompb.MetricMetadata_COUNTER, + MetricFamilyName: prometheustranslator.BuildCompliantName(getIntGaugeMetric( + testdata.TestSumDoubleMetricName, + pcommon.NewMap(), + 1, ts, + ), "", false), + Help: "sum description", + Unit: "testing_unit", + }, + { + Type: prompb.MetricMetadata_COUNTER, + MetricFamilyName: prometheustranslator.BuildCompliantName(getIntGaugeMetric( + testdata.TestSumIntMetricName, + pcommon.NewMap(), + 1, ts, + ), "", false), + Help: "sum description", + Unit: "testing_unit", + }, + { + Type: prompb.MetricMetadata_HISTOGRAM, + MetricFamilyName: prometheustranslator.BuildCompliantName(getIntGaugeMetric( + testdata.TestDoubleHistogramMetricName, + pcommon.NewMap(), + 1, ts, + ), "", false), + Help: "histogram description", + Unit: "testing_unit", + }, + { + Type: prompb.MetricMetadata_SUMMARY, + MetricFamilyName: prometheustranslator.BuildCompliantName(getIntGaugeMetric( + testdata.TestDoubleSummaryMetricName, + pcommon.NewMap(), + 1, ts, + ), "", false), + Help: "summary description", + Unit: "testing_unit", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + metaData := OtelMetricsToMetadata(tt.metrics, false) + + for i := 0; i < len(metaData); i++ { + assert.Equal(t, tt.want[i].Type, metaData[i].Type) + assert.Equal(t, tt.want[i].MetricFamilyName, metaData[i].MetricFamilyName) + assert.Equal(t, tt.want[i].Help, metaData[i].Help) + assert.Equal(t, tt.want[i].Unit, metaData[i].Unit) + } + + }) + } +} + +func GenerateMetricsAllTypesNoDataPointsHelpAndUnit() pmetric.Metrics { + md := testdata.GenerateMetricsOneEmptyInstrumentationLibrary() + ilm0 := md.ResourceMetrics().At(0).ScopeMetrics().At(0) + ms := ilm0.Metrics() + initMetric(ms.AppendEmpty(), testdata.TestGaugeDoubleMetricName, pmetric.MetricTypeGauge, "gauge description", "testing_unit") + initMetric(ms.AppendEmpty(), testdata.TestGaugeIntMetricName, pmetric.MetricTypeGauge, "gauge description", "testing_unit") + initMetric(ms.AppendEmpty(), testdata.TestSumDoubleMetricName, pmetric.MetricTypeSum, "sum description", "testing_unit") + initMetric(ms.AppendEmpty(), testdata.TestSumIntMetricName, pmetric.MetricTypeSum, "sum description", "testing_unit") + initMetric(ms.AppendEmpty(), testdata.TestDoubleHistogramMetricName, pmetric.MetricTypeHistogram, "histogram description", "testing_unit") + initMetric(ms.AppendEmpty(), testdata.TestDoubleSummaryMetricName, pmetric.MetricTypeSummary, "summary description", "testing_unit") + return md +} + +func initMetric(m pmetric.Metric, name string, ty pmetric.MetricType, desc string, unit string) { + m.SetName(name) + m.SetDescription(desc) + m.SetUnit(unit) + //exhaustive:enforce + switch ty { + case pmetric.MetricTypeGauge: + m.SetEmptyGauge() + + case pmetric.MetricTypeSum: + sum := m.SetEmptySum() + sum.SetIsMonotonic(true) + sum.SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) + + case pmetric.MetricTypeHistogram: + histo := m.SetEmptyHistogram() + histo.SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) + + case pmetric.MetricTypeExponentialHistogram: + m.SetEmptyExponentialHistogram() + + case pmetric.MetricTypeSummary: + m.SetEmptySummary() + } +} From c3c4d022ff861aaa41cbb190185d832141c672fe Mon Sep 17 00:00:00 2001 From: Juraj Michalek Date: Thu, 9 Nov 2023 15:55:29 +0100 Subject: [PATCH 11/20] chore: added changelog entry --- ...ote-write-add-option-to-send-metadata.yaml | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100755 .chloggen/prometheus-remote-write-add-option-to-send-metadata.yaml diff --git a/.chloggen/prometheus-remote-write-add-option-to-send-metadata.yaml b/.chloggen/prometheus-remote-write-add-option-to-send-metadata.yaml new file mode 100755 index 000000000000..45199deb9018 --- /dev/null +++ b/.chloggen/prometheus-remote-write-add-option-to-send-metadata.yaml @@ -0,0 +1,27 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: exporter/prometheusremotewrite + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: prometheusremotewrite exporter add option to send metadata + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [ 13849 ] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# If your change doesn't affect end users or the exported elements of any package, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [] From 62588b8b4918cd61e1b994440801850a322fc7a0 Mon Sep 17 00:00:00 2001 From: Juraj Michalek Date: Thu, 9 Nov 2023 16:00:13 +0100 Subject: [PATCH 12/20] chore: make linter happy --- .../otlp_to_openmetrics_metadata_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata_test.go b/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata_test.go index fee41fbf6291..dde1ee31c4c2 100644 --- a/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata_test.go +++ b/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata_test.go @@ -124,7 +124,7 @@ func TestOtelMetricsToMetadata(t *testing.T) { 1, ts, ), "", false), Help: "gauge description", - Unit: "testing_unit", + Unit: "testing_unit1", }, { Type: prompb.MetricMetadata_GAUGE, @@ -198,7 +198,7 @@ func GenerateMetricsAllTypesNoDataPointsHelpAndUnit() pmetric.Metrics { md := testdata.GenerateMetricsOneEmptyInstrumentationLibrary() ilm0 := md.ResourceMetrics().At(0).ScopeMetrics().At(0) ms := ilm0.Metrics() - initMetric(ms.AppendEmpty(), testdata.TestGaugeDoubleMetricName, pmetric.MetricTypeGauge, "gauge description", "testing_unit") + initMetric(ms.AppendEmpty(), testdata.TestGaugeDoubleMetricName, pmetric.MetricTypeGauge, "gauge description", "testing_unit1") initMetric(ms.AppendEmpty(), testdata.TestGaugeIntMetricName, pmetric.MetricTypeGauge, "gauge description", "testing_unit") initMetric(ms.AppendEmpty(), testdata.TestSumDoubleMetricName, pmetric.MetricTypeSum, "sum description", "testing_unit") initMetric(ms.AppendEmpty(), testdata.TestSumIntMetricName, pmetric.MetricTypeSum, "sum description", "testing_unit") From 41c68e7c446ebcb07a60a8bd0f789feca0cf5270 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juraj=20Mich=C3=A1lek?= Date: Wed, 15 Nov 2023 18:49:04 +0100 Subject: [PATCH 13/20] Update exporter/prometheusremotewriteexporter/README.md Co-authored-by: Antoine Toulme --- exporter/prometheusremotewriteexporter/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exporter/prometheusremotewriteexporter/README.md b/exporter/prometheusremotewriteexporter/README.md index f6dacf9da748..d230c2f9765c 100644 --- a/exporter/prometheusremotewriteexporter/README.md +++ b/exporter/prometheusremotewriteexporter/README.md @@ -52,7 +52,7 @@ The following settings can be optionally configured: - *Note the following headers cannot be changed: `Content-Encoding`, `Content-Type`, `X-Prometheus-Remote-Write-Version`, and `User-Agent`.* - `namespace`: prefix attached to each exported metric name. - `add_metric_suffixes`: If set to false, type and unit suffixes will not be added to metrics. Default: true. -- `send_metadata`: If set to true, prometheus metadata will generated and sent. Default: false. +- `send_metadata`: If set to true, prometheus metadata will be generated and sent. Default: false. - `remote_write_queue`: fine tuning for queueing and sending of the outgoing remote writes. - `enabled`: enable the sending queue (default: `true`) - `queue_size`: number of OTLP metrics that can be queued. Ignored if `enabled` is `false` (default: `10000`) From ec03854a064e4b6358d3cc125f8eb3f0b8a2d1f7 Mon Sep 17 00:00:00 2001 From: Juraj Michalek Date: Wed, 15 Nov 2023 18:51:41 +0100 Subject: [PATCH 14/20] chore: update comment copied comment --- exporter/prometheusremotewriteexporter/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exporter/prometheusremotewriteexporter/config.go b/exporter/prometheusremotewriteexporter/config.go index 2ceeffcae326..1f854918d2d5 100644 --- a/exporter/prometheusremotewriteexporter/config.go +++ b/exporter/prometheusremotewriteexporter/config.go @@ -49,7 +49,7 @@ type Config struct { // AddMetricSuffixes controls whether unit and type suffixes are added to metrics on export AddMetricSuffixes bool `mapstructure:"add_metric_suffixes"` - // AddMetricSuffixes controls whether unit and type suffixes are added to metrics on export + // SendMetadata controls whether prometheus metadata will be generated and sent SendMetadata bool `mapstructure:"send_metadata"` } From 7ae3f820296e73d22bee897cc8b32291cdacf134 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juraj=20Mich=C3=A1lek?= Date: Sun, 19 Nov 2023 17:36:56 +0100 Subject: [PATCH 15/20] Update exporter/prometheusremotewriteexporter/exporter.go Co-authored-by: Anthony Mirabella --- exporter/prometheusremotewriteexporter/exporter.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/exporter/prometheusremotewriteexporter/exporter.go b/exporter/prometheusremotewriteexporter/exporter.go index eef1a3c6de92..c9c849bcf5c7 100644 --- a/exporter/prometheusremotewriteexporter/exporter.go +++ b/exporter/prometheusremotewriteexporter/exporter.go @@ -137,10 +137,9 @@ func (prwe *prwExporter) PushMetrics(ctx context.Context, md pmetric.Metrics) er err = consumererror.NewPermanent(err) } + var m []*prompb.MetricMetadata if prwe.exporterSettings.SendMetadata { - m := prometheusremotewrite.OtelMetricsToMetadata(md, prwe.exporterSettings.AddMetricSuffixes) - // Call export even if a conversion error, since there may be points that were successfully converted. - return multierr.Combine(err, prwe.handleExport(ctx, tsMap, m)) + m = prometheusremotewrite.OtelMetricsToMetadata(md, prwe.exporterSettings.AddMetricSuffixes) } // Call export even if a conversion error, since there may be points that were successfully converted. return multierr.Combine(err, prwe.handleExport(ctx, tsMap, nil)) From c47cea6cd3ebda56433573072287ec8e910d842a Mon Sep 17 00:00:00 2001 From: Juraj Michalek Date: Sun, 19 Nov 2023 17:52:13 +0100 Subject: [PATCH 16/20] chore: add separate method for creating metadata requests --- .../prometheusremotewriteexporter/helper.go | 38 ++++++------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/exporter/prometheusremotewriteexporter/helper.go b/exporter/prometheusremotewriteexporter/helper.go index c7187bf004d3..d5eca3086a7e 100644 --- a/exporter/prometheusremotewriteexporter/helper.go +++ b/exporter/prometheusremotewriteexporter/helper.go @@ -25,7 +25,7 @@ func batchTimeSeries(tsMap map[string]*prompb.TimeSeries, maxBatchByteSize int, sizeOfSeries := v.Size() if sizeOfCurrentBatch+sizeOfSeries >= maxBatchByteSize { - wrapped := convertTimeseriesToRequest(tsArray, nil) + wrapped := convertTimeseriesToRequest(tsArray) requests = append(requests, wrapped) tsArray = make([]prompb.TimeSeries, 0, len(tsMap)-i) @@ -38,7 +38,7 @@ func batchTimeSeries(tsMap map[string]*prompb.TimeSeries, maxBatchByteSize int, } if len(tsArray) != 0 { - wrapped := convertTimeseriesToRequest(tsArray, nil) + wrapped := convertTimeseriesToRequest(tsArray) requests = append(requests, wrapped) } @@ -49,7 +49,7 @@ func batchTimeSeries(tsMap map[string]*prompb.TimeSeries, maxBatchByteSize int, sizeOfM := v.Size() if sizeOfCurrentBatch+sizeOfM >= maxBatchByteSize { - wrapped := convertTimeseriesToRequest(nil, mArray) + wrapped := convertMetadataToRequest(mArray) requests = append(requests, wrapped) mArray = make([]prompb.MetricMetadata, 0, len(m)-i) @@ -62,38 +62,16 @@ func batchTimeSeries(tsMap map[string]*prompb.TimeSeries, maxBatchByteSize int, } if len(mArray) != 0 { - wrapped := convertTimeseriesToRequest(nil, mArray) + wrapped := convertMetadataToRequest(mArray) requests = append(requests, wrapped) } return requests, nil } -func convertTimeseriesToRequest(tsArray []prompb.TimeSeries, m []prompb.MetricMetadata) *prompb.WriteRequest { +func convertTimeseriesToRequest(tsArray []prompb.TimeSeries) *prompb.WriteRequest { // the remote_write endpoint only requires the timeseries. // otlp defines it's own way to handle metric metadata - - if m != nil && tsArray != nil { - return &prompb.WriteRequest{ - // Prometheus requires time series to be sorted by Timestamp to avoid out of order problems. - // See: - // * https://github.com/open-telemetry/wg-prometheus/issues/10 - // * https://github.com/open-telemetry/opentelemetry-collector/issues/2315 - Timeseries: orderBySampleTimestamp(tsArray), - Metadata: m, - } - } - - if m != nil { - return &prompb.WriteRequest{ - // Prometheus requires time series to be sorted by Timestamp to avoid out of order problems. - // See: - // * https://github.com/open-telemetry/wg-prometheus/issues/10 - // * https://github.com/open-telemetry/opentelemetry-collector/issues/2315 - Metadata: m, - } - } - return &prompb.WriteRequest{ // Prometheus requires time series to be sorted by Timestamp to avoid out of order problems. // See: @@ -103,6 +81,12 @@ func convertTimeseriesToRequest(tsArray []prompb.TimeSeries, m []prompb.MetricMe } } +func convertMetadataToRequest(m []prompb.MetricMetadata) *prompb.WriteRequest { + return &prompb.WriteRequest{ + Metadata: m, + } +} + func orderBySampleTimestamp(tsArray []prompb.TimeSeries) []prompb.TimeSeries { for i := range tsArray { sL := tsArray[i].Samples From a05570c4be69220660742bed6c06c536b30d2fe1 Mon Sep 17 00:00:00 2001 From: Juraj Michalek Date: Sun, 19 Nov 2023 22:03:20 +0100 Subject: [PATCH 17/20] chore: fix metadata length calculation --- .../prometheusremotewrite/otlp_to_openmetrics_metadata.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go b/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go index 995465da47f0..558685ca2918 100644 --- a/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go +++ b/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go @@ -35,8 +35,12 @@ func OtelMetricsToMetadata(md pmetric.Metrics, addMetricSuffixes bool) []*prompb metadataLength := 0 for i := 0; i < resourceMetricsSlice.Len(); i++ { - metadataLength += resourceMetricsSlice.At(i).ScopeMetrics().Len() + scopeMetricsSlice := resourceMetricsSlice.At(i).ScopeMetrics() + for j := 0; j < scopeMetricsSlice.Len(); j++ { + metadataLength += scopeMetricsSlice.At(j).Metrics().Len() + } } + var metadata = make([]*prompb.MetricMetadata, 0, metadataLength) for i := 0; i < resourceMetricsSlice.Len(); i++ { resourceMetrics := resourceMetricsSlice.At(i) From 90c79d7720901b5dd292d89ec5eb68d50db3ec85 Mon Sep 17 00:00:00 2001 From: Juraj Michalek Date: Sun, 19 Nov 2023 22:10:41 +0100 Subject: [PATCH 18/20] chore: fix pass metadata requests --- exporter/prometheusremotewriteexporter/exporter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exporter/prometheusremotewriteexporter/exporter.go b/exporter/prometheusremotewriteexporter/exporter.go index c9c849bcf5c7..cc7a65f294b1 100644 --- a/exporter/prometheusremotewriteexporter/exporter.go +++ b/exporter/prometheusremotewriteexporter/exporter.go @@ -142,7 +142,7 @@ func (prwe *prwExporter) PushMetrics(ctx context.Context, md pmetric.Metrics) er m = prometheusremotewrite.OtelMetricsToMetadata(md, prwe.exporterSettings.AddMetricSuffixes) } // Call export even if a conversion error, since there may be points that were successfully converted. - return multierr.Combine(err, prwe.handleExport(ctx, tsMap, nil)) + return multierr.Combine(err, prwe.handleExport(ctx, tsMap, m)) } } From 9f7f769fd11c3bf3f7ef5cbf492ca11e366c42b9 Mon Sep 17 00:00:00 2001 From: Juraj Michalek Date: Sun, 19 Nov 2023 22:18:40 +0100 Subject: [PATCH 19/20] chore: update call of a function --- exporter/prometheusremotewriteexporter/helper_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exporter/prometheusremotewriteexporter/helper_test.go b/exporter/prometheusremotewriteexporter/helper_test.go index 1b838ec0a46b..8404bb6c9e9e 100644 --- a/exporter/prometheusremotewriteexporter/helper_test.go +++ b/exporter/prometheusremotewriteexporter/helper_test.go @@ -116,7 +116,7 @@ func TestEnsureTimeseriesPointsAreSortedByTimestamp(t *testing.T) { }, }, } - got := convertTimeseriesToRequest(outOfOrder, nil) + got := convertTimeseriesToRequest(outOfOrder) // We must ensure that the resulting Timeseries' sample points are sorted by Timestamp. want := &prompb.WriteRequest{ From cfaa046602222d1fb5493a404316a2feeb6f7fa0 Mon Sep 17 00:00:00 2001 From: Juraj Michalek Date: Mon, 20 Nov 2023 20:46:56 +0100 Subject: [PATCH 20/20] chore: don't set unit in metadata for now --- .../otlp_to_openmetrics_metadata.go | 1 - .../otlp_to_openmetrics_metadata_test.go | 26 +++++++------------ 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go b/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go index 558685ca2918..b2564a3d187f 100644 --- a/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go +++ b/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata.go @@ -54,7 +54,6 @@ func OtelMetricsToMetadata(md pmetric.Metrics, addMetricSuffixes bool) []*prompb Type: otelMetricTypeToPromMetricType(metric), MetricFamilyName: prometheustranslator.BuildCompliantName(metric, "", addMetricSuffixes), Help: metric.Description(), - Unit: metric.Unit(), } metadata = append(metadata, &entry) } diff --git a/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata_test.go b/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata_test.go index dde1ee31c4c2..6807ed7319d1 100644 --- a/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata_test.go +++ b/pkg/translator/prometheusremotewrite/otlp_to_openmetrics_metadata_test.go @@ -114,7 +114,7 @@ func TestOtelMetricsToMetadata(t *testing.T) { }{ { name: "all types§", - metrics: GenerateMetricsAllTypesNoDataPointsHelpAndUnit(), + metrics: GenerateMetricsAllTypesNoDataPointsHelp(), want: []*prompb.MetricMetadata{ { Type: prompb.MetricMetadata_GAUGE, @@ -124,7 +124,6 @@ func TestOtelMetricsToMetadata(t *testing.T) { 1, ts, ), "", false), Help: "gauge description", - Unit: "testing_unit1", }, { Type: prompb.MetricMetadata_GAUGE, @@ -134,7 +133,6 @@ func TestOtelMetricsToMetadata(t *testing.T) { 1, ts, ), "", false), Help: "gauge description", - Unit: "testing_unit", }, { Type: prompb.MetricMetadata_COUNTER, @@ -144,7 +142,6 @@ func TestOtelMetricsToMetadata(t *testing.T) { 1, ts, ), "", false), Help: "sum description", - Unit: "testing_unit", }, { Type: prompb.MetricMetadata_COUNTER, @@ -154,7 +151,6 @@ func TestOtelMetricsToMetadata(t *testing.T) { 1, ts, ), "", false), Help: "sum description", - Unit: "testing_unit", }, { Type: prompb.MetricMetadata_HISTOGRAM, @@ -164,7 +160,6 @@ func TestOtelMetricsToMetadata(t *testing.T) { 1, ts, ), "", false), Help: "histogram description", - Unit: "testing_unit", }, { Type: prompb.MetricMetadata_SUMMARY, @@ -174,7 +169,6 @@ func TestOtelMetricsToMetadata(t *testing.T) { 1, ts, ), "", false), Help: "summary description", - Unit: "testing_unit", }, }, }, @@ -187,30 +181,28 @@ func TestOtelMetricsToMetadata(t *testing.T) { assert.Equal(t, tt.want[i].Type, metaData[i].Type) assert.Equal(t, tt.want[i].MetricFamilyName, metaData[i].MetricFamilyName) assert.Equal(t, tt.want[i].Help, metaData[i].Help) - assert.Equal(t, tt.want[i].Unit, metaData[i].Unit) } }) } } -func GenerateMetricsAllTypesNoDataPointsHelpAndUnit() pmetric.Metrics { +func GenerateMetricsAllTypesNoDataPointsHelp() pmetric.Metrics { md := testdata.GenerateMetricsOneEmptyInstrumentationLibrary() ilm0 := md.ResourceMetrics().At(0).ScopeMetrics().At(0) ms := ilm0.Metrics() - initMetric(ms.AppendEmpty(), testdata.TestGaugeDoubleMetricName, pmetric.MetricTypeGauge, "gauge description", "testing_unit1") - initMetric(ms.AppendEmpty(), testdata.TestGaugeIntMetricName, pmetric.MetricTypeGauge, "gauge description", "testing_unit") - initMetric(ms.AppendEmpty(), testdata.TestSumDoubleMetricName, pmetric.MetricTypeSum, "sum description", "testing_unit") - initMetric(ms.AppendEmpty(), testdata.TestSumIntMetricName, pmetric.MetricTypeSum, "sum description", "testing_unit") - initMetric(ms.AppendEmpty(), testdata.TestDoubleHistogramMetricName, pmetric.MetricTypeHistogram, "histogram description", "testing_unit") - initMetric(ms.AppendEmpty(), testdata.TestDoubleSummaryMetricName, pmetric.MetricTypeSummary, "summary description", "testing_unit") + initMetric(ms.AppendEmpty(), testdata.TestGaugeDoubleMetricName, pmetric.MetricTypeGauge, "gauge description") + initMetric(ms.AppendEmpty(), testdata.TestGaugeIntMetricName, pmetric.MetricTypeGauge, "gauge description") + initMetric(ms.AppendEmpty(), testdata.TestSumDoubleMetricName, pmetric.MetricTypeSum, "sum description") + initMetric(ms.AppendEmpty(), testdata.TestSumIntMetricName, pmetric.MetricTypeSum, "sum description") + initMetric(ms.AppendEmpty(), testdata.TestDoubleHistogramMetricName, pmetric.MetricTypeHistogram, "histogram description") + initMetric(ms.AppendEmpty(), testdata.TestDoubleSummaryMetricName, pmetric.MetricTypeSummary, "summary description") return md } -func initMetric(m pmetric.Metric, name string, ty pmetric.MetricType, desc string, unit string) { +func initMetric(m pmetric.Metric, name string, ty pmetric.MetricType, desc string) { m.SetName(name) m.SetDescription(desc) - m.SetUnit(unit) //exhaustive:enforce switch ty { case pmetric.MetricTypeGauge: