Repository: GoogleCloudPlatform/opentelemetry-operations-go
Pull request #317 (2022-02-07 16:55:22)

Remove unimplemented resource mapper
We will add this back in before moving the upstream exporter to beta: https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/pull/307 is an example of how that could be done.  But for now, lets remove it and not rush the next implementation.


Patch:
diff --git a/exporter/collector/config.go b/exporter/collector/config.go
index 232e676..6f8b8bf 100644
--- a/exporter/collector/config.go
+++ b/exporter/collector/config.go
@@ -51,10 +51,9 @@ type TraceConfig struct {
 }
 
 type MetricConfig struct {
-	ClientConfig               ClientConfig      `mapstructure:",squash"`
-	Prefix                     string            `mapstructure:"prefix"`
-	ResourceMappings           []ResourceMapping `mapstructure:"resource_mappings"`
-	SkipCreateMetricDescriptor bool              `mapstructure:"skip_create_descriptor"`
+	ClientConfig               ClientConfig `mapstructure:",squash"`
+	Prefix                     string       `mapstructure:"prefix"`
+	SkipCreateMetricDescriptor bool         `mapstructure:"skip_create_descriptor"`
 	// If a metric belongs to one of these domains it does not get a prefix.
 	KnownDomains []string `mapstructure:"known_domains"`
 
@@ -88,22 +87,6 @@ type ResourceFilter struct {
 	Prefix string `mapstructure:"prefix"`
 }
 
-// ResourceMapping defines mapping of resources from source (OpenCensus) to target (Google Cloud).
-type ResourceMapping struct {
-	SourceType string `mapstructure:"source_type"`
-	TargetType string `mapstructure:"target_type"`
-
-	LabelMappings []LabelMapping `mapstructure:"label_mappings"`
-}
-
-type LabelMapping struct {
-	SourceKey string `mapstructure:"source_key"`
-	TargetKey string `mapstructure:"target_key"`
-	// Optional flag signals whether we can proceed with transformation if a label is missing in the resource.
-	// When required label is missing, we fallback to default resource mapping.
-	Optional bool `mapstructure:"optional"`
-}
-
 // Known metric domains. Note: This is now configurable for advanced usages.
 var domains = []string{"googleapis.com", "kubernetes.io", "istio.io", "knative.dev"}
 
diff --git a/exporter/collector/go.mod b/exporter/collector/go.mod
index f3eb622..5ac2d2d 100644
--- a/exporter/collector/go.mod
+++ b/exporter/collector/go.mod
@@ -3,7 +3,6 @@ module github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/colle
 go 1.16
 
 require (
-	contrib.go.opencensus.io/exporter/stackdriver v0.13.10
 	github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace v1.0.0
 	github.com/census-instrumentation/opencensus-proto v0.3.0
 	github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/opencensus v0.40.0
@@ -21,7 +20,7 @@ require (
 
 require (
 	cloud.google.com/go/monitoring v1.1.0
-	github.com/aws/aws-sdk-go v1.42.14 // indirect
+	cloud.google.com/go/trace v1.0.0 // indirect
 	github.com/google/go-cmp v0.5.6
 	go.uber.org/zap v1.19.1
 	golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
diff --git a/exporter/collector/go.sum b/exporter/collector/go.sum
index 72209b5..d1d5b7f 100644
--- a/exporter/collector/go.sum
+++ b/exporter/collector/go.sum
@@ -51,8 +51,6 @@ cloud.google.com/go/trace v1.0.0 h1:laKx2y7IWMjguCe5zZx6n7qLtREk4kyE69SXVC0VSN8=
 cloud.google.com/go/trace v1.0.0/go.mod h1:4iErSByzxkyHWzzlAj63/Gmjz0NH1ASqhJguHpGcr6A=
 code.cloudfoundry.org/bytefmt v0.0.0-20190710193110-1eb035ffe2b6/go.mod h1:wN/zk7mhREp/oviagqUXY3EwuHhWyOvAdsn5Y4CzOrc=
 contrib.go.opencensus.io/exporter/prometheus v0.4.0/go.mod h1:o7cosnyfuPVK0tB8q0QmaQNhGnptITnPQB+z1+qeFB0=
-contrib.go.opencensus.io/exporter/stackdriver v0.13.10 h1:a9+GZPUe+ONKUwULjlEOucMMG0qfSCCenlji0Nhqbys=
-contrib.go.opencensus.io/exporter/stackdriver v0.13.10/go.mod h1:I5htMbyta491eUxufwwZPQdcKvvgzMB4O9ni41YnIM8=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
@@ -69,9 +67,6 @@ github.com/antonmedv/expr v1.9.0/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmH
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
-github.com/aws/aws-sdk-go v1.42.14 h1:Eqwjl/cwRY9z0TTU4RGpiElWo9oPzG+Y8r5Thu6Ug5A=
-github.com/aws/aws-sdk-go v1.42.14/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
 github.com/aws/aws-sdk-go-v2 v1.9.2/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
 github.com/aws/aws-sdk-go-v2/config v1.8.3/go.mod h1:4AEiLtAb8kLs7vgw2ZV3p2VZ1+hBavOc84hqxVNpCyw=
 github.com/aws/aws-sdk-go-v2/credentials v1.4.3/go.mod h1:FNNC6nQZQUuyhq5aE5c7ata8o9e4ECGmS4lAXC7o1mQ=
@@ -291,9 +286,7 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
 github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
-github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
 github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
 github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
 github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
@@ -622,7 +615,6 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -691,7 +683,6 @@ golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 h1:2B5p2L5IfGiD7+b9BOoRMC6DgObAVZV+Fsp050NqXik=
 golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -801,7 +792,6 @@ google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqiv
 google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
 google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
 google.golang.org/api v0.58.0/go.mod h1:cAbP2FsxoGVNwtgNAmmn3y5G1TWAiVYRmg4yku3lv+E=
-google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU=
 google.golang.org/api v0.60.0 h1:eq/zs5WPH4J9undYM9IP1O7dSr7Yh8Y0GtSCpzGzIUk=
 google.golang.org/api v0.60.0/go.mod h1:d7rl65NZAkEQ90JFzqBjcRq1TVeG5ZoGV3sSpEnnVb4=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
@@ -874,7 +864,6 @@ google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEc
 google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
 google.golang.org/genproto v0.0.0-20210921142501-181ce0d877f6/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
 google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
 google.golang.org/genproto v0.0.0-20211018162055-cf77aa76bad2/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
 google.golang.org/genproto v0.0.0-20211021150943-2b146023228c h1:FqrtZMB5Wr+/RecOM3uPJNPfWR8Upb5hAPnt7PU6i4k=
 google.golang.org/genproto v0.0.0-20211021150943-2b146023228c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
diff --git a/exporter/collector/metricsexporter.go b/exporter/collector/metricsexporter.go
index c326bde..6e6f3fc 100644
--- a/exporter/collector/metricsexporter.go
+++ b/exporter/collector/metricsexporter.go
@@ -78,6 +78,7 @@ type MetricsExporter struct {
 // metricMapper is the part that transforms metrics. Separate from MetricsExporter since it has
 // all pure functions.
 type metricMapper struct {
+	obs selfObservability
 	cfg Config
 }
 
@@ -150,12 +151,12 @@ func NewGoogleCloudMetricsExporter(
 	if err != nil {
 		return nil, err
 	}
-
+	obs := selfObservability{log: log}
 	mExp := &MetricsExporter{
 		cfg:    cfg,
 		client: client,
-		obs:    selfObservability{log: log},
-		mapper: metricMapper{cfg},
+		obs:    obs,
+		mapper: metricMapper{obs, cfg},
 		// We create a buffered channel for metric descriptors.
 		// MetricDescritpors are asychronously sent and optimistic.
 		// We only get Unit/Description/Display name from them, so it's ok
@@ -382,7 +383,7 @@ func (m *metricMapper) metricToTimeSeries(
 		}
 	// TODO: add cases for other metric data types
 	default:
-		// TODO: log unsupported metric
+		m.obs.log.Error("Unsupported metric data type", zap.Any("data_type", metric.DataType()))
 	}
 
 	return timeSeries
diff --git a/exporter/collector/resource_mapper.go b/exporter/collector/resource_mapper.go
deleted file mode 100644
index 052f6ae..0000000
--- a/exporter/collector/resource_mapper.go
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2021 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 collector
-
-import (
-	"contrib.go.opencensus.io/exporter/stackdriver"
-	"go.opencensus.io/resource"
-	monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres"
-)
-
-type resourceMapper struct {
-	mappings []ResourceMapping
-}
-
-func (mr *resourceMapper) mapResource(res *resource.Resource) *monitoredrespb.MonitoredResource {
-	for _, mapping := range mr.mappings {
-		if res.Type != mapping.SourceType {
-			continue
-		}
-
-		result := &monitoredrespb.MonitoredResource{
-			Type: mapping.TargetType,
-		}
-
-		labels, ok := transformLabels(mapping.LabelMappings, res.Labels)
-
-		if !ok {
-			// Skip mapping, fallback to default handling
-			continue
-		}
-
-		result.Labels = labels
-		return result
-	}
-
-	// cloud.zone was renamed to cloud.availability_zone in the semantic conventions.
-	// Accept either, for backwards compatibility.
-	availabilityZone, ok := res.Labels["cloud.availability_zone"]
-	if ok {
-		res.Labels["cloud.zone"] = availabilityZone
-	}
-
-	// Keep original behavior by default
-	return stackdriver.DefaultMapResource(res)
-}
-
-// transformLabels transforms labels according to the configured mappings.
-// Returns true if all required labels in match are found.
-func transformLabels(labelMappings []LabelMapping, input map[string]string) (map[string]string, bool) {
-	output := make(map[string]string, len(input))
-	// Convert matching labels
-	for _, labelMapping := range labelMappings {
-		if v, ok := input[labelMapping.SourceKey]; ok {
-			output[labelMapping.TargetKey] = v
-		} else if !labelMapping.Optional {
-			// Required label is missing
-			return nil, false
-		}
-	}
-	return output, true
-}


Test patch:
diff --git a/exporter/collector/integrationtest/config/config_test.go b/exporter/collector/integrationtest/config/config_test.go
index f22a9fe..9762fdb 100644
--- a/exporter/collector/integrationtest/config/config_test.go
+++ b/exporter/collector/integrationtest/config/config_test.go
@@ -75,28 +75,6 @@ func TestLoadConfig(t *testing.T) {
 					InstrumentationLibraryLabels:     true,
 					CreateMetricDescriptorBufferSize: 10,
 					ServiceResourceLabels:            true,
-					ResourceMappings: []collector.ResourceMapping{
-						{
-							SourceType: "source.resource1",
-							TargetType: "target-resource1",
-							LabelMappings: []collector.LabelMapping{
-								{
-									SourceKey: "contrib.opencensus.io/exporter/googlecloud/project_id",
-									TargetKey: "project_id",
-									Optional:  true,
-								},
-								{
-									SourceKey: "source.label1",
-									TargetKey: "target_label_1",
-									Optional:  false,
-								},
-							},
-						},
-						{
-							SourceType: "source.resource2",
-							TargetType: "target-resource2",
-						},
-					},
 				},
 			},
 		})
diff --git a/exporter/collector/integrationtest/go.sum b/exporter/collector/integrationtest/go.sum
index 215fbe1..e1a1620 100644
--- a/exporter/collector/integrationtest/go.sum
+++ b/exporter/collector/integrationtest/go.sum
@@ -69,9 +69,8 @@ github.com/antonmedv/expr v1.9.0/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmH
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/aws/aws-sdk-go v1.37.0 h1:GzFnhOIsrGyQ69s7VgqtrG2BG8v7X7vwB3Xpbd/DBBk=
 github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
-github.com/aws/aws-sdk-go v1.42.14 h1:Eqwjl/cwRY9z0TTU4RGpiElWo9oPzG+Y8r5Thu6Ug5A=
-github.com/aws/aws-sdk-go v1.42.14/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
 github.com/aws/aws-sdk-go-v2 v1.9.2/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
 github.com/aws/aws-sdk-go-v2/config v1.8.3/go.mod h1:4AEiLtAb8kLs7vgw2ZV3p2VZ1+hBavOc84hqxVNpCyw=
 github.com/aws/aws-sdk-go-v2/credentials v1.4.3/go.mod h1:FNNC6nQZQUuyhq5aE5c7ata8o9e4ECGmS4lAXC7o1mQ=
diff --git a/exporter/collector/integrationtest/testdata/config.yaml b/exporter/collector/integrationtest/testdata/config.yaml
index 2f0509a..80d9aaf 100644
--- a/exporter/collector/integrationtest/testdata/config.yaml
+++ b/exporter/collector/integrationtest/testdata/config.yaml
@@ -15,17 +15,6 @@ exporters:
     metric:
       endpoint: test-metric-endpoint
       use_insecure: true
-      resource_mappings:
-        - source_type: source.resource1
-          target_type: target-resource1
-          label_mappings:
-            - source_key: contrib.opencensus.io/exporter/googlecloud/project_id
-              target_key: project_id
-              optional: true
-            - source_key: source.label1
-              target_key: target_label_1
-        - source_type: source.resource2
-          target_type: target-resource2
       prefix: prefix
       skip_create_descriptor: true
 
diff --git a/exporter/collector/metricsexporter_test.go b/exporter/collector/metricsexporter_test.go
index db0f0d3..a6c57b1 100644
--- a/exporter/collector/metricsexporter_test.go
+++ b/exporter/collector/metricsexporter_test.go
@@ -23,6 +23,7 @@ import (
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	"go.opentelemetry.io/collector/model/pdata"
+	"go.uber.org/zap"
 	"google.golang.org/genproto/googleapis/api/label"
 	metricpb "google.golang.org/genproto/googleapis/api/metric"
 	monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres"
@@ -35,11 +36,16 @@ var (
 	start = time.Unix(0, 0)
 )
 
+func newTestMetricMapper() metricMapper {
+	obs := selfObservability{log: zap.NewNop()}
+	return metricMapper{obs, DefaultConfig()}
+}
+
 func TestMetricToTimeSeries(t *testing.T) {
 	mr := &monitoredrespb.MonitoredResource{}
 
 	t.Run("Sum", func(t *testing.T) {
-		mapper := metricMapper{cfg: Config{}}
+		mapper := newTestMetricMapper()
 		metric := pdata.NewMetric()
 		metric.SetDataType(pdata.MetricDataTypeSum)
 		sum := metric.Sum()
@@ -60,7 +66,7 @@ func TestMetricToTimeSeries(t *testing.T) {
 	})
 
 	t.Run("Gauge", func(t *testing.T) {
-		mapper := metricMapper{cfg: Config{}}
+		mapper := newTestMetricMapper()
 		metric := pdata.NewMetric()
 		metric.SetDataType(pdata.MetricDataTypeGauge)
 		gauge := metric.Gauge()
@@ -98,9 +104,8 @@ func TestMergeLabels(t *testing.T) {
 }
 
 func TestHistogramPointToTimeSeries(t *testing.T) {
-	cfg := DefaultConfig()
-	cfg.ProjectID = "myproject"
-	mapper := metricMapper{cfg: cfg}
+	mapper := newTestMetricMapper()
+	mapper.cfg.ProjectID = "myproject"
 	mr := &monitoredrespb.MonitoredResource{}
 	metric := pdata.NewMetric()
 	metric.SetName("myhist")
@@ -162,9 +167,8 @@ func TestHistogramPointToTimeSeries(t *testing.T) {
 }
 
 func TestExponentialHistogramPointToTimeSeries(t *testing.T) {
-	cfg := DefaultConfig()
-	cfg.ProjectID = "myproject"
-	mapper := metricMapper{cfg: cfg}
+	mapper := newTestMetricMapper()
+	mapper.cfg.ProjectID = "myproject"
 	mr := &monitoredrespb.MonitoredResource{}
 	metric := pdata.NewMetric()
 	metric.SetName("myexphist")
@@ -230,7 +234,7 @@ func TestExponentialHistogramPointToTimeSeries(t *testing.T) {
 }
 
 func TestExemplarNoAttachements(t *testing.T) {
-	mapper := metricMapper{cfg: Config{}}
+	mapper := newTestMetricMapper()
 	exemplar := pdata.NewExemplar()
 	exemplar.SetTimestamp(pdata.NewTimestampFromTime(start))
 	exemplar.SetDoubleVal(1)
@@ -242,7 +246,7 @@ func TestExemplarNoAttachements(t *testing.T) {
 }
 
 func TestExemplarOnlyDroppedLabels(t *testing.T) {
-	mapper := metricMapper{cfg: Config{}}
+	mapper := newTestMetricMapper()
 	exemplar := pdata.NewExemplar()
 	exemplar.SetTimestamp(pdata.NewTimestampFromTime(start))
 	exemplar.SetDoubleVal(1)
@@ -260,9 +264,8 @@ func TestExemplarOnlyDroppedLabels(t *testing.T) {
 }
 
 func TestExemplarOnlyTraceId(t *testing.T) {
-	mapper := metricMapper{cfg: Config{
-		ProjectID: "p",
-	}}
+	mapper := newTestMetricMapper()
+	mapper.cfg.ProjectID = "p"
 	exemplar := pdata.NewExemplar()
 	exemplar.SetTimestamp(pdata.NewTimestampFromTime(start))
 	exemplar.SetDoubleVal(1)
@@ -285,7 +288,7 @@ func TestExemplarOnlyTraceId(t *testing.T) {
 }
 
 func TestSumPointToTimeSeries(t *testing.T) {
-	mapper := metricMapper{cfg: DefaultConfig()}
+	mapper := newTestMetricMapper()
 	mr := &monitoredrespb.MonitoredResource{}
 
 	newCase := func() (pdata.Metric, pdata.Sum, pdata.NumberDataPoint) {
@@ -393,7 +396,7 @@ func TestSumPointToTimeSeries(t *testing.T) {
 }
 
 func TestGaugePointToTimeSeries(t *testing.T) {
-	mapper := metricMapper{cfg: DefaultConfig()}
+	mapper := newTestMetricMapper()
 	mr := &monitoredrespb.MonitoredResource{}
 
 	newCase := func() (pdata.Metric, pdata.Gauge, pdata.NumberDataPoint) {
@@ -449,7 +452,7 @@ func TestGaugePointToTimeSeries(t *testing.T) {
 }
 
 func TestSummaryPointToTimeSeries(t *testing.T) {
-	mapper := metricMapper{cfg: DefaultConfig()}
+	mapper := newTestMetricMapper()
 	mr := &monitoredrespb.MonitoredResource{}
 
 	metric := pdata.NewMetric()
@@ -521,7 +524,7 @@ func TestSummaryPointToTimeSeries(t *testing.T) {
 }
 
 func TestMetricNameToType(t *testing.T) {
-	mapper := metricMapper{cfg: DefaultConfig()}
+	mapper := newTestMetricMapper()
 	assert.Equal(
 		t,
 		mapper.metricNameToType("foo"),
@@ -944,7 +947,7 @@ func TestMetricDescriptorMapping(t *testing.T) {
 	}
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
-			mapper := metricMapper{cfg: DefaultConfig()}
+			mapper := newTestMetricMapper()
 			metric := test.metricCreator()
 			md := mapper.metricDescriptor(metric, test.extraLabels)
 			diff := cmp.Diff(
@@ -1001,12 +1004,11 @@ func TestKnownDomains(t *testing.T) {
 	}
 	for _, test := range tests {
 		t.Run(fmt.Sprintf("%v to %v", test.name, test.metricType), func(t *testing.T) {
-			config := DefaultConfig()
-			config.MetricConfig.Prefix = "prefix"
+			mapper := newTestMetricMapper()
 			if len(test.knownDomains) > 0 {
-				config.MetricConfig.KnownDomains = test.knownDomains
+				mapper.cfg.MetricConfig.KnownDomains = test.knownDomains
 			}
-			mapper := metricMapper{cfg: config}
+			mapper.cfg.MetricConfig.Prefix = "prefix"
 			assert.Equal(t, test.metricType, mapper.metricNameToType(test.name))
 		})
 	}
@@ -1044,9 +1046,8 @@ func TestInstrumentationLibraryToLabels(t *testing.T) {
 
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
-			config := DefaultConfig()
-			config.MetricConfig = test.metricConfig
-			m := metricMapper{cfg: config}
+			m := newTestMetricMapper()
+			m.cfg.MetricConfig = test.metricConfig
 
 			out := m.instrumentationLibraryToLabels(test.instrumentationLibrary)
 
diff --git a/exporter/collector/resource_mapper_test.go b/exporter/collector/resource_mapper_test.go
deleted file mode 100644
index 4955720..0000000
--- a/exporter/collector/resource_mapper_test.go
+++ /dev/null
@@ -1,189 +0,0 @@
-// Copyright 2021 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 collector
-
-import (
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-	"go.opencensus.io/resource"
-	"google.golang.org/genproto/googleapis/api/monitoredres"
-)
-
-func TestResourceMapper(t *testing.T) {
-	rm := resourceMapper{
-		mappings: []ResourceMapping{
-			{
-				SourceType: "source.resource1",
-				TargetType: "target_resource_1",
-				LabelMappings: []LabelMapping{
-					{
-						SourceKey: "contrib.opencensus.io/exporter/stackdriver/project_id",
-						TargetKey: "project_id",
-						Optional:  true,
-					},
-					{
-						SourceKey: "renamedLabel",
-						TargetKey: "target_label",
-					},
-				},
-			},
-			{
-				SourceType: "source.resource2",
-				TargetType: "target_resource_2",
-			},
-		},
-	}
-
-	tests := []struct {
-		name           string
-		sourceResource *resource.Resource
-		wantResource   *monitoredres.MonitoredResource
-	}{
-		{
-			name: "Converted resource with all matching labels",
-			sourceResource: &resource.Resource{
-				Type: "source.resource1",
-				Labels: map[string]string{
-					"renamedLabel": "value1",
-					"contrib.opencensus.io/exporter/stackdriver/project_id": "123",
-					"unknown": "value1",
-				},
-			},
-			wantResource: &monitoredres.MonitoredResource{
-				// Resource type transformed
-				Type: "target_resource_1",
-				Labels: map[string]string{
-					// Both labels transformed
-					"project_id":   "123",
-					"target_label": "value1",
-				},
-			},
-		},
-		{
-			name: "Converted resource with optional label missing",
-			sourceResource: &resource.Resource{
-				Type: "source.resource1",
-				Labels: map[string]string{
-					"renamedLabel": "value1",
-					"unknown":      "value1",
-				},
-			},
-			wantResource: &monitoredres.MonitoredResource{
-				// Resource type transformed
-				Type: "target_resource_1",
-				Labels: map[string]string{
-					// Required label transformed
-					"target_label": "value1",
-				},
-			},
-		},
-		{
-			name: "Converted resource with required label missing",
-			sourceResource: &resource.Resource{
-				Type: "source.resource1",
-				Labels: map[string]string{
-					"contrib.opencensus.io/exporter/stackdriver/project_id": "123",
-				},
-			},
-			// Resource with missing required labels should be converted via default implementation
-			wantResource: &monitoredres.MonitoredResource{
-				// Resource type transformed
-				Type: "global",
-				Labels: map[string]string{
-					// project_id is transformed by default function
-					"project_id": "123",
-				},
-			},
-		},
-		{
-			name: "Resource without matching labels",
-			sourceResource: &resource.Resource{
-				Type: "source.resource2",
-				Labels: map[string]string{
-					"someLabel": "value1",
-					"contrib.opencensus.io/exporter/stackdriver/project_id": "123",
-				},
-			},
-			// Resource without matching labels should drop all labels
-			wantResource: &monitoredres.MonitoredResource{
-				// Resource type transformed
-				Type: "target_resource_2",
-				// All labels are dropped
-				Labels: map[string]string{},
-			},
-		},
-		{
-			name: "Resource without matching type",
-			sourceResource: &resource.Resource{
-				Type: "source.resource3",
-				Labels: map[string]string{
-					"source.label1": "value1", // unknown label is dropped
-					"contrib.opencensus.io/exporter/stackdriver/project_id":             "123",
-					"cloud.availability_zone":                                           "zone1",
-					"contrib.opencensus.io/exporter/stackdriver/generic_task/namespace": "ns1",
-					"contrib.opencensus.io/exporter/stackdriver/generic_task/job":       "job1",
-					"contrib.opencensus.io/exporter/stackdriver/generic_task/task_id":   "task1",
-				},
-			},
-			// Resource without matching config should be converted via default implementation
-			wantResource: &monitoredres.MonitoredResource{
-				Type: "generic_task",
-				// All labels are transformed by default function
-				Labels: map[string]string{
-					"project_id": "123",
-					"location":   "zone1",
-					"namespace":  "ns1",
-					"job":        "job1",
-					"task_id":    "task1",
-				},
-			},
-		},
-		{
-			name: "Handle cloud.zone for backcompat",
-			sourceResource: &resource.Resource{
-				Type: "source.resource3",
-				Labels: map[string]string{
-					"contrib.opencensus.io/exporter/stackdriver/project_id": "123",
-					"cloud.zone": "zone1",
-					"contrib.opencensus.io/exporter/stackdriver/generic_task/namespace": "ns1",
-					"contrib.opencensus.io/exporter/stackdriver/generic_task/job":       "job1",
-					"contrib.opencensus.io/exporter/stackdriver/generic_task/task_id":   "task1",
-				},
-			},
-			wantResource: &monitoredres.MonitoredResource{
-				Type: "generic_task",
-				// All labels are transformed by default function
-				Labels: map[string]string{
-					"project_id": "123",
-					"location":   "zone1",
-					"namespace":  "ns1",
-					"job":        "job1",
-					"task_id":    "task1",
-				},
-			},
-		},
-	}
-
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			result := rm.mapResource(tt.sourceResource)
-			require.NotNil(t, result)
-			assert.Equal(t, tt.wantResource.Type, result.Type)
-			assert.EqualValues(t, tt.wantResource.Labels, result.Labels)
-		})
-	}
-}