diff --git a/exporter/signalfxexporter/README.md b/exporter/signalfxexporter/README.md index fc99d952abad6..1337a636f09aa 100644 --- a/exporter/signalfxexporter/README.md +++ b/exporter/signalfxexporter/README.md @@ -41,9 +41,10 @@ The following configuration options can also be configured: configuration option for [SignalFx receiver](../../receiver/signalfxreceiver/README.md) to preserve datapoint origin. -- `exclude_metrics`: metric names that will be excluded from sending - to Signalfx backend. If `send_compatible_metrics` or `translation_rules` - options are enabled, the exclusion will be applied on translated metrics. +- `exclude_metrics`: List of metric filters that will determine metrics to be + excluded from sending to Signalfx backend. If `send_compatible_metrics` + or `translation_rules` options are enabled, the exclusion will be applied + on translated metrics. See [here](./testdata/config.yaml) for examples. - `headers` (no default): Headers to pass in the payload. - `log_dimension_updates` (default = `false`): Whether or not to log dimension updates. diff --git a/exporter/signalfxexporter/config.go b/exporter/signalfxexporter/config.go index 458125df0a29f..5721fde8ce0f4 100644 --- a/exporter/signalfxexporter/config.go +++ b/exporter/signalfxexporter/config.go @@ -25,6 +25,7 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/signalfxexporter/correlation" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/signalfxexporter/translation" + "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/signalfxexporter/translation/dpfilters" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/splunk" ) @@ -85,10 +86,11 @@ type Config struct { // And keep `override=true` in resourcedetection config. SyncHostMetadata bool `mapstructure:"sync_host_metadata"` - // ExcludeMetrics defines metrics that will be excluded from sending to Signalfx - // backend. If translations enabled with SendCompatibleMetrics or TranslationRules - // options, the exclusion will be applied on translated metrics. - ExcludeMetrics []string `mapstructure:"exclude_metrics"` + // ExcludeMetrics defines dpfilter.MetricFilters that will determine metrics to be + // excluded from sending to SignalFx backend. If translations enabled with + // SendCompatibleMetrics or TranslationRules options, the exclusion will be applied + // on translated metrics. + ExcludeMetrics []dpfilters.MetricFilter `mapstructure:"exclude_metrics"` // Correlation configuration for syncing traces service and environment to metrics. Correlation *correlation.Config `mapstructure:"correlation"` diff --git a/exporter/signalfxexporter/config_test.go b/exporter/signalfxexporter/config_test.go index b296e0069ac2b..7fc88c5fa2730 100644 --- a/exporter/signalfxexporter/config_test.go +++ b/exporter/signalfxexporter/config_test.go @@ -34,6 +34,7 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/signalfxexporter/correlation" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/signalfxexporter/translation" + "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/signalfxexporter/translation/dpfilters" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/splunk" ) @@ -94,6 +95,26 @@ func TestLoadConfig(t *testing.T) { }, }, }, + ExcludeMetrics: []dpfilters.MetricFilter{ + { + MetricName: "metric1", + }, + { + MetricNames: []string{"metric2", "metric3"}, + }, + { + MetricName: "metric4", + Dimensions: map[string]interface{}{ + "dimension_key": "dimension_val", + }, + }, + { + MetricName: "metric5", + Dimensions: map[string]interface{}{ + "dimension_key": []interface{}{"dimension_val1", "dimension_val2"}, + }, + }, + }, DeltaTranslationTTL: 3600, Correlation: &correlation.Config{ HTTPClientSettings: confighttp.HTTPClientSettings{ diff --git a/exporter/signalfxexporter/exporter.go b/exporter/signalfxexporter/exporter.go index 8844cde377dbb..8ffbc8f2f33b9 100644 --- a/exporter/signalfxexporter/exporter.go +++ b/exporter/signalfxexporter/exporter.go @@ -90,6 +90,11 @@ func newSignalFxExporter( headers := buildHeaders(config) + converter, err := translation.NewMetricsConverter(logger, options.metricTranslator, config.ExcludeMetrics) + if err != nil { + return nil, fmt.Errorf("failed to create metric converter: %v", err) + } + dpClient := &sfxDPClient{ sfxClientBase: sfxClientBase{ ingestURL: options.ingestURL, @@ -103,7 +108,7 @@ func newSignalFxExporter( }, logger: logger, accessTokenPassthrough: config.AccessTokenPassthrough, - converter: translation.NewMetricsConverter(logger, options.metricTranslator), + converter: converter, } dimClient := dimensions.NewDimensionClient( diff --git a/exporter/signalfxexporter/exporter_test.go b/exporter/signalfxexporter/exporter_test.go index e188f244a95bc..18b6f3acaa4f6 100644 --- a/exporter/signalfxexporter/exporter_test.go +++ b/exporter/signalfxexporter/exporter_test.go @@ -41,6 +41,7 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/signalfxexporter/dimensions" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/signalfxexporter/translation" + "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/signalfxexporter/translation/dpfilters" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/common/metrics" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/splunk" ) @@ -64,6 +65,15 @@ func TestNew(t *testing.T) { }, wantErr: true, }, + { + name: "fails to create metrics converter", + config: &Config{ + AccessToken: "test", + Realm: "realm", + ExcludeMetrics: []dpfilters.MetricFilter{{}}, + }, + wantErr: true, + }, { name: "successfully create exporter", config: &Config{ @@ -184,6 +194,9 @@ func TestConsumeMetrics(t *testing.T) { serverURL, err := url.Parse(server.URL) assert.NoError(t, err) + c, err := translation.NewMetricsConverter(zap.NewNop(), nil, nil) + require.NoError(t, err) + require.NotNil(t, c) dpClient := &sfxDPClient{ sfxClientBase: sfxClientBase{ ingestURL: serverURL, @@ -196,7 +209,7 @@ func TestConsumeMetrics(t *testing.T) { }}, }, logger: zap.NewNop(), - converter: translation.NewMetricsConverter(zap.NewNop(), nil), + converter: c, } numDroppedTimeSeries, err := dpClient.pushMetricsData(context.Background(), tt.md) @@ -961,6 +974,9 @@ func BenchmarkExporterConsumeData(b *testing.B) { serverURL, err := url.Parse(server.URL) assert.NoError(b, err) + c, err := translation.NewMetricsConverter(zap.NewNop(), nil, nil) + require.NoError(b, err) + require.NotNil(b, c) dpClient := &sfxDPClient{ sfxClientBase: sfxClientBase{ ingestURL: serverURL, @@ -972,7 +988,7 @@ func BenchmarkExporterConsumeData(b *testing.B) { }}, }, logger: zap.NewNop(), - converter: translation.NewMetricsConverter(zap.NewNop(), nil), + converter: c, } for i := 0; i < b.N; i++ { diff --git a/exporter/signalfxexporter/factory.go b/exporter/signalfxexporter/factory.go index ca26a8ec4e44c..c98f65f069a7d 100644 --- a/exporter/signalfxexporter/factory.go +++ b/exporter/signalfxexporter/factory.go @@ -151,10 +151,6 @@ func setTranslationRules(cfg *Config) error { } cfg.TranslationRules = defaultRules } - if len(cfg.ExcludeMetrics) > 0 { - cfg.TranslationRules = append(cfg.TranslationRules, - translation.GetExcludeMetricsRule(cfg.ExcludeMetrics)) - } return nil } diff --git a/exporter/signalfxexporter/factory_test.go b/exporter/signalfxexporter/factory_test.go index 5dfd38a0d71f0..b5fed8bac63a2 100644 --- a/exporter/signalfxexporter/factory_test.go +++ b/exporter/signalfxexporter/factory_test.go @@ -37,6 +37,7 @@ import ( "google.golang.org/protobuf/types/known/timestamppb" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/signalfxexporter/translation" + "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/signalfxexporter/translation/dpfilters" ) func TestCreateDefaultConfig(t *testing.T) { @@ -237,27 +238,6 @@ func TestCreateMetricsExporterWithSpecifiedTranslaitonRules(t *testing.T) { } func TestCreateMetricsExporterWithExcludedMetrics(t *testing.T) { - config := &Config{ - ExporterSettings: configmodels.ExporterSettings{ - TypeVal: configmodels.Type(typeStr), - NameVal: typeStr, - }, - AccessToken: "testToken", - Realm: "us1", - ExcludeMetrics: []string{"metric1"}, - } - - te, err := createMetricsExporter(context.Background(), component.ExporterCreateParams{Logger: zap.NewNop()}, config) - require.NoError(t, err) - require.NotNil(t, te) - - assert.Equal(t, 1, len(config.TranslationRules)) - assert.Equal(t, translation.ActionDropMetrics, config.TranslationRules[0].Action) - assert.Equal(t, 1, len(config.TranslationRules[0].MetricNames)) - assert.True(t, config.TranslationRules[0].MetricNames["metric1"]) -} - -func TestCreateMetricsExporterWithDefinedRulesAndExcludedMetrics(t *testing.T) { config := &Config{ ExporterSettings: configmodels.ExporterSettings{ TypeVal: configmodels.Type(typeStr), @@ -265,26 +245,20 @@ func TestCreateMetricsExporterWithDefinedRulesAndExcludedMetrics(t *testing.T) { }, AccessToken: "testToken", Realm: "us1", - TranslationRules: []translation.Rule{ - { - Action: translation.ActionRenameDimensionKeys, - Mapping: map[string]string{ - "old_dimension": "new_dimension", - }, - }, - }, - ExcludeMetrics: []string{"metric1"}, + ExcludeMetrics: []dpfilters.MetricFilter{{ + MetricName: "metric1", + }}, } te, err := createMetricsExporter(context.Background(), component.ExporterCreateParams{Logger: zap.NewNop()}, config) require.NoError(t, err) require.NotNil(t, te) - assert.Equal(t, 2, len(config.TranslationRules)) - assert.Equal(t, translation.ActionRenameDimensionKeys, config.TranslationRules[0].Action) - assert.Equal(t, translation.ActionDropMetrics, config.TranslationRules[1].Action) - assert.Equal(t, 1, len(config.TranslationRules[1].MetricNames)) - assert.True(t, config.TranslationRules[1].MetricNames["metric1"]) + // TODO: Assert exclude metrics are correctly configured. + //assert.Equal(t, 1, len(config.TranslationRules)) + //assert.Equal(t, translation.ActionDropMetrics, config.TranslationRules[0].Action) + //require.Equal(t, 1, len(config.TranslationRules[0].MetricFilters)) + //assert.Equal(t, "metric1", config.TranslationRules[0].MetricFilters[0].MetricName) } func TestDefaultTranslationRules(t *testing.T) { @@ -295,7 +269,8 @@ func TestDefaultTranslationRules(t *testing.T) { require.NoError(t, err) data := testMetricsData() - c := translation.NewMetricsConverter(zap.NewNop(), tr) + c, err := translation.NewMetricsConverter(zap.NewNop(), tr, nil) + require.NoError(t, err) translated := c.MetricDataToSignalFxV2(data) require.NotNil(t, translated) diff --git a/exporter/signalfxexporter/testdata/config.yaml b/exporter/signalfxexporter/testdata/config.yaml index 05907a9370ac4..4ba4d9acc4210 100644 --- a/exporter/signalfxexporter/testdata/config.yaml +++ b/exporter/signalfxexporter/testdata/config.yaml @@ -26,9 +26,20 @@ exporters: access_token_passthrough: false send_compatible_metrics: true translation_rules: - - action: rename_dimension_keys - mapping: - k8s.cluster.name: kubernetes_cluster + - action: rename_dimension_keys + mapping: + k8s.cluster.name: kubernetes_cluster + exclude_metrics: + - metric_name: metric1 + - metric_names: [metric2, metric3] + - metric_name: metric4 + dimensions: + dimension_key: dimension_val + - metric_name: metric5 + dimensions: + dimension_key: [dimension_val1, dimension_val2] + + service: pipelines: diff --git a/exporter/signalfxexporter/translation/converter.go b/exporter/signalfxexporter/translation/converter.go index a557bd238533e..129415947289b 100644 --- a/exporter/signalfxexporter/translation/converter.go +++ b/exporter/signalfxexporter/translation/converter.go @@ -27,6 +27,7 @@ import ( tracetranslator "go.opentelemetry.io/collector/translator/trace" "go.uber.org/zap" + "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/signalfxexporter/translation/dpfilters" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/splunk" ) @@ -51,13 +52,18 @@ var ( type MetricsConverter struct { logger *zap.Logger metricTranslator *MetricTranslator + filterSet *dpfilters.FilterSet } // NewMetricsConverter creates a MetricsConverter from the passed in logger and // MetricTranslator. Pass in a nil MetricTranslator to not use translation // rules. -func NewMetricsConverter(logger *zap.Logger, t *MetricTranslator) *MetricsConverter { - return &MetricsConverter{logger: logger, metricTranslator: t} +func NewMetricsConverter(logger *zap.Logger, t *MetricTranslator, excludes []dpfilters.MetricFilter) (*MetricsConverter, error) { + fs, err := dpfilters.NewFilterSet(excludes) + if err != nil { + return nil, err + } + return &MetricsConverter{logger: logger, metricTranslator: t, filterSet: fs}, nil } // MetricDataToSignalFxV2 converts the passed in MetricsData to SFx datapoints, @@ -111,6 +117,10 @@ func (c *MetricsConverter) metricToSfxDataPoints(metric pdata.Metric, extraDimen dps = c.metricTranslator.TranslateDataPoints(c.logger, dps) } + dps = filterDataPoints(dps, func(dp *sfxpb.DataPoint) bool { + return c.filterSet.Matches(dp) + }) + return dps } diff --git a/exporter/signalfxexporter/translation/converter_test.go b/exporter/signalfxexporter/translation/converter_test.go index c16202f67c3b5..c38237f5488a6 100644 --- a/exporter/signalfxexporter/translation/converter_test.go +++ b/exporter/signalfxexporter/translation/converter_test.go @@ -16,6 +16,7 @@ package translation import ( "math" + "reflect" "sort" "testing" "time" @@ -27,6 +28,7 @@ import ( "go.opentelemetry.io/collector/translator/conventions" "go.uber.org/zap" + "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/signalfxexporter/translation/dpfilters" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/common/testing/util" ) @@ -88,6 +90,7 @@ func Test_MetricDataToSignalFxV2(t *testing.T) { tests := []struct { name string metricsDataFn func() pdata.ResourceMetrics + excludeMetrics []dpfilters.MetricFilter wantSfxDataPoints []*sfxpb.DataPoint }{ { @@ -483,10 +486,67 @@ func Test_MetricDataToSignalFxV2(t *testing.T) { }, wantSfxDataPoints: expectedFromIntHistogram("no_bucket_histo", tsMSecs, labelMap, histDPNoBuckets, false), }, + { + name: "with_exclude_metrics_filter", + metricsDataFn: func() pdata.ResourceMetrics { + out := pdata.NewResourceMetrics() + out.InstrumentationLibraryMetrics().Resize(1) + ilm := out.InstrumentationLibraryMetrics().At(0) + ilm.Metrics().Resize(4) + + { + m := ilm.Metrics().At(0) + m.SetName("gauge_double_with_dims") + m.SetDataType(pdata.MetricDataTypeDoubleGauge) + m.DoubleGauge().DataPoints().Append(doublePtWithLabels) + } + { + m := ilm.Metrics().At(1) + m.SetName("gauge_int_with_dims") + m.SetDataType(pdata.MetricDataTypeIntGauge) + m.IntGauge().DataPoints().Append(int64PtWithLabels) + } + { + m := ilm.Metrics().At(2) + m.SetName("cumulative_double_with_dims") + m.SetDataType(pdata.MetricDataTypeDoubleSum) + m.DoubleSum().SetIsMonotonic(true) + m.DoubleSum().DataPoints().Append(doublePtWithLabels) + } + { + m := ilm.Metrics().At(3) + m.SetName("cumulative_int_with_dims") + m.SetDataType(pdata.MetricDataTypeIntSum) + m.IntSum().SetIsMonotonic(true) + m.IntSum().DataPoints().Append(int64PtWithLabels) + } + + return out + }, + excludeMetrics: []dpfilters.MetricFilter{ + { + MetricNames: []string{"gauge_double_with_dims"}, + }, + { + MetricName: "cumulative_int_with_dims", + }, + { + MetricName: "gauge_int_with_dims", + Dimensions: map[string]interface{}{ + "k0": []interface{}{"v1"}, + }, + }, + }, + wantSfxDataPoints: []*sfxpb.DataPoint{ + int64SFxDataPoint("gauge_int_with_dims", tsMSecs, &sfxMetricTypeGauge, labelMap, int64Val), + doubleSFxDataPoint("cumulative_double_with_dims", tsMSecs, &sfxMetricTypeCumulativeCounter, labelMap, doubleVal), + }, + }, } - c := NewMetricsConverter(logger, nil) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + c, err := NewMetricsConverter(logger, nil, tt.excludeMetrics) + require.NoError(t, err) gotSfxDataPoints := c.MetricDataToSignalFxV2(tt.metricsDataFn()) // Sort SFx dimensions since they are built from maps and the order // of those is not deterministic. @@ -534,7 +594,8 @@ func TestMetricDataToSignalFxV2WithTranslation(t *testing.T) { }, }, } - c := NewMetricsConverter(zap.NewNop(), translator) + c, err := NewMetricsConverter(zap.NewNop(), translator, nil) + require.NoError(t, err) assert.EqualValues(t, expected, c.MetricDataToSignalFxV2(wrapMetric(md))) } @@ -686,3 +747,30 @@ func mergeDPs(dps ...[]*sfxpb.DataPoint) []*sfxpb.DataPoint { } return out } + +func TestNewMetricsConverter(t *testing.T) { + tests := []struct { + name string + excludes []dpfilters.MetricFilter + want *MetricsConverter + wantErr bool + }{ + { + name: "Error on creating filterSet", + excludes: []dpfilters.MetricFilter{{}}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := NewMetricsConverter(zap.NewNop(), nil, tt.excludes) + if (err != nil) != tt.wantErr { + t.Errorf("NewMetricsConverter() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("NewMetricsConverter() got = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/exporter/signalfxexporter/translation/defaultrules.go b/exporter/signalfxexporter/translation/defaultrules.go deleted file mode 100644 index b7231c34d78e7..0000000000000 --- a/exporter/signalfxexporter/translation/defaultrules.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2020, OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package translation - -// GetExcludeMetricsRule returns DropMetrics translation rule for provided metrics slice -func GetExcludeMetricsRule(excludeMetrics []string) Rule { - rule := Rule{ - Action: ActionDropMetrics, - MetricNames: map[string]bool{}, - } - for _, m := range excludeMetrics { - rule.MetricNames[m] = true - } - return rule -} diff --git a/exporter/signalfxexporter/translation/defaultrules_test.go b/exporter/signalfxexporter/translation/defaultrules_test.go deleted file mode 100644 index 5fe8f46a272b8..0000000000000 --- a/exporter/signalfxexporter/translation/defaultrules_test.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2020, OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package translation - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestGetExcludeMetricsRule(t *testing.T) { - rule := GetExcludeMetricsRule([]string{"m1", "m2"}) - assert.Equal(t, rule.Action, ActionDropMetrics) - assert.Equal(t, 2, len(rule.MetricNames)) - assert.False(t, rule.MetricNames["m0"]) - assert.True(t, rule.MetricNames["m1"]) -} diff --git a/exporter/signalfxexporter/translation/dpfilters/dimensions.go b/exporter/signalfxexporter/translation/dpfilters/dimensions.go index 6a5ab02be1da6..ea6736c07b78a 100644 --- a/exporter/signalfxexporter/translation/dpfilters/dimensions.go +++ b/exporter/signalfxexporter/translation/dpfilters/dimensions.go @@ -26,8 +26,7 @@ type dimensionsFilter struct { // newDimensionsFilter returns a filter that matches against a // sfxpb.Dimension slice. The filter will return true, if there's -// at least one matching dimension in the provided slice or if the -// slice if empty. +// at least one matching dimension in the provided slice. func newDimensionsFilter(m map[string][]string) (*dimensionsFilter, error) { filterMap := map[string]*stringFilter{} for k := range m { diff --git a/exporter/signalfxexporter/translation/translator.go b/exporter/signalfxexporter/translation/translator.go index a99b291ae28e4..e54d174b5fbcc 100644 --- a/exporter/signalfxexporter/translation/translator.go +++ b/exporter/signalfxexporter/translation/translator.go @@ -460,16 +460,9 @@ func (mp *MetricTranslator) TranslateDataPoints(logger *zap.Logger, sfxDataPoint processedDataPoints = append(otherDps, aggregatedDps...) case ActionDropMetrics: - resultSliceLen := 0 - for i, dp := range processedDataPoints { - if match := tr.MetricNames[dp.Metric]; !match { - if resultSliceLen < i { - processedDataPoints[resultSliceLen] = dp - } - resultSliceLen++ - } - } - processedDataPoints = processedDataPoints[:resultSliceLen] + processedDataPoints = filterDataPoints(processedDataPoints, func(dp *sfxpb.DataPoint) bool { + return tr.MetricNames[dp.Metric] + }) case ActionDeltaMetric: processedDataPoints = mp.deltaTranslator.translate(processedDataPoints, tr) @@ -479,6 +472,20 @@ func (mp *MetricTranslator) TranslateDataPoints(logger *zap.Logger, sfxDataPoint return processedDataPoints } +func filterDataPoints(dps []*sfxpb.DataPoint, matches func(*sfxpb.DataPoint) bool) []*sfxpb.DataPoint { + resultSliceLen := 0 + for i, dp := range dps { + if !matches(dp) { + if resultSliceLen < i { + dps[resultSliceLen] = dp + } + resultSliceLen++ + } + } + dps = dps[:resultSliceLen] + return dps +} + func calcNewMetricInputPairs(processedDataPoints []*sfxpb.DataPoint, tr Rule) [][2]*sfxpb.DataPoint { var operand1Pts, operand2Pts []*sfxpb.DataPoint for _, dp := range processedDataPoints { diff --git a/exporter/signalfxexporter/translation/translator_test.go b/exporter/signalfxexporter/translation/translator_test.go index 925d0e1c57837..72ac7bcc0957b 100644 --- a/exporter/signalfxexporter/translation/translator_test.go +++ b/exporter/signalfxexporter/translation/translator_test.go @@ -2586,7 +2586,8 @@ func testConverter(t *testing.T, mapping map[string]string) *MetricsConverter { tr, err := NewMetricTranslator(rules, 1) require.NoError(t, err) - c := NewMetricsConverter(zap.NewNop(), tr) + c, err := NewMetricsConverter(zap.NewNop(), tr, nil) + require.NoError(t, err) return c }