Repository: census-instrumentation/opencensus-go
Pull request #208 (2017-12-01 19:24:02)

Support sum and mean for Stackdriver exporter
Fix https://github.com/census-instrumentation/opencensus-go/issues/180


Patch:
diff --git a/.travis.yml b/.travis.yml
index 9e535d8..e969610 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,6 +2,7 @@ language: go
 
 go:
   - 1.8.x
+  - 1.9.x
 
 go_import_path: go.opencensus.io
 
diff --git a/exporter/stats/stackdriver/stackdriver.go b/exporter/stats/stackdriver/stackdriver.go
index 9585d5d..7262504 100644
--- a/exporter/stats/stackdriver/stackdriver.go
+++ b/exporter/stats/stackdriver/stackdriver.go
@@ -242,6 +242,10 @@ func (e *Exporter) createMeasure(ctx context.Context, vd *stats.ViewData) error
 	switch agg.(type) {
 	case stats.CountAggregation:
 		valueType = metricpb.MetricDescriptor_INT64
+	case stats.SumAggregation:
+		valueType = metricpb.MetricDescriptor_DOUBLE
+	case stats.MeanAggregation:
+		valueType = metricpb.MetricDescriptor_DOUBLE
 	case stats.DistributionAggregation:
 		valueType = metricpb.MetricDescriptor_DISTRIBUTION
 	default:
@@ -299,6 +303,14 @@ func newTypedValue(view *stats.View, r *stats.Row) *monitoringpb.TypedValue {
 		return &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{
 			Int64Value: int64(*v),
 		}}
+	case *stats.SumData:
+		return &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{
+			DoubleValue: float64(*v),
+		}}
+	case *stats.MeanData:
+		return &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{
+			DoubleValue: v.Mean,
+		}}
 	case *stats.DistributionData:
 		bounds := view.Aggregation().(stats.DistributionAggregation)
 		return &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DistributionValue{
diff --git a/exporter/trace/stackdriver/stackdriver.go b/exporter/trace/stackdriver/stackdriver.go
index d0e8a80..dfd92be 100644
--- a/exporter/trace/stackdriver/stackdriver.go
+++ b/exporter/trace/stackdriver/stackdriver.go
@@ -30,6 +30,7 @@
 package stackdriver
 
 import (
+	"context"
 	"fmt"
 	"log"
 	"sync"
@@ -39,7 +40,6 @@ import (
 
 	tracingclient "cloud.google.com/go/trace/apiv2"
 	"go.opencensus.io/trace"
-	"golang.org/x/net/context"
 	"google.golang.org/api/option"
 	"google.golang.org/api/support/bundler"
 	tracepb "google.golang.org/genproto/googleapis/devtools/cloudtrace/v2"
diff --git a/plugin/grpc/grpcstats/client_metrics.go b/plugin/grpc/grpcstats/client_metrics.go
index b1690cb..9545248 100644
--- a/plugin/grpc/grpcstats/client_metrics.go
+++ b/plugin/grpc/grpcstats/client_metrics.go
@@ -97,51 +97,53 @@ func defaultClientMeasures() {
 }
 
 func defaultClientViews() {
-	RPCClientErrorCountView, _ = stats.NewView("grpc.io/client/error_count/distribution_cumulative", "RPC Errors", []tag.Key{keyOpStatus, keyService, keyMethod}, RPCClientErrorCount, aggCount, windowCumulative)
+	// Use the Java implementation as a reference at
+	// https://github.com/census-instrumentation/opencensus-java/blob/2b464864e3dd3f80e8e4c9dc72fccc225444a939/contrib/grpc_metrics/src/main/java/io/opencensus/contrib/grpc/metrics/RpcViewConstants.java#L113-L658
+	RPCClientErrorCountView, _ = stats.NewView(" rpc.io/client/error_count/cumulative", "RPC Errors", []tag.Key{keyOpStatus, keyService, keyMethod}, RPCClientErrorCount, aggMean, windowCumulative)
 	clientViews = append(clientViews, RPCClientErrorCountView)
-	RPCClientRoundTripLatencyView, _ = stats.NewView("grpc.io/client/roundtrip_latency/distribution_cumulative", "Latency in msecs", []tag.Key{keyService, keyMethod}, RPCClientRoundTripLatency, aggDistMillis, windowCumulative)
+	RPCClientRoundTripLatencyView, _ = stats.NewView("grpc.io/client/roundtrip_latency/cumulative", "Latency in msecs", []tag.Key{keyService, keyMethod}, RPCClientRoundTripLatency, aggDistMillis, windowCumulative)
 	clientViews = append(clientViews, RPCClientRoundTripLatencyView)
-	RPCClientRequestBytesView, _ = stats.NewView("grpc.io/client/request_bytes/distribution_cumulative", "Request bytes", []tag.Key{keyService, keyMethod}, RPCClientRequestBytes, aggDistBytes, windowCumulative)
+	RPCClientRequestBytesView, _ = stats.NewView("grpc.io/client/request_bytes/cumulative", "Request bytes", []tag.Key{keyService, keyMethod}, RPCClientRequestBytes, aggDistBytes, windowCumulative)
 	clientViews = append(clientViews, RPCClientRequestBytesView)
-	RPCClientResponseBytesView, _ = stats.NewView("grpc.io/client/response_bytes/distribution_cumulative", "Response bytes", []tag.Key{keyService, keyMethod}, RPCClientResponseBytes, aggDistBytes, windowCumulative)
+	RPCClientResponseBytesView, _ = stats.NewView("grpc.io/client/response_bytes/cumulative", "Response bytes", []tag.Key{keyService, keyMethod}, RPCClientResponseBytes, aggDistBytes, windowCumulative)
 	clientViews = append(clientViews, RPCClientResponseBytesView)
-	RPCClientRequestCountView, _ = stats.NewView("grpc.io/client/request_count/distribution_cumulative", "Count of request messages per client RPC", []tag.Key{keyService, keyMethod}, RPCClientRequestCount, aggDistCounts, windowCumulative)
+	RPCClientRequestCountView, _ = stats.NewView("grpc.io/client/request_count/cumulative", "Count of request messages per client RPC", []tag.Key{keyService, keyMethod}, RPCClientRequestCount, aggDistCounts, windowCumulative)
 	clientViews = append(clientViews, RPCClientRequestCountView)
-	RPCClientResponseCountView, _ = stats.NewView("grpc.io/client/response_count/distribution_cumulative", "Count of response messages per client RPC", []tag.Key{keyService, keyMethod}, RPCClientResponseCount, aggDistCounts, windowCumulative)
+	RPCClientResponseCountView, _ = stats.NewView("grpc.io/client/response_count/cumulative", "Count of response messages per client RPC", []tag.Key{keyService, keyMethod}, RPCClientResponseCount, aggDistCounts, windowCumulative)
 	clientViews = append(clientViews, RPCClientResponseCountView)
 
-	RPCClientRoundTripLatencyMinuteView, _ = stats.NewView("grpc.io/client/roundtrip_latency/minute_interval", "Minute stats for latency in msecs", []tag.Key{keyService, keyMethod}, RPCClientRoundTripLatency, aggDistMillis, windowSlidingMinute)
+	RPCClientRoundTripLatencyMinuteView, _ = stats.NewView("grpc.io/client/roundtrip_latency/minute", "Minute stats for latency in msecs", []tag.Key{keyService, keyMethod}, RPCClientRoundTripLatency, aggMean, windowSlidingMinute)
 	clientViews = append(clientViews, RPCClientRoundTripLatencyMinuteView)
-	RPCClientRequestBytesMinuteView, _ = stats.NewView("grpc.io/client/request_bytes/minute_interval", "Minute stats for request size in bytes", []tag.Key{keyService, keyMethod}, RPCClientRequestBytes, aggCount, windowSlidingMinute)
+	RPCClientRequestBytesMinuteView, _ = stats.NewView("grpc.io/client/request_bytes/minute", "Minute stats for request size in bytes", []tag.Key{keyService, keyMethod}, RPCClientRequestBytes, aggMean, windowSlidingMinute)
 	clientViews = append(clientViews, RPCClientRequestBytesMinuteView)
-	RPCClientResponseBytesMinuteView, _ = stats.NewView("grpc.io/client/response_bytes/minute_interval", "Minute stats for response size in bytes", []tag.Key{keyService, keyMethod}, RPCClientResponseBytes, aggCount, windowSlidingMinute)
+	RPCClientResponseBytesMinuteView, _ = stats.NewView("grpc.io/client/response_bytes/minute", "Minute stats for response size in bytes", []tag.Key{keyService, keyMethod}, RPCClientResponseBytes, aggMean, windowSlidingMinute)
 	clientViews = append(clientViews, RPCClientResponseBytesMinuteView)
-	RPCClientErrorCountMinuteView, _ = stats.NewView("grpc.io/client/error_count/minute_interval", "Minute stats for rpc errors", []tag.Key{keyService, keyMethod}, RPCClientErrorCount, aggCount, windowSlidingMinute)
+	RPCClientErrorCountMinuteView, _ = stats.NewView("grpc.io/client/error_count/minute", "Minute stats for rpc errors", []tag.Key{keyService, keyMethod}, RPCClientErrorCount, aggMean, windowSlidingMinute)
 	clientViews = append(clientViews, RPCClientErrorCountMinuteView)
-	RPCClientStartedCountMinuteView, _ = stats.NewView("grpc.io/client/started_count/minute_interval", "Minute stats on the number of client RPCs started", []tag.Key{keyService, keyMethod}, RPCClientStartedCount, aggCount, windowSlidingMinute)
+	RPCClientStartedCountMinuteView, _ = stats.NewView("grpc.io/client/started_count/minute", "Minute stats on the number of client RPCs started", []tag.Key{keyService, keyMethod}, RPCClientStartedCount, aggMean, windowSlidingMinute)
 	clientViews = append(clientViews, RPCClientStartedCountMinuteView)
-	RPCClientFinishedCountMinuteView, _ = stats.NewView("grpc.io/client/finished_count/minute_interval", "Minute stats on the number of client RPCs finished", []tag.Key{keyService, keyMethod}, RPCClientFinishedCount, aggCount, windowSlidingMinute)
+	RPCClientFinishedCountMinuteView, _ = stats.NewView("grpc.io/client/finished_count/minute", "Minute stats on the number of client RPCs finished", []tag.Key{keyService, keyMethod}, RPCClientFinishedCount, aggMean, windowSlidingMinute)
 	clientViews = append(clientViews, RPCClientFinishedCountMinuteView)
-	RPCClientRequestCountMinuteView, _ = stats.NewView("grpc.io/client/request_count/minute_interval", "Minute stats on the count of request messages per client RPC", []tag.Key{keyService, keyMethod}, RPCClientRequestCount, aggCount, windowSlidingMinute)
+	RPCClientRequestCountMinuteView, _ = stats.NewView("grpc.io/client/request_count/minute", "Minute stats on the count of request messages per client RPC", []tag.Key{keyService, keyMethod}, RPCClientRequestCount, aggMean, windowSlidingMinute)
 	clientViews = append(clientViews, RPCClientRequestCountMinuteView)
-	RPCClientResponseCountMinuteView, _ = stats.NewView("grpc.io/client/response_count/minute_interval", "Minute stats on the count of response messages per client RPC", []tag.Key{keyService, keyMethod}, RPCClientResponseCount, aggCount, windowSlidingMinute)
+	RPCClientResponseCountMinuteView, _ = stats.NewView("grpc.io/client/response_count/minute", "Minute stats on the count of response messages per client RPC", []tag.Key{keyService, keyMethod}, RPCClientResponseCount, aggMean, windowSlidingMinute)
 	clientViews = append(clientViews, RPCClientResponseCountMinuteView)
 
-	RPCClientRoundTripLatencyHourView, _ = stats.NewView("grpc.io/client/roundtrip_latency/hour_interval", "Hour stats for latency in msecs", []tag.Key{keyService, keyMethod}, RPCClientRoundTripLatency, aggDistMillis, windowSlidingHour)
+	RPCClientRoundTripLatencyHourView, _ = stats.NewView("grpc.io/client/roundtrip_latency/hour", "Hour stats for latency in msecs", []tag.Key{keyService, keyMethod}, RPCClientRoundTripLatency, aggMean, windowSlidingHour)
 	clientViews = append(clientViews, RPCClientRoundTripLatencyHourView)
-	RPCClientRequestBytesHourView, _ = stats.NewView("grpc.io/client/request_bytes/hour_interval", "Hour stats for request size in bytes", []tag.Key{keyService, keyMethod}, RPCClientRequestBytes, aggCount, windowSlidingHour)
+	RPCClientRequestBytesHourView, _ = stats.NewView("grpc.io/client/request_bytes/hour", "Hour stats for request size in bytes", []tag.Key{keyService, keyMethod}, RPCClientRequestBytes, aggMean, windowSlidingHour)
 	clientViews = append(clientViews, RPCClientRequestBytesHourView)
-	RPCClientResponseBytesHourView, _ = stats.NewView("grpc.io/client/response_bytes/hour_interval", "Hour stats for response size in bytes", []tag.Key{keyService, keyMethod}, RPCClientResponseBytes, aggCount, windowSlidingHour)
+	RPCClientResponseBytesHourView, _ = stats.NewView("grpc.io/client/response_bytes/hour", "Hour stats for response size in bytes", []tag.Key{keyService, keyMethod}, RPCClientResponseBytes, aggMean, windowSlidingHour)
 	clientViews = append(clientViews, RPCClientResponseBytesHourView)
-	RPCClientErrorCountHourView, _ = stats.NewView("grpc.io/client/error_count/hour_interval", "Hour stats for rpc errors", []tag.Key{keyService, keyMethod}, RPCClientErrorCount, aggCount, windowSlidingHour)
+	RPCClientErrorCountHourView, _ = stats.NewView("grpc.io/client/error_count/hour", "Hour stats for rpc errors", []tag.Key{keyService, keyMethod}, RPCClientErrorCount, aggMean, windowSlidingHour)
 	clientViews = append(clientViews, RPCClientErrorCountHourView)
-	RPCClientStartedCountHourView, _ = stats.NewView("grpc.io/client/started_count/hour_interval", "Hour stats on the number of client RPCs started", []tag.Key{keyService, keyMethod}, RPCClientStartedCount, aggCount, windowSlidingHour)
+	RPCClientStartedCountHourView, _ = stats.NewView("grpc.io/client/started_count/hour", "Hour stats on the number of client RPCs started", []tag.Key{keyService, keyMethod}, RPCClientStartedCount, aggMean, windowSlidingHour)
 	clientViews = append(clientViews, RPCClientStartedCountHourView)
-	RPCClientFinishedCountHourView, _ = stats.NewView("grpc.io/client/finished_count/hour_interval", "Hour stats on the number of client RPCs finished", []tag.Key{keyService, keyMethod}, RPCClientFinishedCount, aggCount, windowSlidingHour)
+	RPCClientFinishedCountHourView, _ = stats.NewView("grpc.io/client/finished_count/hour", "Hour stats on the number of client RPCs finished", []tag.Key{keyService, keyMethod}, RPCClientFinishedCount, aggMean, windowSlidingHour)
 	clientViews = append(clientViews, RPCClientFinishedCountHourView)
-	RPCClientRequestCountHourView, _ = stats.NewView("grpc.io/client/request_count/hour_interval", "Hour stats on the count of request messages per client RPC", []tag.Key{keyService, keyMethod}, RPCClientRequestCount, aggCount, windowSlidingHour)
+	RPCClientRequestCountHourView, _ = stats.NewView("grpc.io/client/request_count/hour", "Hour stats on the count of request messages per client RPC", []tag.Key{keyService, keyMethod}, RPCClientRequestCount, aggMean, windowSlidingHour)
 	clientViews = append(clientViews, RPCClientRequestCountHourView)
-	RPCClientResponseCountHourView, _ = stats.NewView("grpc.io/client/response_count/hour_interval", "Hour stats on the count of response messages per client RPC", []tag.Key{keyService, keyMethod}, RPCClientResponseCount, aggCount, windowSlidingHour)
+	RPCClientResponseCountHourView, _ = stats.NewView("grpc.io/client/response_count/hour", "Hour stats on the count of response messages per client RPC", []tag.Key{keyService, keyMethod}, RPCClientResponseCount, aggMean, windowSlidingHour)
 	clientViews = append(clientViews, RPCClientResponseCountHourView)
 	// TODO(jbd): Register it when constructing the stats handler.
 }
diff --git a/plugin/grpc/grpcstats/grpcstats.go b/plugin/grpc/grpcstats/grpcstats.go
index 56feb27..e9224fe 100644
--- a/plugin/grpc/grpcstats/grpcstats.go
+++ b/plugin/grpc/grpcstats/grpcstats.go
@@ -56,6 +56,7 @@ var (
 	rpcCountBucketBoundaries  = []float64{0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536}
 
 	aggCount      = istats.CountAggregation{}
+	aggMean       = istats.MeanAggregation{}
 	aggDistBytes  = istats.DistributionAggregation(rpcBytesBucketBoundaries)
 	aggDistMillis = istats.DistributionAggregation(rpcMillisBucketBoundaries)
 	aggDistCounts = istats.DistributionAggregation(rpcCountBucketBoundaries)
diff --git a/plugin/grpc/grpcstats/server_metrics.go b/plugin/grpc/grpcstats/server_metrics.go
index 247623f..6f17f61 100644
--- a/plugin/grpc/grpcstats/server_metrics.go
+++ b/plugin/grpc/grpcstats/server_metrics.go
@@ -97,51 +97,51 @@ func defaultServerMeasures() {
 }
 
 func defaultServerserverViews() {
-	RPCServerErrorCountView, _ = stats.NewView("grpc.io/server/error_count/distribution_cumulative", "RPC Errors", []tag.Key{keyMethod, keyOpStatus, keyService}, RPCServerErrorCount, aggCount, windowCumulative)
+	RPCServerErrorCountView, _ = stats.NewView("grpc.io/server/error_count/cumulative", "RPC Errors", []tag.Key{keyMethod, keyOpStatus, keyService}, RPCServerErrorCount, aggCount, windowCumulative)
 	serverViews = append(serverViews, RPCServerErrorCountView)
-	RPCServerServerElapsedTimeView, _ = stats.NewView("grpc.io/server/server_elapsed_time/distribution_cumulative", "Server elapsed time in msecs", []tag.Key{keyService, keyMethod}, RPCServerServerElapsedTime, aggDistMillis, windowCumulative)
+	RPCServerServerElapsedTimeView, _ = stats.NewView("grpc.io/server/server_elapsed_time/cumulative", "Server elapsed time in msecs", []tag.Key{keyService, keyMethod}, RPCServerServerElapsedTime, aggDistMillis, windowCumulative)
 	serverViews = append(serverViews, RPCServerServerElapsedTimeView)
-	RPCServerRequestBytesView, _ = stats.NewView("grpc.io/server/request_bytes/distribution_cumulative", "Request bytes", []tag.Key{keyService, keyMethod}, RPCServerRequestBytes, aggDistBytes, windowCumulative)
+	RPCServerRequestBytesView, _ = stats.NewView("grpc.io/server/request_bytes/cumulative", "Request bytes", []tag.Key{keyService, keyMethod}, RPCServerRequestBytes, aggDistBytes, windowCumulative)
 	serverViews = append(serverViews, RPCServerRequestBytesView)
-	RPCServerResponseBytesView, _ = stats.NewView("grpc.io/server/response_bytes/distribution_cumulative", "Response bytes", []tag.Key{keyService, keyMethod}, RPCServerResponseBytes, aggDistBytes, windowCumulative)
+	RPCServerResponseBytesView, _ = stats.NewView("grpc.io/server/response_bytes/cumulative", "Response bytes", []tag.Key{keyService, keyMethod}, RPCServerResponseBytes, aggDistBytes, windowCumulative)
 	serverViews = append(serverViews, RPCServerResponseBytesView)
-	RPCServerRequestCountView, _ = stats.NewView("grpc.io/server/request_count/distribution_cumulative", "Count of request messages per server RPC", []tag.Key{keyService, keyMethod}, RPCServerRequestCount, aggDistCounts, windowCumulative)
+	RPCServerRequestCountView, _ = stats.NewView("grpc.io/server/request_count/cumulative", "Count of request messages per server RPC", []tag.Key{keyService, keyMethod}, RPCServerRequestCount, aggDistCounts, windowCumulative)
 	serverViews = append(serverViews, RPCServerRequestCountView)
-	RPCServerResponseCountView, _ = stats.NewView("grpc.io/server/response_count/distribution_cumulative", "Count of response messages per server RPC", []tag.Key{keyService, keyMethod}, RPCServerResponseCount, aggDistCounts, windowCumulative)
+	RPCServerResponseCountView, _ = stats.NewView("grpc.io/server/response_count/cumulative", "Count of response messages per server RPC", []tag.Key{keyService, keyMethod}, RPCServerResponseCount, aggDistCounts, windowCumulative)
 	serverViews = append(serverViews, RPCServerResponseCountView)
 
-	RPCServerServerElapsedTimeMinuteView, _ = stats.NewView("grpc.io/server/server_elapsed_time/minute_interval", "Minute stats for server elapsed time in msecs", []tag.Key{keyService, keyMethod}, RPCServerServerElapsedTime, aggDistMillis, windowSlidingMinute)
+	RPCServerServerElapsedTimeMinuteView, _ = stats.NewView("grpc.io/server/server_elapsed_time/minute", "Minute stats for server elapsed time in msecs", []tag.Key{keyService, keyMethod}, RPCServerServerElapsedTime, aggDistMillis, windowSlidingMinute)
 	serverViews = append(serverViews, RPCServerServerElapsedTimeMinuteView)
-	RPCServerRequestBytesMinuteView, _ = stats.NewView("grpc.io/server/request_bytes/minute_interval", "Minute stats for request size in bytes", []tag.Key{keyService, keyMethod}, RPCServerRequestBytes, aggCount, windowSlidingMinute)
+	RPCServerRequestBytesMinuteView, _ = stats.NewView("grpc.io/server/request_bytes/minute", "Minute stats for request size in bytes", []tag.Key{keyService, keyMethod}, RPCServerRequestBytes, aggCount, windowSlidingMinute)
 	serverViews = append(serverViews, RPCServerRequestBytesMinuteView)
-	RPCServerResponseBytesMinuteView, _ = stats.NewView("grpc.io/server/response_bytes/minute_interval", "Minute stats for response size in bytes", []tag.Key{keyService, keyMethod}, RPCServerResponseBytes, aggCount, windowSlidingMinute)
+	RPCServerResponseBytesMinuteView, _ = stats.NewView("grpc.io/server/response_bytes/minute", "Minute stats for response size in bytes", []tag.Key{keyService, keyMethod}, RPCServerResponseBytes, aggCount, windowSlidingMinute)
 	serverViews = append(serverViews, RPCServerResponseBytesMinuteView)
-	RPCServerErrorCountMinuteView, _ = stats.NewView("grpc.io/server/error_count/minute_interval", "Minute stats for rpc errors", []tag.Key{keyService, keyMethod}, RPCServerErrorCount, aggCount, windowSlidingMinute)
+	RPCServerErrorCountMinuteView, _ = stats.NewView("grpc.io/server/error_count/minute", "Minute stats for rpc errors", []tag.Key{keyService, keyMethod}, RPCServerErrorCount, aggCount, windowSlidingMinute)
 	serverViews = append(serverViews, RPCServerErrorCountMinuteView)
-	RPCServerStartedCountMinuteView, _ = stats.NewView("grpc.io/server/started_count/minute_interval", "Minute stats on the number of server RPCs started", []tag.Key{keyService, keyMethod}, RPCServerStartedCount, aggCount, windowSlidingMinute)
+	RPCServerStartedCountMinuteView, _ = stats.NewView("grpc.io/server/started_count/minute", "Minute stats on the number of server RPCs started", []tag.Key{keyService, keyMethod}, RPCServerStartedCount, aggCount, windowSlidingMinute)
 	serverViews = append(serverViews, RPCServerStartedCountMinuteView)
-	RPCServerFinishedCountMinuteView, _ = stats.NewView("grpc.io/server/finished_count/minute_interval", "Minute stats on the number of server RPCs finished", []tag.Key{keyService, keyMethod}, RPCServerFinishedCount, aggCount, windowSlidingMinute)
+	RPCServerFinishedCountMinuteView, _ = stats.NewView("grpc.io/server/finished_count/minute", "Minute stats on the number of server RPCs finished", []tag.Key{keyService, keyMethod}, RPCServerFinishedCount, aggCount, windowSlidingMinute)
 	serverViews = append(serverViews, RPCServerFinishedCountMinuteView)
-	RPCServerRequestCountMinuteView, _ = stats.NewView("grpc.io/server/request_count/minute_interval", "Minute stats on the count of request messages per server RPC", []tag.Key{keyService, keyMethod}, RPCServerRequestCount, aggCount, windowSlidingMinute)
+	RPCServerRequestCountMinuteView, _ = stats.NewView("grpc.io/server/request_count/minute", "Minute stats on the count of request messages per server RPC", []tag.Key{keyService, keyMethod}, RPCServerRequestCount, aggCount, windowSlidingMinute)
 	serverViews = append(serverViews, RPCServerRequestCountMinuteView)
-	RPCServerResponseCountMinuteView, _ = stats.NewView("grpc.io/server/response_count/minute_interval", "Minute stats on the count of response messages per server RPC", []tag.Key{keyService, keyMethod}, RPCServerResponseCount, aggCount, windowSlidingMinute)
+	RPCServerResponseCountMinuteView, _ = stats.NewView("grpc.io/server/response_count/minute", "Minute stats on the count of response messages per server RPC", []tag.Key{keyService, keyMethod}, RPCServerResponseCount, aggCount, windowSlidingMinute)
 	serverViews = append(serverViews, RPCServerResponseCountMinuteView)
 
-	RPCServerServerElapsedTimeHourView, _ = stats.NewView("grpc.io/server/server_elapsed_time/hour_interval", "Hour stats for server elapsed time in msecs", []tag.Key{keyService, keyMethod}, RPCServerServerElapsedTime, aggDistMillis, windowSlidingHour)
+	RPCServerServerElapsedTimeHourView, _ = stats.NewView("grpc.io/server/server_elapsed_time/hour", "Hour stats for server elapsed time in msecs", []tag.Key{keyService, keyMethod}, RPCServerServerElapsedTime, aggDistMillis, windowSlidingHour)
 	serverViews = append(serverViews, RPCServerServerElapsedTimeHourView)
-	RPCServerRequestBytesHourView, _ = stats.NewView("grpc.io/server/request_bytes/hour_interval", "Hour stats for request size in bytes", []tag.Key{keyService, keyMethod}, RPCServerRequestBytes, aggCount, windowSlidingHour)
+	RPCServerRequestBytesHourView, _ = stats.NewView("grpc.io/server/request_bytes/hour", "Hour stats for request size in bytes", []tag.Key{keyService, keyMethod}, RPCServerRequestBytes, aggCount, windowSlidingHour)
 	serverViews = append(serverViews, RPCServerRequestBytesHourView)
-	RPCServerResponseBytesHourView, _ = stats.NewView("grpc.io/server/response_bytes/hour_interval", "Hour stats for response size in bytes", []tag.Key{keyService, keyMethod}, RPCServerResponseBytes, aggCount, windowSlidingHour)
+	RPCServerResponseBytesHourView, _ = stats.NewView("grpc.io/server/response_bytes/hour", "Hour stats for response size in bytes", []tag.Key{keyService, keyMethod}, RPCServerResponseBytes, aggCount, windowSlidingHour)
 	serverViews = append(serverViews, RPCServerResponseBytesHourView)
-	RPCServerErrorCountHourView, _ = stats.NewView("grpc.io/server/error_count/hour_interval", "Hour stats for rpc errors", []tag.Key{keyService, keyMethod}, RPCServerErrorCount, aggCount, windowSlidingHour)
+	RPCServerErrorCountHourView, _ = stats.NewView("grpc.io/server/error_count/hour", "Hour stats for rpc errors", []tag.Key{keyService, keyMethod}, RPCServerErrorCount, aggCount, windowSlidingHour)
 	serverViews = append(serverViews, RPCServerErrorCountHourView)
-	RPCServerStartedCountHourView, _ = stats.NewView("grpc.io/server/started_count/hour_interval", "Hour stats on the number of server RPCs started", []tag.Key{keyService, keyMethod}, RPCServerStartedCount, aggCount, windowSlidingHour)
+	RPCServerStartedCountHourView, _ = stats.NewView("grpc.io/server/started_count/hour", "Hour stats on the number of server RPCs started", []tag.Key{keyService, keyMethod}, RPCServerStartedCount, aggCount, windowSlidingHour)
 	serverViews = append(serverViews, RPCServerStartedCountHourView)
-	RPCServerFinishedCountHourView, _ = stats.NewView("grpc.io/server/finished_count/hour_interval", "Hour stats on the number of server RPCs finished", []tag.Key{keyService, keyMethod}, RPCServerFinishedCount, aggCount, windowSlidingHour)
+	RPCServerFinishedCountHourView, _ = stats.NewView("grpc.io/server/finished_count/hour", "Hour stats on the number of server RPCs finished", []tag.Key{keyService, keyMethod}, RPCServerFinishedCount, aggCount, windowSlidingHour)
 	serverViews = append(serverViews, RPCServerFinishedCountHourView)
-	RPCServerRequestCountHourView, _ = stats.NewView("grpc.io/server/request_count/hour_interval", "Hour stats on the count of request messages per server RPC", []tag.Key{keyService, keyMethod}, RPCServerRequestCount, aggCount, windowSlidingHour)
+	RPCServerRequestCountHourView, _ = stats.NewView("grpc.io/server/request_count/hour", "Hour stats on the count of request messages per server RPC", []tag.Key{keyService, keyMethod}, RPCServerRequestCount, aggCount, windowSlidingHour)
 	serverViews = append(serverViews, RPCServerRequestCountHourView)
-	RPCServerResponseCountHourView, _ = stats.NewView("grpc.io/server/response_count/hour_interval", "Hour stats on the count of response messages per server RPC", []tag.Key{keyService, keyMethod}, RPCServerResponseCount, aggCount, windowSlidingHour)
+	RPCServerResponseCountHourView, _ = stats.NewView("grpc.io/server/response_count/hour", "Hour stats on the count of response messages per server RPC", []tag.Key{keyService, keyMethod}, RPCServerResponseCount, aggCount, windowSlidingHour)
 	serverViews = append(serverViews, RPCServerResponseCountHourView)
 }
 
diff --git a/tag/context.go b/tag/context.go
index 8add6d8..9fe32e4 100644
--- a/tag/context.go
+++ b/tag/context.go
@@ -15,7 +15,7 @@
 
 package tag
 
-import "golang.org/x/net/context"
+import "context"
 
 // FromContext returns the tag map stored in the context.
 func FromContext(ctx context.Context) *Map {
diff --git a/tag/key.go b/tag/key.go
index b53ab77..da9f342 100644
--- a/tag/key.go
+++ b/tag/key.go
@@ -15,8 +15,7 @@
 
 package tag
 
-// Key represents a tag key. Keys with the same name will return
-// true when compared with the == operator.
+// Key represents a tag key.
 type Key struct {
 	id   uint16
 	name string
diff --git a/tag/map.go b/tag/map.go
index 06b10ef..a07d230 100644
--- a/tag/map.go
+++ b/tag/map.go
@@ -17,10 +17,9 @@ package tag
 
 import (
 	"bytes"
+	"context"
 	"fmt"
 	"sort"
-
-	"golang.org/x/net/context"
 )
 
 // Tag is a key value pair that can be propagated on wire.


Test patch:
diff --git a/exporter/stats/stackdriver/stackdriver_test.go b/exporter/stats/stackdriver/stackdriver_test.go
index 02f2e41..ae58ffa 100644
--- a/exporter/stats/stackdriver/stackdriver_test.go
+++ b/exporter/stats/stackdriver/stackdriver_test.go
@@ -63,6 +63,18 @@ func TestExporter_makeReq(t *testing.T) {
 
 	start := time.Now()
 	end := start.Add(time.Minute)
+	count1 := stats.CountData(10)
+	count2 := stats.CountData(16)
+	sum1 := stats.SumData(5.5)
+	sum2 := stats.SumData(-11.1)
+	mean1 := stats.MeanData{
+		Mean:  3.3,
+		Count: 7,
+	}
+	mean2 := stats.MeanData{
+		Mean:  -7.7,
+		Count: 5,
+	}
 
 	tests := []struct {
 		name   string
@@ -73,7 +85,7 @@ func TestExporter_makeReq(t *testing.T) {
 		{
 			name:   "count agg + cum timeline",
 			projID: "proj-id",
-			vd:     newTestCumViewData(cumView, start, end),
+			vd:     newTestCumViewData(cumView, start, end, &count1, &count2),
 			want: []*monitoringpb.CreateTimeSeriesRequest{{
 				Name: monitoring.MetricProjectPath("proj-id"),
 				TimeSeries: []*monitoringpb.TimeSeries{
@@ -132,6 +144,130 @@ func TestExporter_makeReq(t *testing.T) {
 				},
 			}},
 		},
+		{
+			name:   "sum agg + cum timeline",
+			projID: "proj-id",
+			vd:     newTestCumViewData(cumView, start, end, &sum1, &sum2),
+			want: []*monitoringpb.CreateTimeSeriesRequest{{
+				Name: monitoring.MetricProjectPath("proj-id"),
+				TimeSeries: []*monitoringpb.TimeSeries{
+					{
+						Metric: &metricpb.Metric{
+							Type:   "custom.googleapis.com/opencensus/cumview",
+							Labels: map[string]string{"test_key": "test-value-1"},
+						},
+						Resource: &monitoredrespb.MonitoredResource{
+							Type: "global",
+						},
+						Points: []*monitoringpb.Point{
+							{
+								Interval: &monitoringpb.TimeInterval{
+									StartTime: &timestamp.Timestamp{
+										Seconds: start.Unix(),
+										Nanos:   int32(start.Nanosecond()),
+									},
+									EndTime: &timestamp.Timestamp{
+										Seconds: end.Unix(),
+										Nanos:   int32(end.Nanosecond()),
+									},
+								},
+								Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{
+									DoubleValue: 5.5,
+								}},
+							},
+						},
+					},
+					{
+						Metric: &metricpb.Metric{
+							Type:   "custom.googleapis.com/opencensus/cumview",
+							Labels: map[string]string{"test_key": "test-value-2"},
+						},
+						Resource: &monitoredrespb.MonitoredResource{
+							Type: "global",
+						},
+						Points: []*monitoringpb.Point{
+							{
+								Interval: &monitoringpb.TimeInterval{
+									StartTime: &timestamp.Timestamp{
+										Seconds: start.Unix(),
+										Nanos:   int32(start.Nanosecond()),
+									},
+									EndTime: &timestamp.Timestamp{
+										Seconds: end.Unix(),
+										Nanos:   int32(end.Nanosecond()),
+									},
+								},
+								Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{
+									DoubleValue: -11.1,
+								}},
+							},
+						},
+					},
+				},
+			}},
+		},
+		{
+			name:   "mean agg + cum timeline",
+			projID: "proj-id",
+			vd:     newTestCumViewData(cumView, start, end, &mean1, &mean2),
+			want: []*monitoringpb.CreateTimeSeriesRequest{{
+				Name: monitoring.MetricProjectPath("proj-id"),
+				TimeSeries: []*monitoringpb.TimeSeries{
+					{
+						Metric: &metricpb.Metric{
+							Type:   "custom.googleapis.com/opencensus/cumview",
+							Labels: map[string]string{"test_key": "test-value-1"},
+						},
+						Resource: &monitoredrespb.MonitoredResource{
+							Type: "global",
+						},
+						Points: []*monitoringpb.Point{
+							{
+								Interval: &monitoringpb.TimeInterval{
+									StartTime: &timestamp.Timestamp{
+										Seconds: start.Unix(),
+										Nanos:   int32(start.Nanosecond()),
+									},
+									EndTime: &timestamp.Timestamp{
+										Seconds: end.Unix(),
+										Nanos:   int32(end.Nanosecond()),
+									},
+								},
+								Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{
+									DoubleValue: 3.3,
+								}},
+							},
+						},
+					},
+					{
+						Metric: &metricpb.Metric{
+							Type:   "custom.googleapis.com/opencensus/cumview",
+							Labels: map[string]string{"test_key": "test-value-2"},
+						},
+						Resource: &monitoredrespb.MonitoredResource{
+							Type: "global",
+						},
+						Points: []*monitoringpb.Point{
+							{
+								Interval: &monitoringpb.TimeInterval{
+									StartTime: &timestamp.Timestamp{
+										Seconds: start.Unix(),
+										Nanos:   int32(start.Nanosecond()),
+									},
+									EndTime: &timestamp.Timestamp{
+										Seconds: end.Unix(),
+										Nanos:   int32(end.Nanosecond()),
+									},
+								},
+								Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{
+									DoubleValue: -7.7,
+								}},
+							},
+						},
+					},
+				},
+			}},
+		},
 		{
 			name:   "dist agg + time window",
 			projID: "proj-id",
@@ -207,10 +343,13 @@ func TestExporter_makeReq_batching(t *testing.T) {
 		},
 	}
 
+	count1 := stats.CountData(10)
+	count2 := stats.CountData(16)
+
 	for _, tt := range tests {
 		var vds []*stats.ViewData
 		for i := 0; i < tt.iter; i++ {
-			vds = append(vds, newTestCumViewData(view, time.Now(), time.Now()))
+			vds = append(vds, newTestCumViewData(view, time.Now(), time.Now(), &count1, &count2))
 		}
 
 		e := &Exporter{}
@@ -331,9 +470,7 @@ func TestEqualAggWindowTagKeys(t *testing.T) {
 	}
 }
 
-func newTestCumViewData(v *stats.View, start, end time.Time) *stats.ViewData {
-	count1 := stats.CountData(10)
-	count2 := stats.CountData(16)
+func newTestCumViewData(v *stats.View, start, end time.Time, data1, data2 stats.AggregationData) *stats.ViewData {
 	key, _ := tag.NewKey("test-key")
 	tag1 := tag.Tag{Key: key, Value: "test-value-1"}
 	tag2 := tag.Tag{Key: key, Value: "test-value-2"}
@@ -342,11 +479,11 @@ func newTestCumViewData(v *stats.View, start, end time.Time) *stats.ViewData {
 		Rows: []*stats.Row{
 			{
 				Tags: []tag.Tag{tag1},
-				Data: &count1,
+				Data: data1,
 			},
 			{
 				Tags: []tag.Tag{tag2},
-				Data: &count2,
+				Data: data2,
 			},
 		},
 		Start: start,
diff --git a/plugin/grpc/grpcstats/client_handler_test.go b/plugin/grpc/grpcstats/client_handler_test.go
index 07740f1..9f315b1 100644
--- a/plugin/grpc/grpcstats/client_handler_test.go
+++ b/plugin/grpc/grpcstats/client_handler_test.go
@@ -160,7 +160,7 @@ func TestClientDefaultCollections(t *testing.T) {
 								{Key: keyOpStatus, Value: "someError"},
 								{Key: keyService, Value: "package.service"},
 							},
-							newCountData(1),
+							newMeanData(1, 1),
 						},
 					},
 				},
@@ -243,7 +243,7 @@ func TestClientDefaultCollections(t *testing.T) {
 								{Key: keyOpStatus, Value: "someError1"},
 								{Key: keyService, Value: "package.service"},
 							},
-							newCountData(1),
+							newMeanData(1, 1),
 						},
 						{
 							[]tag.Tag{
@@ -251,7 +251,7 @@ func TestClientDefaultCollections(t *testing.T) {
 								{Key: keyOpStatus, Value: "someError2"},
 								{Key: keyService, Value: "package.service"},
 							},
-							newCountData(1),
+							newMeanData(1, 1),
 						},
 					},
 				},
diff --git a/plugin/grpc/grpcstats/client_metrics_test.go b/plugin/grpc/grpcstats/client_metrics_test.go
new file mode 100644
index 0000000..aae1a38
--- /dev/null
+++ b/plugin/grpc/grpcstats/client_metrics_test.go
@@ -0,0 +1,65 @@
+// Copyright 2017, OpenCensus 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 grpcstats
+
+import (
+	"reflect"
+	"runtime"
+	"testing"
+
+	"go.opencensus.io/stats"
+)
+
+func TestViewsAggregationsConform(t *testing.T) {
+	// See Issue https://github.com/census-instrumentation/opencensus-go/issues/210.
+	// This test ensures that the types of our Views match up with those
+	// from the Java reference at
+	// https://github.com/census-instrumentation/opencensus-java/blob/2b464864e3dd3f80e8e4c9dc72fccc225444a939/contrib/grpc_metrics/src/main/java/io/opencensus/contrib/grpc/metrics/RpcViewConstants.java#L113-L658
+	// Add any other defined views to be type checked during tests to ensure we don't regress.
+
+	assertTypeOf := func(v *stats.View, wantSample stats.Aggregation) {
+		aggregation := v.Aggregation()
+		gotValue := reflect.ValueOf(aggregation)
+		wantValue := reflect.ValueOf(wantSample)
+		if gotValue.Type() != wantValue.Type() {
+			_, _, line, _ := runtime.Caller(1)
+			t.Errorf("Item on line: %d got %T want %T", line, aggregation, wantSample)
+		}
+	}
+
+	assertTypeOf(RPCClientErrorCountView, stats.MeanAggregation{})
+	assertTypeOf(RPCClientRoundTripLatencyView, stats.DistributionAggregation{})
+	assertTypeOf(RPCClientRequestBytesView, stats.DistributionAggregation{})
+	assertTypeOf(RPCClientResponseBytesView, stats.DistributionAggregation{})
+	assertTypeOf(RPCClientRequestCountView, stats.DistributionAggregation{})
+	assertTypeOf(RPCClientResponseCountView, stats.DistributionAggregation{})
+	assertTypeOf(RPCClientRoundTripLatencyMinuteView, stats.MeanAggregation{})
+	assertTypeOf(RPCClientRequestBytesMinuteView, stats.MeanAggregation{})
+	assertTypeOf(RPCClientResponseBytesMinuteView, stats.MeanAggregation{})
+	assertTypeOf(RPCClientErrorCountMinuteView, stats.MeanAggregation{})
+	assertTypeOf(RPCClientStartedCountMinuteView, stats.MeanAggregation{})
+	assertTypeOf(RPCClientFinishedCountMinuteView, stats.MeanAggregation{})
+	assertTypeOf(RPCClientRequestCountMinuteView, stats.MeanAggregation{})
+	assertTypeOf(RPCClientResponseCountMinuteView, stats.MeanAggregation{})
+	assertTypeOf(RPCClientRoundTripLatencyHourView, stats.MeanAggregation{})
+	assertTypeOf(RPCClientRequestBytesHourView, stats.MeanAggregation{})
+	assertTypeOf(RPCClientResponseBytesHourView, stats.MeanAggregation{})
+	assertTypeOf(RPCClientErrorCountHourView, stats.MeanAggregation{})
+	assertTypeOf(RPCClientStartedCountHourView, stats.MeanAggregation{})
+	assertTypeOf(RPCClientFinishedCountHourView, stats.MeanAggregation{})
+	assertTypeOf(RPCClientRequestCountHourView, stats.MeanAggregation{})
+	assertTypeOf(RPCClientResponseCountHourView, stats.MeanAggregation{})
+}
diff --git a/plugin/grpc/grpcstats/server_handler_test.go b/plugin/grpc/grpcstats/server_handler_test.go
index d1383a4..1a4fdbd 100644
--- a/plugin/grpc/grpcstats/server_handler_test.go
+++ b/plugin/grpc/grpcstats/server_handler_test.go
@@ -376,6 +376,11 @@ func newCountData(v int) *istats.CountData {
 	return &cav
 }
 
+func newMeanData(count, mean float64) *istats.MeanData {
+	mav := istats.MeanData{Count: count, Mean: mean}
+	return &mav
+}
+
 func newDistributionData(bounds []float64, countPerBucket []int64, count int64, min, max, mean, sumOfSquaredDev float64) *istats.DistributionData {
 	return &istats.DistributionData{
 		Count:           count,
diff --git a/stats/collector_test.go b/stats/collector_test.go
index bf56ee7..8382b59 100644
--- a/stats/collector_test.go
+++ b/stats/collector_test.go
@@ -15,10 +15,9 @@
 package stats
 
 import (
+	"context"
 	"testing"
 
-	"golang.org/x/net/context"
-
 	"go.opencensus.io/tag"
 )
 
diff --git a/stats/example_test.go b/stats/example_test.go
index 07938c9..f403389 100644
--- a/stats/example_test.go
+++ b/stats/example_test.go
@@ -15,11 +15,10 @@
 package stats_test
 
 import (
+	"context"
 	"log"
 	"time"
 
-	"golang.org/x/net/context"
-
 	"go.opencensus.io/stats"
 )
 
diff --git a/stats/view_test.go b/stats/view_test.go
index 4351e6f..8698b8a 100644
--- a/stats/view_test.go
+++ b/stats/view_test.go
@@ -16,11 +16,10 @@
 package stats
 
 import (
+	"context"
 	"testing"
 	"time"
 
-	"golang.org/x/net/context"
-
 	"go.opencensus.io/tag"
 )
 
diff --git a/stats/worker_test.go b/stats/worker_test.go
index 223a05d..a2d0595 100644
--- a/stats/worker_test.go
+++ b/stats/worker_test.go
@@ -16,6 +16,7 @@
 package stats
 
 import (
+	"context"
 	"errors"
 	"fmt"
 	"sync"
@@ -23,8 +24,6 @@ import (
 	"time"
 
 	"go.opencensus.io/tag"
-
-	"golang.org/x/net/context"
 )
 
 func Test_Worker_MeasureCreation(t *testing.T) {