Repository: GoogleCloudPlatform/opentelemetry-operations-go
Pull request #105 (2020-10-06 07:06:12)

Fix to use the correct version to build user agent

shouichi: @nilebox Totally unrelated but... Could you add `hacktoberfest-accepted` label to my PRs or add `hacktoberfest` topic to this repository so that they are accepted to hacktoberfest? Thanks!

Patch:
diff --git a/Makefile b/Makefile
index f32a198..61d146c 100644
--- a/Makefile
+++ b/Makefile
@@ -130,11 +130,13 @@ gotidy:
 .PHONY: update-dep
 update-dep:
 	$(MAKE) for-all CMD="$(PWD)/internal/buildscripts/update-dep"
-	$(MAKE) build
-	$(MAKE) gotidy
 
-OTEL_VERSION=v0.12.0
+OTEL_VERSION=v0.13.0
 
 .PHONY: update-otel
 update-otel:
 	$(MAKE) update-dep MODULE=go.opentelemetry.io/otel VERSION=$(OTEL_VERSION)
+	$(MAKE) update-dep MODULE=go.opentelemetry.io/otel/sdk VERSION=$(OTEL_VERSION)
+	$(MAKE) update-dep MODULE=go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp VERSION=$(OTEL_VERSION)
+	$(MAKE) build
+	$(MAKE) gotidy
diff --git a/example/metric/go.mod b/example/metric/go.mod
index cc4c24d..78621d3 100644
--- a/example/metric/go.mod
+++ b/example/metric/go.mod
@@ -6,6 +6,6 @@ replace github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metr
 
 require (
 	github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.12.0
-	go.opentelemetry.io/otel v0.12.0
-	go.opentelemetry.io/otel/sdk v0.12.0
+	go.opentelemetry.io/otel v0.13.0
+	go.opentelemetry.io/otel/sdk v0.13.0
 )
diff --git a/example/metric/go.sum b/example/metric/go.sum
index 8c5f7b3..dba774d 100644
--- a/example/metric/go.sum
+++ b/example/metric/go.sum
@@ -143,10 +143,10 @@ go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
 go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto=
 go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opentelemetry.io/otel v0.12.0 h1:bwWaPd/h2q+U6KdKaAiOS5GLwOMd1LDt9iNaeyIoAI8=
