Repository: census-ecosystem/opencensus-go-exporter-stackdriver
Pull request #217 (2019-09-15 21:02:49)

Enforce consistent logic for CreateMetricDescriptor for stats and metrics

codecov-io: # [Codecov](https://codecov.io/gh/census-ecosystem/opencensus-go-exporter-stackdriver/pull/217?src=pr&el=h1) Report
> Merging [#217](https://codecov.io/gh/census-ecosystem/opencensus-go-exporter-stackdriver/pull/217?src=pr&el=desc) into [master](https://codecov.io/gh/census-ecosystem/opencensus-go-exporter-stackdriver/commit/e1ae7ede1bac90a934f5b3b98a55c0bb989ae1d5?src=pr&el=desc) will **decrease** coverage by `0.02%`.
> The diff coverage is `70%`.

[![Impacted file tree graph](https://codecov.io/gh/census-ecosystem/opencensus-go-exporter-stackdriver/pull/217/graphs/tree.svg?width=650&token=os6w8WyKNy&height=150&src=pr)](https://codecov.io/gh/census-ecosystem/opencensus-go-exporter-stackdriver/pull/217?src=pr&el=tree)

```diff
@@            Coverage Diff            @@
##           master    #217      +/-   ##
=========================================
- Coverage   72.63%   72.6%   -0.03%     
=========================================
  Files          15      15              
  Lines        1586    1548      -38     
=========================================
- Hits         1152    1124      -28     
+ Misses        355     350       -5     
+ Partials       79      74       -5
```


| [Impacted Files](https://codecov.io/gh/census-ecosystem/opencensus-go-exporter-stackdriver/pull/217?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [metrics.go](https://codecov.io/gh/census-ecosystem/opencensus-go-exporter-stackdriver/pull/217/diff?src=pr&el=tree#diff-bWV0cmljcy5nbw==) | `80.37% <62.5%> (ø)` | :arrow_up: |
| [stats.go](https://codecov.io/gh/census-ecosystem/opencensus-go-exporter-stackdriver/pull/217/diff?src=pr&el=tree#diff-c3RhdHMuZ28=) | `77.77% <75%> (+0.41%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/census-ecosystem/opencensus-go-exporter-stackdriver/pull/217?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/census-ecosystem/opencensus-go-exporter-stackdriver/pull/217?src=pr&el=footer). Last update [e1ae7ed...60e81d5](https://codecov.io/gh/census-ecosystem/opencensus-go-exporter-stackdriver/pull/217?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/metrics.go b/metrics.go
index d9cddc7..bba6aaa 100644
--- a/metrics.go
+++ b/metrics.go
@@ -190,6 +190,11 @@ func metricLabelsToTsLabels(defaults map[string]labelValue, labelKeys []metricda
 // createMetricDescriptorFromMetric creates a metric descriptor from the OpenCensus metric
 // and then creates it remotely using Stackdriver's API.
 func (se *statsExporter) createMetricDescriptorFromMetric(ctx context.Context, metric *metricdata.Metric) error {
+	// Skip create metric descriptor if configured
+	if se.o.SkipCMD {
+		return nil
+	}
+
 	se.metricMu.Lock()
 	defer se.metricMu.Unlock()
 
@@ -198,6 +203,11 @@ func (se *statsExporter) createMetricDescriptorFromMetric(ctx context.Context, m
 		return nil
 	}
 
+	if builtinMetric(se.metricTypeFromProto(name)) {
+		se.metricDescriptors[name] = true
+		return nil
+	}
+
 	// Otherwise, we encountered a cache-miss and
 	// should create the metric descriptor remotely.
 	inMD, err := se.metricToMpbMetricDescriptor(metric)
@@ -205,21 +215,13 @@ func (se *statsExporter) createMetricDescriptorFromMetric(ctx context.Context, m
 		return err
 	}
 
-	if builtinMetric(inMD.Type) {
-		se.metricDescriptors[name] = true
-	} else {
-		cmrdesc := &monitoringpb.CreateMetricDescriptorRequest{
-			Name:             fmt.Sprintf("projects/%s", se.o.ProjectID),
-			MetricDescriptor: inMD,
-		}
-		_, err = createMetricDescriptor(ctx, se.c, cmrdesc)
-		if err == nil {
-			// Now record the metric as having been created.
-			se.metricDescriptors[name] = true
-		}
+	if err = se.createMetricDescriptor(ctx, inMD); err != nil {
+		return err
 	}
 
-	return err
+	// Now record the metric as having been created.
+	se.metricDescriptors[name] = true
+	return nil
 }
 
 func (se *statsExporter) metricToMpbMetricDescriptor(metric *metricdata.Metric) (*googlemetricpb.MetricDescriptor, error) {
diff --git a/metrics_proto.go b/metrics_proto.go
index 04633d5..41f7bb8 100644
--- a/metrics_proto.go
+++ b/metrics_proto.go
@@ -70,14 +70,14 @@ func (se *statsExporter) PushMetricsProto(ctx context.Context, node *commonpb.No
 		if metric.GetMetricDescriptor().GetType() == metricspb.MetricDescriptor_SUMMARY {
 			summaryMtcs := se.convertSummaryMetrics(metric)
 			for _, summaryMtc := range summaryMtcs {
-				if err := se.createMetricDescriptor(ctx, summaryMtc); err != nil {
+				if err := se.protoCreateMetricDescriptor(ctx, summaryMtc); err != nil {
 					mb.recordDroppedTimeseries(len(summaryMtc.GetTimeseries()), err)
 					continue
 				}
 				se.protoMetricToTimeSeries(ctx, mappedRsc, summaryMtc, mb)
 			}
 		} else {
-			if err := se.createMetricDescriptor(ctx, metric); err != nil {
+			if err := se.protoCreateMetricDescriptor(ctx, metric); err != nil {
 				mb.recordDroppedTimeseries(len(metric.GetTimeseries()), err)
 				continue
 			}
@@ -301,7 +301,12 @@ func labelsPerTimeSeries(defaults map[string]labelValue, labelKeys []string, lab
 
 // createMetricDescriptor creates a metric descriptor from the OpenCensus proto metric
 // and then creates it remotely using Stackdriver's API.
-func (se *statsExporter) createMetricDescriptor(ctx context.Context, metric *metricspb.Metric) error {
+func (se *statsExporter) protoCreateMetricDescriptor(ctx context.Context, metric *metricspb.Metric) error {
+	// Skip create metric descriptor if configured
+	if se.o.SkipCMD {
+		return nil
+	}
+
 	se.protoMu.Lock()
 	defer se.protoMu.Unlock()
 
@@ -310,6 +315,11 @@ func (se *statsExporter) createMetricDescriptor(ctx context.Context, metric *met
 		return nil
 	}
 
+	if builtinMetric(se.metricTypeFromProto(name)) {
+		se.protoMetricDescriptors[name] = true
+		return nil
+	}
+
 	// Otherwise, we encountered a cache-miss and
 	// should create the metric descriptor remotely.
 	inMD, err := se.protoToMonitoringMetricDescriptor(metric, se.defaultLabels)
@@ -317,21 +327,12 @@ func (se *statsExporter) createMetricDescriptor(ctx context.Context, metric *met
 		return err
 	}
 
-	if builtinMetric(inMD.Type) {
-		se.protoMetricDescriptors[name] = true
-	} else {
-		cmrdesc := &monitoringpb.CreateMetricDescriptorRequest{
-			Name:             fmt.Sprintf("projects/%s", se.o.ProjectID),
-			MetricDescriptor: inMD,
-		}
-		_, err = createMetricDescriptor(ctx, se.c, cmrdesc)
-		if err == nil {
-			// Now record the metric as having been created.
-			se.protoMetricDescriptors[name] = true
-		}
+	if err = se.createMetricDescriptor(ctx, inMD); err != nil {
+		return err
 	}
 
-	return err
+	se.protoMetricDescriptors[name] = true
+	return nil
 }
 
 func (se *statsExporter) protoTimeSeriesToMonitoringPoints(ts *metricspb.TimeSeries, metricKind googlemetricpb.MetricDescriptor_MetricKind) (sptl []*monitoringpb.Point, err error) {
diff --git a/stackdriver.go b/stackdriver.go
index e7d86bc..c219e1b 100644
--- a/stackdriver.go
+++ b/stackdriver.go
@@ -238,6 +238,12 @@ type Options struct {
 	// If unset, context.Background() will be used.
 	Context context.Context
 
+	// SkipCMD enforces to skip all the CreateMetricDescriptor calls.
+	// These calls are important in order to configure the unit of the metrics,
+	// but in some cases all the exported metrics are builtin (unit is configured)
+	// or the unit is not important.
+	SkipCMD bool
+
 	// Timeout for all API calls. If not set, defaults to 5 seconds.
 	Timeout time.Duration
 
diff --git a/stats.go b/stats.go
index 6b05927..ff776b6 100644
--- a/stats.go
+++ b/stats.go
@@ -64,14 +64,11 @@ type statsExporter struct {
 	viewDataBundler *bundler.Bundler
 	metricsBundler  *bundler.Bundler
 
-	createdViewsMu sync.Mutex
-	createdViews   map[string]*metricpb.MetricDescriptor // Views already created remotely
-
 	protoMu                sync.Mutex
-	protoMetricDescriptors map[string]bool // Saves the metric descriptors that were already created remotely
+	protoMetricDescriptors map[string]bool // Metric descriptors that were already created remotely
 
 	metricMu          sync.Mutex
-	metricDescriptors map[string]bool // Saves the metric descriptors that were already created remotely
+	metricDescriptors map[string]bool // Metric descriptors that were already created remotely
 
 	c             *monitoring.MetricClient
 	defaultLabels map[string]labelValue
@@ -104,7 +101,6 @@ func newStatsExporter(o Options) (*statsExporter, error) {
 	e := &statsExporter{
 		c:                      client,
 		o:                      o,
-		createdViews:           make(map[string]*metricpb.MetricDescriptor),
 		protoMetricDescriptors: make(map[string]bool),
 		metricDescriptors:      make(map[string]bool),
 	}
@@ -222,7 +218,7 @@ func (e *statsExporter) uploadStats(vds []*view.Data) error {
 	defer span.End()
 
 	for _, vd := range vds {
-		if err := e.createMeasure(ctx, vd.View); err != nil {
+		if err := e.createMetricDescriptorFromView(ctx, vd.View); err != nil {
 			span.SetStatus(trace.Status{Code: 2, Message: err.Error()})
 			return err
 		}
@@ -331,21 +327,27 @@ func (e *statsExporter) viewToMetricDescriptor(ctx context.Context, v *view.View
 	return res, nil
 }
 
-// createMeasure creates a MetricDescriptor for the given view data in Stackdriver Monitoring.
+// createMetricDescriptorFromView creates a MetricDescriptor for the given view data in Stackdriver Monitoring.
 // An error will be returned if there is already a metric descriptor created with the same name
 // but it has a different aggregation or keys.
-func (e *statsExporter) createMeasure(ctx context.Context, v *view.View) error {
-	e.createdViewsMu.Lock()
-	defer e.createdViewsMu.Unlock()
+func (e *statsExporter) createMetricDescriptorFromView(ctx context.Context, v *view.View) error {
+	// Skip create metric descriptor if configured
+	if e.o.SkipCMD {
+		return nil
+	}
+
+	e.metricMu.Lock()
+	defer e.metricMu.Unlock()
 
 	viewName := v.Name
 
-	if md, ok := e.createdViews[viewName]; ok {
-		// [TODO:rghetia] Temporary fix for https://github.com/census-ecosystem/opencensus-go-exporter-stackdriver/issues/76#issuecomment-459459091
-		if builtinMetric(md.Type) {
-			return nil
-		}
-		return e.equalMeasureAggTagKeys(md, v.Measure, v.Aggregation, v.TagKeys)
+	if _, created := e.metricDescriptors[viewName]; created {
+		return nil
+	}
+
+	if builtinMetric(e.metricType(v)) {
+		e.metricDescriptors[viewName] = true
+		return nil
 	}
 
 	inMD, err := e.viewToMetricDescriptor(ctx, v)
@@ -353,26 +355,13 @@ func (e *statsExporter) createMeasure(ctx context.Context, v *view.View) error {
 		return err
 	}
 
-	var dmd *metric.MetricDescriptor
-	if builtinMetric(inMD.Type) {
-		gmrdesc := &monitoringpb.GetMetricDescriptorRequest{
-			Name: inMD.Name,
-		}
-		dmd, err = getMetricDescriptor(ctx, e.c, gmrdesc)
-	} else {
-		cmrdesc := &monitoringpb.CreateMetricDescriptorRequest{
-			Name:             fmt.Sprintf("projects/%s", e.o.ProjectID),
-			MetricDescriptor: inMD,
-		}
-		dmd, err = createMetricDescriptor(ctx, e.c, cmrdesc)
-	}
-	if err != nil {
+	if err = e.createMetricDescriptor(ctx, inMD); err != nil {
 		return err
 	}
 
 	// Now cache the metric descriptor
-	e.createdViews[viewName] = dmd
-	return err
+	e.metricDescriptors[viewName] = true
+	return nil
 }
 
 func (e *statsExporter) displayName(suffix string) string {
@@ -607,61 +596,20 @@ func newLabelDescriptors(defaults map[string]labelValue, keys []tag.Key) []*labe
 	return labelDescriptors
 }
 
-func (e *statsExporter) equalMeasureAggTagKeys(md *metricpb.MetricDescriptor, m stats.Measure, agg *view.Aggregation, keys []tag.Key) error {
-	var aggTypeMatch bool
-	switch md.ValueType {
-	case metricpb.MetricDescriptor_INT64:
-		if _, ok := m.(*stats.Int64Measure); !(ok || agg.Type == view.AggTypeCount) {
-			return fmt.Errorf("stackdriver metric descriptor was not created as int64")
-		}
-		aggTypeMatch = agg.Type == view.AggTypeCount || agg.Type == view.AggTypeSum || agg.Type == view.AggTypeLastValue
-	case metricpb.MetricDescriptor_DOUBLE:
-		if _, ok := m.(*stats.Float64Measure); !ok {
-			return fmt.Errorf("stackdriver metric descriptor was not created as double")
-		}
-		aggTypeMatch = agg.Type == view.AggTypeSum || agg.Type == view.AggTypeLastValue
-	case metricpb.MetricDescriptor_DISTRIBUTION:
-		aggTypeMatch = agg.Type == view.AggTypeDistribution
-	}
-
-	if !aggTypeMatch {
-		return fmt.Errorf("stackdriver metric descriptor was not created with aggregation type %T", agg.Type)
-	}
-
-	labels := make(map[string]struct{}, len(keys)+len(e.defaultLabels))
-	for _, k := range keys {
-		labels[sanitize(k.Name())] = struct{}{}
-	}
-	for k := range e.defaultLabels {
-		labels[sanitize(k)] = struct{}{}
-	}
-
-	for _, k := range md.Labels {
-		if _, ok := labels[k.Key]; !ok {
-			return fmt.Errorf("stackdriver metric descriptor %q was not created with label %q", md.Type, k)
-		}
-		delete(labels, k.Key)
-	}
-
-	if len(labels) > 0 {
-		extra := make([]string, 0, len(labels))
-		for k := range labels {
-			extra = append(extra, k)
-		}
-		return fmt.Errorf("stackdriver metric descriptor %q contains unexpected labels: %s", md.Type, strings.Join(extra, ", "))
+func (e *statsExporter) createMetricDescriptor(ctx context.Context, md *metric.MetricDescriptor) error {
+	cmrdesc := &monitoringpb.CreateMetricDescriptorRequest{
+		Name:             fmt.Sprintf("projects/%s", e.o.ProjectID),
+		MetricDescriptor: md,
 	}
 
-	return nil
+	_, err := createMetricDescriptor(ctx, e.c, cmrdesc)
+	return err
 }
 
 var createMetricDescriptor = func(ctx context.Context, c *monitoring.MetricClient, mdr *monitoringpb.CreateMetricDescriptorRequest) (*metric.MetricDescriptor, error) {
 	return c.CreateMetricDescriptor(ctx, mdr)
 }
 
-var getMetricDescriptor = func(ctx context.Context, c *monitoring.MetricClient, mdr *monitoringpb.GetMetricDescriptorRequest) (*metric.MetricDescriptor, error) {
-	return c.GetMetricDescriptor(ctx, mdr)
-}
-
 var createTimeSeries = func(ctx context.Context, c *monitoring.MetricClient, ts *monitoringpb.CreateTimeSeriesRequest) error {
 	return c.CreateTimeSeries(ctx, ts)
 }


Test patch:
diff --git a/stats_test.go b/stats_test.go
index c43fc3e..558d21e 100644
--- a/stats_test.go
+++ b/stats_test.go
@@ -30,7 +30,6 @@ import (
 	"go.opencensus.io/tag"
 	"google.golang.org/api/option"
 	"google.golang.org/genproto/googleapis/api/distribution"
-	"google.golang.org/genproto/googleapis/api/label"
 	"google.golang.org/genproto/googleapis/api/metric"
 	metricpb "google.golang.org/genproto/googleapis/api/metric"
 	monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres"
@@ -569,163 +568,7 @@ func TestExporter_makeReq_batching(t *testing.T) {
 	}
 }
 
-func TestEqualAggWindowTagKeys(t *testing.T) {
-	key1, _ := tag.NewKey("test-key-one")
-	key2, _ := tag.NewKey("test-key-two")
-	tests := []struct {
-		name    string
-		md      *metricpb.MetricDescriptor
-		m       stats.Measure
-		agg     *view.Aggregation
-		keys    []tag.Key
-		wantErr bool
-	}{
-		{
-			name: "count agg with in64 measure",
-			md: &metricpb.MetricDescriptor{
-				MetricKind: metricpb.MetricDescriptor_CUMULATIVE,
-				ValueType:  metricpb.MetricDescriptor_INT64,
-				Labels:     []*label.LabelDescriptor{{Key: opencensusTaskKey}},
-			},
-			m:       stats.Int64("name", "", ""),
-			agg:     view.Count(),
-			wantErr: false,
-		},
-		{
-			name: "count agg with double measure",
-			md: &metricpb.MetricDescriptor{
-				MetricKind: metricpb.MetricDescriptor_CUMULATIVE,
-				ValueType:  metricpb.MetricDescriptor_INT64,
-				Labels:     []*label.LabelDescriptor{{Key: opencensusTaskKey}},
-			},
-			m:       stats.Float64("name", "", ""),
-			agg:     view.Count(),
-			wantErr: false,
-		},
-		{
-			name: "sum agg double",
-			md: &metricpb.MetricDescriptor{
-				MetricKind: metricpb.MetricDescriptor_CUMULATIVE,
-				ValueType:  metricpb.MetricDescriptor_DOUBLE,
-				Labels:     []*label.LabelDescriptor{{Key: opencensusTaskKey}},
-			},
-			m:       stats.Float64("name", "", ""),
-			agg:     view.Sum(),
-			wantErr: false,
-		},
-		{
-			name: "sum agg int64",
-			md: &metricpb.MetricDescriptor{
-				MetricKind: metricpb.MetricDescriptor_CUMULATIVE,
-				ValueType:  metricpb.MetricDescriptor_INT64,
-				Labels:     []*label.LabelDescriptor{{Key: opencensusTaskKey}},
-			},
-			m:       stats.Int64("name", "", ""),
-			agg:     view.Sum(),
-			wantErr: false,
-		},
-		{
-			name: "last value agg double",
-			md: &metricpb.MetricDescriptor{
-				MetricKind: metricpb.MetricDescriptor_CUMULATIVE,
-				ValueType:  metricpb.MetricDescriptor_DOUBLE,
-				Labels:     []*label.LabelDescriptor{{Key: opencensusTaskKey}},
-			},
-			m:       stats.Float64("name", "", ""),
-			agg:     view.LastValue(),
-			wantErr: false,
-		},
-		{
-			name: "last value agg int64",
-			md: &metricpb.MetricDescriptor{
-				MetricKind: metricpb.MetricDescriptor_CUMULATIVE,
-				ValueType:  metricpb.MetricDescriptor_INT64,
-				Labels:     []*label.LabelDescriptor{{Key: opencensusTaskKey}},
-			},
-			m:       stats.Int64("name", "", ""),
-			agg:     view.LastValue(),
-			wantErr: false,
-		},
-		{
-			name: "distribution - mismatch",
-			md: &metricpb.MetricDescriptor{
-				MetricKind: metricpb.MetricDescriptor_CUMULATIVE,
-				ValueType:  metricpb.MetricDescriptor_DISTRIBUTION,
-				Labels:     []*label.LabelDescriptor{{Key: opencensusTaskKey}},
-			},
-			m:       stats.Int64("name", "", ""),
-			agg:     view.Count(),
-			wantErr: true,
-		},
-		{
-			name: "last value - measure mismatch",
-			md: &metricpb.MetricDescriptor{
-				MetricKind: metricpb.MetricDescriptor_CUMULATIVE,
-				ValueType:  metricpb.MetricDescriptor_INT64,
-				Labels:     []*label.LabelDescriptor{{Key: opencensusTaskKey}},
-			},
-			m:       stats.Float64("name", "", ""),
-			agg:     view.LastValue(),
-			wantErr: true,
-		},
-		{
-			name: "distribution agg with keys",
-			md: &metricpb.MetricDescriptor{
-				MetricKind: metricpb.MetricDescriptor_CUMULATIVE,
-				ValueType:  metricpb.MetricDescriptor_DISTRIBUTION,
-				Labels: []*label.LabelDescriptor{
-					{Key: "test_key_one"},
-					{Key: "test_key_two"},
-					{Key: opencensusTaskKey},
-				},
-			},
-			m:       stats.Int64("name", "", ""),
-			agg:     view.Distribution(),
-			keys:    []tag.Key{key1, key2},
-			wantErr: false,
-		},
-		{
-			name: "distribution agg with keys -- mismatch",
-			md: &metricpb.MetricDescriptor{
-				MetricKind: metricpb.MetricDescriptor_CUMULATIVE,
-				ValueType:  metricpb.MetricDescriptor_DISTRIBUTION,
-			},
-			m:       stats.Int64("name", "", ""),
-			agg:     view.Distribution(),
-			keys:    []tag.Key{key1, key2},
-			wantErr: true,
-		},
-		{
-			name: "count agg with pointers",
-			md: &metricpb.MetricDescriptor{
-				MetricKind: metricpb.MetricDescriptor_CUMULATIVE,
-				ValueType:  metricpb.MetricDescriptor_INT64,
-				Labels:     []*label.LabelDescriptor{{Key: opencensusTaskKey}},
-			},
-			m:       stats.Int64("name", "", ""),
-			agg:     view.Count(),
-			wantErr: false,
-		},
-	}
-	e, err := newStatsExporter(testOptions)
-	if err != nil {
-		t.Fatal(err)
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			err := e.equalMeasureAggTagKeys(tt.md, tt.m, tt.agg, tt.keys)
-			if err != nil && !tt.wantErr {
-				t.Errorf("equalAggTagKeys() = %q; want no error", err)
-			}
-			if err == nil && tt.wantErr {
-				t.Errorf("equalAggTagKeys() = %q; want error", err)
-			}
-
-		})
-	}
-}
-
-func TestExporter_createMeasure(t *testing.T) {
+func TestExporter_createMetricDescriptorFromView(t *testing.T) {
 	oldCreateMetricDescriptor := createMetricDescriptor
 
 	defer func() {
@@ -733,7 +576,7 @@ func TestExporter_createMeasure(t *testing.T) {
 	}()
 
 	key, _ := tag.NewKey("test-key-one")
-	m := stats.Float64("test-measure/TestExporter_createMeasure", "measure desc", stats.UnitMilliseconds)
+	m := stats.Float64("test-measure/TestExporter_createMetricDescriptorFromView", "measure desc", stats.UnitMilliseconds)
 
 	v := &view.View{
 		Name:        "test_view_sum",
@@ -814,23 +657,23 @@ func TestExporter_createMeasure(t *testing.T) {
 			}
 
 			ctx := context.Background()
-			if err := e.createMeasure(ctx, vd.View); err != nil {
-				t.Errorf("Exporter.createMeasure() error = %v", err)
+			if err := e.createMetricDescriptorFromView(ctx, vd.View); err != nil {
+				t.Errorf("Exporter.createMetricDescriptorFromView() error = %v", err)
 			}
-			if err := e.createMeasure(ctx, vd.View); err != nil {
-				t.Errorf("Exporter.createMeasure() error = %v", err)
+			if err := e.createMetricDescriptorFromView(ctx, vd.View); err != nil {
+				t.Errorf("Exporter.createMetricDescriptorFromView() error = %v", err)
 			}
 			if count := createCalls; count != 1 {
 				t.Errorf("createMetricDescriptor needs to be called for once; called %v times", count)
 			}
-			if count := len(e.createdViews); count != 1 {
-				t.Errorf("len(e.createdViews) = %v; want 1", count)
+			if count := len(e.metricDescriptors); count != 1 {
+				t.Errorf("len(e.metricDescriptors) = %v; want 1", count)
 			}
 		})
 	}
 }
 
-func TestExporter_createMeasure_CountAggregation(t *testing.T) {
+func TestExporter_createMetricDescriptorFromView_CountAggregation(t *testing.T) {
 	oldCreateMetricDescriptor := createMetricDescriptor
 
 	defer func() {
@@ -838,7 +681,7 @@ func TestExporter_createMeasure_CountAggregation(t *testing.T) {
 	}()
 
 	key, _ := tag.NewKey("test-key-one")
-	m := stats.Float64("test-measure/TestExporter_createMeasure", "measure desc", stats.UnitMilliseconds)
+	m := stats.Float64("test-measure/TestExporter_createMetricDescriptorFromView", "measure desc", stats.UnitMilliseconds)
 
 	v := &view.View{
 		Name:        "test_view_count",
@@ -852,8 +695,8 @@ func TestExporter_createMeasure_CountAggregation(t *testing.T) {
 	vd := newTestViewData(v, time.Now(), time.Now(), data, data)
 
 	e := &statsExporter{
-		createdViews: make(map[string]*metricpb.MetricDescriptor),
-		o:            Options{ProjectID: "test_project"},
+		metricDescriptors: make(map[string]bool),
+		o:                 Options{ProjectID: "test_project"},
 	}
 
 	createMetricDescriptor = func(ctx context.Context, c *monitoring.MetricClient, mdr *monitoringpb.CreateMetricDescriptorRequest) (*metric.MetricDescriptor, error) {
@@ -889,8 +732,8 @@ func TestExporter_createMeasure_CountAggregation(t *testing.T) {
 		}, nil
 	}
 	ctx := context.Background()
-	if err := e.createMeasure(ctx, vd.View); err != nil {
-		t.Errorf("Exporter.createMeasure() error = %v", err)
+	if err := e.createMetricDescriptorFromView(ctx, vd.View); err != nil {
+		t.Errorf("Exporter.createMetricDescriptorFromView() error = %v", err)
 	}
 }
 
@@ -1275,7 +1118,7 @@ func TestExporter_customContext(t *testing.T) {
 	v := &view.View{
 		Name:        "test_view_count",
 		Description: "view_description",
-		Measure:     stats.Float64("test-measure/TestExporter_createMeasure", "measure desc", stats.UnitMilliseconds),
+		Measure:     stats.Float64("test-measure/TestExporter_createMetricDescriptorFromView", "measure desc", stats.UnitMilliseconds),
 		Aggregation: view.Count(),
 	}
 
@@ -1285,8 +1128,8 @@ func TestExporter_customContext(t *testing.T) {
 	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
 	defer cancel()
 	e := &statsExporter{
-		createdViews: make(map[string]*metricpb.MetricDescriptor),
-		o:            Options{ProjectID: "test_project", Context: ctx},
+		metricDescriptors: make(map[string]bool),
+		o:                 Options{ProjectID: "test_project", Context: ctx},
 	}
 	if err := e.uploadStats([]*view.Data{vd}); err != nil {
 		t.Errorf("Exporter.uploadStats() error = %v", err)