-go.opentelemetry.io/otel v0.12.0/go.mod h1:dlSNewoRYikTkotEnxdmuBHgzT+k/idJSfDv/FxEnOY=
-go.opentelemetry.io/otel/sdk v0.12.0 h1:YVUyDXsGvFWjhJxGXT4kBcGdfoTbo1vSGjbGRUdRh5U=
-go.opentelemetry.io/otel/sdk v0.12.0/go.mod h1:u3joRdxhrS1hUf9xSFH8vgdXdujQ3jxXxZl3loZFSqs=
+go.opentelemetry.io/otel v0.13.0 h1:2isEnyzjjJZq6r2EKMsFj4TxiQiexsM04AVhwbR/oBA=
+go.opentelemetry.io/otel v0.13.0/go.mod h1:dlSNewoRYikTkotEnxdmuBHgzT+k/idJSfDv/FxEnOY=
+go.opentelemetry.io/otel/sdk v0.13.0 h1:4VCfpKamZ8GtnepXxMRurSpHpMKkcxhtO33z1S4rGDQ=
+go.opentelemetry.io/otel/sdk v0.13.0/go.mod h1:dKvLH8Uu8LcEPlSAUsfW7kMGaJBhk/1NYvpPZ6wIMbU=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
diff --git a/example/trace/http/client/client.go b/example/trace/http/client/client.go
index 84b808f..4bfa72b 100644
--- a/example/trace/http/client/client.go
+++ b/example/trace/http/client/client.go
@@ -21,6 +21,7 @@ import (
 	"log"
 	"os"
 
+	"go.opentelemetry.io/otel"
 	"go.opentelemetry.io/otel/semconv"
 
 	"net/http"
@@ -28,7 +29,6 @@ import (
 	"go.opentelemetry.io/otel/codes"
 
 	"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
-	"go.opentelemetry.io/otel/api/baggage"
 	"go.opentelemetry.io/otel/api/global"
 	"go.opentelemetry.io/otel/api/trace"
 	"go.opentelemetry.io/otel/label"
@@ -60,7 +60,7 @@ func main() {
 	tr := global.TracerProvider().Tracer("cloudtrace/example/client")
 
 	client := http.Client{Transport: otelhttp.NewTransport(http.DefaultTransport)}
-	ctx := baggage.NewContext(context.Background(),
+	ctx := otel.ContextWithBaggageValues(context.Background(),
 		label.String("username", "donuts"),
 	)
 
@@ -78,7 +78,7 @@ func main() {
 		}
 		body, err = ioutil.ReadAll(res.Body)
 		_ = res.Body.Close()
-		span.SetStatus(codes.OK, "")
+		span.SetStatus(codes.Ok, "")
 
 		return err
 	}(ctx)
diff --git a/example/trace/http/go.mod b/example/trace/http/go.mod
index 332ef73..223d4ed 100644
--- a/example/trace/http/go.mod
+++ b/example/trace/http/go.mod
@@ -6,8 +6,8 @@ replace github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trac
 
 require (
 	github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace v0.12.0
-	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.12.0
-	go.opentelemetry.io/otel v0.12.0
-	go.opentelemetry.io/otel/sdk v0.12.0
+	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.13.0
+	go.opentelemetry.io/otel v0.13.0
+	go.opentelemetry.io/otel/sdk v0.13.0
 	golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 // indirect
 )
diff --git a/example/trace/http/go.sum b/example/trace/http/go.sum
index 6fa8a7d..394950c 100644
--- a/example/trace/http/go.sum
+++ b/example/trace/http/go.sum
@@ -134,14 +134,14 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto=
 go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opentelemetry.io/contrib v0.12.0 h1:vLtYifaYQD8i9ncT07vLqUmo2RivECfpNJ2kv3YKnK0=
-go.opentelemetry.io/contrib v0.12.0/go.mod h1:onlxH6TKFRkW2Xgc5IO37kPYz3v7wMzh/FrBxsQxCt4=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.12.0 h1:MlJBwZ+FZYZqrUUr9hUO/8RrGFMT3Aos6k82UwLfBb8=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.12.0/go.mod h1:h7OH5woH8YpaEpJkBpGeo9OzNDjT5fYpLdIC7JD1WX4=
-go.opentelemetry.io/otel v0.12.0 h1:bwWaPd/h2q+U6KdKaAiOS5GLwOMd1LDt9iNaeyIoAI8=
-go.opentelemetry.io/otel v0.12.0/go.mod h1:dlSNewoRYikTkotEnxdmuBHgzT+k/idJSfDv/FxEnOY=
-go.opentelemetry.io/otel/sdk v0.12.0 h1:YVUyDXsGvFWjhJxGXT4kBcGdfoTbo1vSGjbGRUdRh5U=
-go.opentelemetry.io/otel/sdk v0.12.0/go.mod h1:u3joRdxhrS1hUf9xSFH8vgdXdujQ3jxXxZl3loZFSqs=
+go.opentelemetry.io/contrib v0.13.0 h1:q34CFu5REx9Dt2ksESHC/doIjFJkEg1oV3aSwlL5JR0=
+go.opentelemetry.io/contrib v0.13.0/go.mod h1:HzCu6ebm0ywgNxGaEfs3izyJOMP4rZnzxycyTgpI5Sg=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.13.0 h1:dnZy1afzxEDrHybTYoJE1bQ3fphNwZF2ipSsynlITP4=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.13.0/go.mod h1:SeQm4RTCcZ2/hlMSTuHb7nwIROe5odBtgfKx+7MMqEs=
+go.opentelemetry.io/otel v0.13.0 h1:2isEnyzjjJZq6r2EKMsFj4TxiQiexsM04AVhwbR/oBA=
+go.opentelemetry.io/otel v0.13.0/go.mod h1:dlSNewoRYikTkotEnxdmuBHgzT+k/idJSfDv/FxEnOY=
+go.opentelemetry.io/otel/sdk v0.13.0 h1:4VCfpKamZ8GtnepXxMRurSpHpMKkcxhtO33z1S4rGDQ=
+go.opentelemetry.io/otel/sdk v0.13.0/go.mod h1:dKvLH8Uu8LcEPlSAUsfW7kMGaJBhk/1NYvpPZ6wIMbU=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
diff --git a/exporter/metric/go.mod b/exporter/metric/go.mod
index 7964a15..cc17d6c 100644
--- a/exporter/metric/go.mod
+++ b/exporter/metric/go.mod
@@ -8,11 +8,12 @@ require (
 	github.com/golang/protobuf v1.4.2
 	github.com/googleinterns/cloud-operations-api-mock v0.0.0-20200709193332-a1e58c29bdd3
 	github.com/stretchr/testify v1.6.1
-	go.opentelemetry.io/otel v0.12.0
-	go.opentelemetry.io/otel/sdk v0.12.0
+	go.opentelemetry.io/otel v0.13.0
+	go.opentelemetry.io/otel/sdk v0.13.0
 	golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
 	golang.org/x/sys v0.0.0-20200828194041-157a740278f4 // indirect
 	google.golang.org/api v0.30.0
 	google.golang.org/genproto v0.0.0-20200831141814-d751682dd103
+	google.golang.org/grpc v1.32.0 // indirect
 	gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
 )
diff --git a/exporter/metric/go.sum b/exporter/metric/go.sum
index f787520..9a270bc 100644
--- a/exporter/metric/go.sum
+++ b/exporter/metric/go.sum
@@ -149,10 +149,10 @@ go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
 go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto=
 go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opentelemetry.io/otel v0.12.0 h1:bwWaPd/h2q+U6KdKaAiOS5GLwOMd1LDt9iNaeyIoAI8=
-go.opentelemetry.io/otel v0.12.0/go.mod h1:dlSNewoRYikTkotEnxdmuBHgzT+k/idJSfDv/FxEnOY=
-go.opentelemetry.io/otel/sdk v0.12.0 h1:YVUyDXsGvFWjhJxGXT4kBcGdfoTbo1vSGjbGRUdRh5U=
-go.opentelemetry.io/otel/sdk v0.12.0/go.mod h1:u3joRdxhrS1hUf9xSFH8vgdXdujQ3jxXxZl3loZFSqs=
+go.opentelemetry.io/otel v0.13.0 h1:2isEnyzjjJZq6r2EKMsFj4TxiQiexsM04AVhwbR/oBA=
+go.opentelemetry.io/otel v0.13.0/go.mod h1:dlSNewoRYikTkotEnxdmuBHgzT+k/idJSfDv/FxEnOY=
+go.opentelemetry.io/otel/sdk v0.13.0 h1:4VCfpKamZ8GtnepXxMRurSpHpMKkcxhtO33z1S4rGDQ=
+go.opentelemetry.io/otel/sdk v0.13.0/go.mod h1:dKvLH8Uu8LcEPlSAUsfW7kMGaJBhk/1NYvpPZ6wIMbU=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
diff --git a/exporter/metric/metric.go b/exporter/metric/metric.go
index 36d3eb8..a045f48 100644
--- a/exporter/metric/metric.go
+++ b/exporter/metric/metric.go
@@ -40,7 +40,6 @@ import (
 )
 
 const (
-	version                                   = "0.2.1"
 	cloudMonitoringMetricDescriptorNameFormat = "custom.googleapis.com/opentelemetry/%s"
 )
 
@@ -216,11 +215,7 @@ func (me *metricExporter) exportMetricDescriptor(ctx context.Context, cps export
 	// the descriptor does not exist in global cache (me.mdCache).
 	// See details in #26.
 	for kmd, md := range mds {
-		req := &monitoringpb.CreateMetricDescriptorRequest{
-			Name:             fmt.Sprintf("projects/%s", me.o.ProjectID),
-			MetricDescriptor: md,
-		}
-		_, err := me.client.CreateMetricDescriptor(ctx, req)
+		err := me.createMetricDescriptorIfNeeded(ctx, md)
 		if err != nil {
 			return err
 		}
@@ -229,6 +224,26 @@ func (me *metricExporter) exportMetricDescriptor(ctx context.Context, cps export
 	return nil
 }
 
+func (me *metricExporter) createMetricDescriptorIfNeeded(ctx context.Context, md *googlemetricpb.MetricDescriptor) error {
+	mdReq := &monitoringpb.GetMetricDescriptorRequest{
+		Name: fmt.Sprintf("projects/%s/metricDescriptors/%s", me.o.ProjectID, md.Type),
+	}
+	_, err := me.client.GetMetricDescriptor(ctx, mdReq)
+	if err == nil {
+		// If the metric descriptor already exists, skip the CreateMetricDescriptor call.
+		// Metric descriptors cannot be updated without deleting them first, so there
+		// isn't anything we can do here:
+		// https://cloud.google.com/monitoring/custom-metrics/creating-metrics#md-modify
+		return nil
+	}
+	req := &monitoringpb.CreateMetricDescriptorRequest{
+		Name:             fmt.Sprintf("projects/%s", me.o.ProjectID),
+		MetricDescriptor: md,
+	}
+	_, err = me.client.CreateMetricDescriptor(ctx, req)
+	return err
+}
+
 // exportTimeSeriees create TimeSeries from the records in cps.
 // res should be the common resource among all TimeSeries, such as instance id, application name and so on.
 func (me *metricExporter) exportTimeSeries(ctx context.Context, cps export.CheckpointSet) error {
diff --git a/exporter/metric/option.go b/exporter/metric/option.go
index 2e68b98..e5395bc 100644
--- a/exporter/metric/option.go
+++ b/exporter/metric/option.go
@@ -25,9 +25,7 @@ import (
 	apioption "google.golang.org/api/option"
 )
 
-var (
-	userAgent = fmt.Sprintf("opentelemetry-go %s; metric-exporter %s", otel.Version(), version)
-)
+var userAgent = fmt.Sprintf("opentelemetry-go %s; metric-exporter %s", otel.Version(), Version())
 
 // Option is function type that is passed to the exporter initialization function.
 type Option func(*options)
diff --git a/exporter/trace/cloudtrace.go b/exporter/trace/cloudtrace.go
index 8a11977..f006162 100644
--- a/exporter/trace/cloudtrace.go
+++ b/exporter/trace/cloudtrace.go
@@ -87,6 +87,15 @@ type options struct {
 	// Optional. Default value is 50.
 	BundleCountThreshold int
 
+	// BundleByteThreshold is the number of bytes that can be buffered before
+	// batch uploading them to the backend.
+	// Optional. Default value is 15KB.
+	BundleByteThreshold int
+
+	// BundleByteLimit is the maximum size of a bundle, in bytes. Zero means unlimited.
+	// Optional. Default value is unlimited.
+	BundleByteLimit int
+
 	// BufferMaxBytes is the maximum size (in bytes) of spans that
 	// will be buffered in memory before being dropped.
 	//
@@ -167,6 +176,22 @@ func WithBundleCountThreshold(bundleCountThreshold int) func(o *options) {
 	}
 }
 
+// WithBundleByteThreshold sets the number of bytes that can be buffered before
+// batch uploading them to the backend.
+func WithBundleByteThreshold(bundleByteThreshold int) func(o *options) {
+	return func(o *options) {
+		o.BundleByteThreshold = bundleByteThreshold
+	}
+}
+
+// WithBundleByteLimit sets the maximum size of a bundle, in bytes. Zero means
+// unlimited.
+func WithBundleByteLimit(bundleByteLimit int) func(o *options) {
+	return func(o *options) {
+		o.BundleByteLimit = bundleByteLimit
+	}
+}
+
 // WithBufferMaxBytes sets the maximum size (in bytes) of spans that will
 // be buffered in memory before being dropped
 func WithBufferMaxBytes(bufferMaxBytes int) func(o *options) {
diff --git a/exporter/trace/go.mod b/exporter/trace/go.mod
index b8158bd..8980526 100644
--- a/exporter/trace/go.mod
+++ b/exporter/trace/go.mod
@@ -7,11 +7,11 @@ require (
 	github.com/golang/protobuf v1.4.2
 	github.com/googleinterns/cloud-operations-api-mock v0.0.0-20200709193332-a1e58c29bdd3
 	github.com/stretchr/testify v1.6.1
-	go.opentelemetry.io/otel v0.12.0
-	go.opentelemetry.io/otel/sdk v0.12.0
+	go.opentelemetry.io/otel v0.13.0
+	go.opentelemetry.io/otel/sdk v0.13.0
 	golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
 	google.golang.org/api v0.29.0
 	google.golang.org/genproto v0.0.0-20200715011427-11fb19a81f2c
-	google.golang.org/grpc v1.32.0
+	google.golang.org/grpc v1.32.0 // indirect
 	google.golang.org/protobuf v1.25.0
 )
diff --git a/exporter/trace/go.sum b/exporter/trace/go.sum
index 486a1db..942b2c2 100644
--- a/exporter/trace/go.sum
+++ b/exporter/trace/go.sum
@@ -131,10 +131,10 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto=
 go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opentelemetry.io/otel v0.12.0 h1:bwWaPd/h2q+U6KdKaAiOS5GLwOMd1LDt9iNaeyIoAI8=
-go.opentelemetry.io/otel v0.12.0/go.mod h1:dlSNewoRYikTkotEnxdmuBHgzT+k/idJSfDv/FxEnOY=
-go.opentelemetry.io/otel/sdk v0.12.0 h1:YVUyDXsGvFWjhJxGXT4kBcGdfoTbo1vSGjbGRUdRh5U=
-go.opentelemetry.io/otel/sdk v0.12.0/go.mod h1:u3joRdxhrS1hUf9xSFH8vgdXdujQ3jxXxZl3loZFSqs=
+go.opentelemetry.io/otel v0.13.0 h1:2isEnyzjjJZq6r2EKMsFj4TxiQiexsM04AVhwbR/oBA=
+go.opentelemetry.io/otel v0.13.0/go.mod h1:dlSNewoRYikTkotEnxdmuBHgzT+k/idJSfDv/FxEnOY=
+go.opentelemetry.io/otel/sdk v0.13.0 h1:4VCfpKamZ8GtnepXxMRurSpHpMKkcxhtO33z1S4rGDQ=
+go.opentelemetry.io/otel/sdk v0.13.0/go.mod h1:dKvLH8Uu8LcEPlSAUsfW7kMGaJBhk/1NYvpPZ6wIMbU=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
diff --git a/exporter/trace/trace.go b/exporter/trace/trace.go
index a2b193d..60f26c0 100644
--- a/exporter/trace/trace.go
+++ b/exporter/trace/trace.go
@@ -18,6 +18,7 @@ import (
 	"context"
 	"fmt"
 	"log"
+	"strings"
 	"sync"
 	"time"
 
@@ -41,11 +42,11 @@ type traceExporter struct {
 	client *traceclient.Client
 }
 
-const defaultBufferedByteLimit = 8 * 1024 * 1024
 const defaultBundleDelayThreshold = 2 * time.Second
 const defaultBundleCountThreshold = 50
-const bundleByteThresholdMultiplier = 300
-const bundleByteLimitMultiplier = 1000
+const defaultBundleByteThreshold = 15000
+const defaultBundleByteLimit = 0
+const defaultBufferedByteLimit = 8 * 1024 * 1024
 
 func newTraceExporter(o *options) (*traceExporter, error) {
 	client, err := traceclient.NewClient(o.Context, o.TraceClientOptions...)
@@ -53,30 +54,45 @@ func newTraceExporter(o *options) (*traceExporter, error) {
 		return nil, fmt.Errorf("stackdriver: couldn't initiate trace client: %v", err)
 	}
 	e := &traceExporter{
-		projectID: o.ProjectID,
-		client:    client,
-		o:         o,
+		projectID:      o.ProjectID,
+		client:         client,
+		o:              o,
+		overflowLogger: overflowLogger{delayDur: 5 * time.Second},
 	}
 	b := bundler.NewBundler((*tracepb.Span)(nil), func(bundle interface{}) {
 		e.uploadFn(context.Background(), bundle.([]*tracepb.Span))
 	})
+
 	if o.BundleDelayThreshold > 0 {
 		b.DelayThreshold = o.BundleDelayThreshold
 	} else {
 		b.DelayThreshold = defaultBundleDelayThreshold
 	}
+
 	if o.BundleCountThreshold > 0 {
 		b.BundleCountThreshold = o.BundleCountThreshold
 	} else {
 		b.BundleCountThreshold = defaultBundleCountThreshold
 	}
-	b.BundleByteThreshold = b.BundleCountThreshold * bundleByteThresholdMultiplier
-	b.BundleByteLimit = b.BundleCountThreshold * bundleByteLimitMultiplier
+
+	if o.BundleByteThreshold > 0 {
+		b.BundleByteThreshold = o.BundleByteThreshold
+	} else {
+		b.BundleByteThreshold = defaultBundleByteThreshold
+	}
+
+	if o.BundleByteLimit > 0 {
+		b.BundleByteLimit = o.BundleByteLimit
+	} else {
+		b.BundleByteLimit = defaultBundleByteLimit
+	}
+
 	if o.BufferMaxBytes > 0 {
 		b.BufferedByteLimit = o.BufferMaxBytes
 	} else {
 		b.BufferedByteLimit = defaultBufferedByteLimit
 	}
+
 	if o.MaxNumberOfWorkers > 0 {
 		b.HandlerLimit = o.MaxNumberOfWorkers
 	}
@@ -91,9 +107,9 @@ func (e *traceExporter) checkBundlerError(err error) {
 	case nil:
 		return
 	case bundler.ErrOversizedItem:
-		fallthrough
+		e.overflowLogger.log(true)
 	case bundler.ErrOverflow:
-		e.overflowLogger.log()
+		e.overflowLogger.log(false)
 	default:
 		e.o.handleError(err)
 	}
@@ -144,38 +160,51 @@ func (e *traceExporter) Flush() {
 // overflowLogger ensures that at most one overflow error log message is
 // written every 5 seconds.
 type overflowLogger struct {
-	mu    sync.Mutex
-	pause bool
-	accum int
+	mu         sync.Mutex
+	pause      bool
+	delayDur   time.Duration
+	bufferErrs int
+	oversized  int
+}
+
+func (o *overflowLogger) log(oversized bool) {
+	o.mu.Lock()
+	defer o.mu.Unlock()
+	if !o.pause {
+		o.delay()
+	}
+
+	if oversized {
+		o.oversized++
+	} else {
+		o.bufferErrs++
+	}
 }
 
 func (o *overflowLogger) delay() {
 	o.pause = true
-	time.AfterFunc(5*time.Second, func() {
+	time.AfterFunc(o.delayDur, func() {
 		o.mu.Lock()
 		defer o.mu.Unlock()
-		switch {
-		case o.accum == 0:
-			o.pause = false
-		case o.accum == 1:
-			log.Println("OpenTelemetry Cloud Trace exporter: failed to upload span: buffer full")
-			o.accum = 0
-			o.delay()
-		default:
-			log.Printf("OpenTelemetry Cloud Trace exporter: failed to upload %d spans: buffer full", o.accum)
-			o.accum = 0
-			o.delay()
-		}
+		o.pause = false
+		logBufferErrors(o.bufferErrs, o.oversized)
+		o.bufferErrs = 0
+		o.oversized = 0
 	})
 }
 
-func (o *overflowLogger) log() {
-	o.mu.Lock()
-	defer o.mu.Unlock()
-	if !o.pause {
-		log.Println("OpenTelemetry Cloud Trace exporter: failed to upload span: buffer full")
-		o.delay()
-	} else {
-		o.accum++
+func logBufferErrors(bufferFull, oversized int) {
+	if bufferFull == 0 && oversized == 0 {
+		return
 	}
+
+	msgs := make([]string, 0, 2)
+	if bufferFull > 0 {
+		msgs = append(msgs, fmt.Sprintf("buffer full: %v", bufferFull))
+	}
+	if oversized > 0 {
+		msgs = append(msgs, fmt.Sprintf("oversized item: %v", oversized))
+	}
+
+	log.Printf("OpenTelemetry Cloud Trace exporter: failed to upload spans: %s\n", strings.Join(msgs, ", "))
 }
diff --git a/exporter/trace/trace_proto.go b/exporter/trace/trace_proto.go
index 7615358..f49e6b3 100644
--- a/exporter/trace/trace_proto.go
+++ b/exporter/trace/trace_proto.go
@@ -23,9 +23,9 @@ import (
 
 	timestamppb "github.com/golang/protobuf/ptypes/timestamp"
 	wrapperspb "github.com/golang/protobuf/ptypes/wrappers"
+	"go.opentelemetry.io/otel/codes"
 	tracepb "google.golang.org/genproto/googleapis/devtools/cloudtrace/v2"
 	statuspb "google.golang.org/genproto/googleapis/rpc/status"
-	"google.golang.org/grpc/codes"
 
 	"go.opentelemetry.io/otel/label"
 	opentelemetry "go.opentelemetry.io/otel/sdk"
@@ -53,11 +53,9 @@ const (
 	labelHTTPStatusCode = `/http/status_code`
 	labelHTTPPath       = `/http/path`
 	labelHTTPUserAgent  = `/http/user_agent`
-
-	version = "0.1.0"
 )
 
-var userAgent = fmt.Sprintf("opentelemetry-go %s; google-cloud-trace-exporter %s", opentelemetry.Version(), version)
+var userAgent = fmt.Sprintf("opentelemetry-go %s; google-cloud-trace-exporter %s", opentelemetry.Version(), Version())
 
 func generateDisplayName(s *export.SpanData, format DisplayNameFormatter) string {
 	if format != nil {
@@ -112,10 +110,10 @@ func protoFromSpanData(s *export.SpanData, projectID string, format DisplayNameF
 	if s.ParentSpanID != s.SpanContext.SpanID && s.ParentSpanID.IsValid() {
 		sp.ParentSpanId = s.ParentSpanID.String()
 	}
-	if s.StatusCode != codes.OK {
+	if s.StatusCode != codes.Ok {
 		sp.Status = &statuspb.Status{Code: int32(s.StatusCode), Message: s.StatusMessage}
 	}
-	if s.StatusCode == codes.OK && s.StatusMessage != "" {
+	if s.StatusCode == codes.Ok && s.StatusMessage != "" {
 		sp.Status = &statuspb.Status{Code: int32(s.StatusCode), Message: s.StatusMessage}
 	}
 


Test patch:
diff --git a/exporter/trace/cloudtrace_test.go b/exporter/trace/cloudtrace_test.go
index 6228db7..44ae6f1 100644
--- a/exporter/trace/cloudtrace_test.go
+++ b/exporter/trace/cloudtrace_test.go
@@ -12,10 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package trace_test
+package trace
 
 import (
 	"context"
+	"log"
+	"os"
 	"regexp"
 	"sync"
 	"testing"
@@ -26,8 +28,6 @@ import (
 	"github.com/googleinterns/cloud-operations-api-mock/cloudmock"
 	"github.com/stretchr/testify/assert"
 
-	texporter "github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace"
-
 	"go.opentelemetry.io/otel/api/global"
 	export "go.opentelemetry.io/otel/sdk/export/trace"
 	sdktrace "go.opentelemetry.io/otel/sdk/trace"
@@ -43,24 +43,24 @@ func TestExporter_ExportSpan(t *testing.T) {
 	clientOpt := []option.ClientOption{option.WithGRPCConn(mock.ClientConn())}
 
 	// Create Google Cloud Trace Exporter
-	_, flush, err := texporter.InstallNewPipeline(
-		[]texporter.Option{
-			texporter.WithProjectID("PROJECT_ID_NOT_REAL"),
-			texporter.WithTraceClientOptions(clientOpt),
+	_, flush, err := InstallNewPipeline(
+		[]Option{
+			WithProjectID("PROJECT_ID_NOT_REAL"),
+			WithTraceClientOptions(clientOpt),
 			// handle bundle as soon as span is received
-			texporter.WithBundleCountThreshold(1),
+			WithBundleCountThreshold(1),
 		},
 		sdktrace.WithConfig(sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()}),
 	)
 	assert.NoError(t, err)
 
 	_, span := global.TracerProvider().Tracer("test-tracer").Start(context.Background(), "test-span")
-	span.SetStatus(codes.OK, "Status Message")
+	span.SetStatus(codes.Ok, "Status Message")
 	span.End()
 	assert.True(t, span.SpanContext().IsValid())
 
 	_, span = global.TracerProvider().Tracer("test-tracer").Start(context.Background(), "test-span-with-error-status")
-	span.SetStatus(codes.NotFound, "Error Message")
+	span.SetStatus(codes.Error, "Error Message")
 	span.End()
 
 	// wait exporter to flush
@@ -82,12 +82,12 @@ func TestExporter_DisplayNameFormatter(t *testing.T) {
 	}
 
 	// Create Google Cloud Trace Exporter
-	_, flush, err := texporter.InstallNewPipeline(
-		[]texporter.Option{
-			texporter.WithProjectID("PROJECT_ID_NOT_REAL"),
-			texporter.WithTraceClientOptions(clientOpt),
-			texporter.WithBundleCountThreshold(1),
-			texporter.WithDisplayNameFormatter(format),
+	_, flush, err := InstallNewPipeline(
+		[]Option{
+			WithProjectID("PROJECT_ID_NOT_REAL"),
+			WithTraceClientOptions(clientOpt),
+			WithBundleCountThreshold(1),
+			WithDisplayNameFormatter(format),
 		},
 		sdktrace.WithConfig(sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()}),
 	)
@@ -112,14 +112,14 @@ func TestExporter_Timeout(t *testing.T) {
 	var exportErrors []error
 
 	// Create Google Cloud Trace Exporter
-	_, flush, err := texporter.InstallNewPipeline(
-		[]texporter.Option{
-			texporter.WithProjectID("PROJECT_ID_NOT_REAL"),
-			texporter.WithTraceClientOptions(clientOpt),
-			texporter.WithTimeout(1 * time.Millisecond),
+	_, flush, err := InstallNewPipeline(
+		[]Option{
+			WithProjectID("PROJECT_ID_NOT_REAL"),
+			WithTraceClientOptions(clientOpt),
+			WithTimeout(1 * time.Millisecond),
 			// handle bundle as soon as span is received
-			texporter.WithBundleCountThreshold(1),
-			texporter.WithOnError(func(err error) {
+			WithBundleCountThreshold(1),
+			WithOnError(func(err error) {
 				exportErrors = append(exportErrors, err)
 			}),
 		},
@@ -153,12 +153,12 @@ func TestBundling(t *testing.T) {
 		ch <- spans
 	})
 
-	_, _, err := texporter.InstallNewPipeline(
-		[]texporter.Option{
-			texporter.WithProjectID("PROJECT_ID_NOT_REAL"),
-			texporter.WithTraceClientOptions(clientOpt),
-			texporter.WithBundleDelayThreshold(time.Second / 10),
-			texporter.WithBundleCountThreshold(10),
+	_, _, err := InstallNewPipeline(
+		[]Option{
+			WithProjectID("PROJECT_ID_NOT_REAL"),
+			WithTraceClientOptions(clientOpt),
+			WithBundleDelayThreshold(time.Second / 10),
+			WithBundleCountThreshold(10),
 		},
 		sdktrace.WithConfig(sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()}),
 	)
@@ -212,13 +212,13 @@ func TestBundling_ConcurrentExports(t *testing.T) {
 	workers := 3
 	spansPerWorker := 50
 	delay := 2 * time.Second
-	_, flush, err := texporter.InstallNewPipeline(
-		[]texporter.Option{
-			texporter.WithProjectID("PROJECT_ID_NOT_REAL"),
-			texporter.WithTraceClientOptions(clientOpt),
-			texporter.WithBundleDelayThreshold(delay),
-			texporter.WithBundleCountThreshold(spansPerWorker),
-			texporter.WithMaxNumberOfWorkers(workers),
+	_, flush, err := InstallNewPipeline(
+		[]Option{
+			WithProjectID("PROJECT_ID_NOT_REAL"),
+			WithTraceClientOptions(clientOpt),
+			WithBundleDelayThreshold(delay),
+			WithBundleCountThreshold(spansPerWorker),
+			WithMaxNumberOfWorkers(workers),
 		},
 		sdktrace.WithConfig(sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()}),
 	)
@@ -265,3 +265,56 @@ func TestBundling_ConcurrentExports(t *testing.T) {
 
 	flush()
 }
+
+func TestBundling_Oversized(t *testing.T) {
+	mock := cloudmock.NewCloudMock()
+	defer mock.Shutdown()
+	clientOpt := []option.ClientOption{option.WithGRPCConn(mock.ClientConn())}
+
+	var uploaded bool
+	mock.SetOnUpload(func(ctx context.Context, spans []*tracepb.Span) { uploaded = true })
+
+	exp, err := NewExporter(
+		WithProjectID("PROJECT_ID_NOT_REAL"),
+		WithTraceClientOptions(clientOpt),
+		WithBundleByteLimit(1),
+	)
+	assert.NoError(t, err)
+	exp.traceExporter.overflowLogger.delayDur = 100 * time.Millisecond
+
+	tp := sdktrace.NewTracerProvider(
+		sdktrace.WithConfig(sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()}),
+		sdktrace.WithSyncer(exp),
+	)
+	global.SetTracerProvider(tp)
+
+	buf := &logBuffer{logInputChan: make(chan []byte, 100)}
+	log.SetOutput(buf)
+	defer func() {
+		log.SetOutput(os.Stderr)
+	}()
+
+	go func() {
+		for i := 0; i < 10; i++ {
+			_, span := global.TracerProvider().Tracer("test-tracer").Start(context.Background(), "test-span")
+			span.SetName("a")
+			span.End()
+		}
+	}()
+
+	if got, want := <-buf.logInputChan, regexp.MustCompile(`OpenTelemetry Cloud Trace exporter: failed to upload spans: oversized item: 10`); !want.Match([]byte(got)) {
+		t.Errorf("log: got %s, want %s", got, want)
+	}
+	if got, want := uploaded, false; got != want {
+		t.Errorf("uploaded: got %v, want %v", got, want)
+	}
+}
+
+type logBuffer struct {
+	logInputChan chan []byte
+}
+
+func (lb *logBuffer) Write(b []byte) (n int, err error) {
+	lb.logInputChan <- b
+	return len(b), nil
+}