Repository: GoogleCloudPlatform/opentelemetry-operations-go
Pull request #83 (2020-08-04 14:01:22)

Add pass through of status message
When setting the the status of a span with `span.SetStatus(codes.Unknown, "Error message")`, the error message didn't get send to the server. This PR adds the status message to the grpc request if a message is given.


Patch:
diff --git a/.gitignore b/.gitignore
index 14291fa..d1d2b0e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,4 @@ Thumbs.db
 *.so
 coverage.*
 
+/example/metric/metric
diff --git a/Makefile b/Makefile
index 966fab3..b1894b4 100644
--- a/Makefile
+++ b/Makefile
@@ -38,6 +38,10 @@ $(TOOLS_DIR)/stringer: $(TOOLS_MOD_DIR)/go.mod $(TOOLS_MOD_DIR)/go.sum $(TOOLS_M
 	cd $(TOOLS_MOD_DIR) && \
 	go build -o $(TOOLS_DIR)/stringer golang.org/x/tools/cmd/stringer
 
+$(TOOLS_DIR)/gojq: $(TOOLS_MOD_DIR)/go.mod $(TOOLS_MOD_DIR)/go.sum $(TOOLS_MOD_DIR)/tools.go
+	cd $(TOOLS_MOD_DIR) && \
+	go build -o $(TOOLS_DIR)/gojq github.com/itchyny/gojq/cmd/gojq
+
 precommit: generate build lint test
 
 .PHONY: test-with-coverage
@@ -109,3 +113,28 @@ lint: $(TOOLS_DIR)/golangci-lint $(TOOLS_DIR)/misspell
 
 generate: $(TOOLS_DIR)/stringer
 	PATH="$(TOOLS_DIR):$${PATH}" go generate ./...
+
+.PHONY: for-all
+for-all:
+	@$${CMD}
+	@set -e; for dir in $(ALL_GO_MOD_DIRS); do \
+	  (cd "$${dir}" && \
+	  	echo "running $${CMD} in $${dir}" && \
+	 	$${CMD} ); \
+	done
+
+.PHONY: gotidy
+gotidy:
+	$(MAKE) for-all CMD="go mod tidy"
+
+.PHONY: update-dep
+update-dep:
+	$(MAKE) for-all CMD="$(PWD)/internal/buildscripts/update-dep"
+	$(MAKE) build
+	$(MAKE) gotidy
+
+OTEL_VERSION=v0.10.0
+
+.PHONY: update-otel
+update-otel:
+	$(MAKE) update-dep MODULE=go.opentelemetry.io/otel VERSION=$(OTEL_VERSION)
\ No newline at end of file
diff --git a/README.md b/README.md
index f56c4e5..b234f8f 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
 # Open-Telemetry Operations Exporters for Go
 
+[![Build Status][circleci-image]][circleci-url]
+
 This repository contains the source code of 2 packages of OpenTelemetry exporters to [Google Cloud Trace](https://cloud.google.com/trace) and [Google Cloud Monitoring](https://cloud.google.com/monitoring).
 
 ## OpenTelemetry Google Cloud Trace Exporter
@@ -13,3 +15,6 @@ See [README.md](https://github.com/GoogleCloudPlatform/opentelemetry-operations-
 OpenTelemetry Google Cloud Monitoring Exporter allows the user to send collected metrics to Google Cloud Monitoring.
 
 See [README.md](https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/blob/master/exporter/metric/README.md) for setup and usage information.
+
+[circleci-image]: https://circleci.com/gh/GoogleCloudPlatform/opentelemetry-operations-go.svg?style=shield 
+[circleci-url]: https://circleci.com/gh/GoogleCloudPlatform/opentelemetry-operations-go
diff --git a/RELEASING.md b/RELEASING.md
new file mode 100644
index 0000000..4e05f87
--- /dev/null
+++ b/RELEASING.md
@@ -0,0 +1,69 @@
+# Release Process
+
+## Pre-Release
+
+Update go.mod for submodules to depend on the new release which will happen in the next step.
+
+1. Run the pre-release script. It creates a branch `pre_release_<new tag>` that will contain all release changes.
+
+    ```
+    ./pre_release.sh -t <new tag>
+    ```
+
+2. Verify the changes.
+
+    ```
+    git diff master
+    ```
+
+    This should have changed the version for all modules to be `<new tag>`.
+
+3. TODO: Consider adding [Changelog](./CHANGELOG.md) and update this for each release.
+
+4. Push the changes to upstream and create a Pull Request on GitHub.
+    Be sure to include the curated changes from the [Changelog](./CHANGELOG.md) in the description.
+
+
+## Tag
+
+Once the Pull Request with all the version changes has been approved and merged it is time to tag the merged commit.
+
+***IMPORTANT***: It is critical you use the same tag that you used in the Pre-Release step!
+Failure to do so will leave things in a broken state.
+
+***IMPORTANT***: [There is currently no way to remove an incorrectly tagged version of a Go module](https://github.com/golang/go/issues/34189).
+It is critical you make sure the version you push upstream is correct.
+[Failure to do so will lead to minor emergencies and tough to work around](https://github.com/open-telemetry/opentelemetry-go/issues/331).
+
+1. Run the tag.sh script using the `<commit-hash>` of the commit on the master branch for the merged Pull Request.
+
+    ```
+    ./tag.sh <new tag> <commit-hash>
+    ```
+
+2. Push tags to the upstream remote (not your fork: `github.com/GoogleCloudPlatform/opentelemetry-operations-go.git`).
+
+    ```
+    git push upstream <new tag>
+    ```
+
+## Release
+
+Finally create a Release for the new `<new tag>` on GitHub.
+
+Make sure all relevant changes for this release are included in the release notes and are in language that non-contributors to the project can understand. The `tag.sh` script generates commit logs since last release which can be used to derive the release notes from. These are generated using:
+
+```
+git --no-pager log --pretty=oneline "<last tag>..HEAD"
+```
+
+## Verify Examples
+
+After releasing verify that examples build outside of the repository.
+
+```
+./verify_examples.sh
+```
+
+The script copies examples into a different directory removes any `replace` declarations in `go.mod` and builds them.
+This ensures they build with the published release, not the local copy.
diff --git a/example/metric/go.mod b/example/metric/go.mod
index e21f807..0414b7a 100644
--- a/example/metric/go.mod
+++ b/example/metric/go.mod
@@ -5,7 +5,8 @@ go 1.14
 replace github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric => ../../exporter/metric
 
 require (
-	github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.2.1
-	go.opentelemetry.io/otel v0.9.0
+	github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.10.0
+	go.opentelemetry.io/otel v0.10.0
+	go.opentelemetry.io/otel/sdk v0.10.0
 	google.golang.org/api v0.25.0 // indirect
 )
diff --git a/example/metric/go.sum b/example/metric/go.sum
index 3c60108..ebec7bf 100644
--- a/example/metric/go.sum
+++ b/example/metric/go.sum
@@ -25,8 +25,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7 h1:qELHH0AWCvf98Yf+CNIJx9vOZOfHFDDzgDRYsnNk/vs=
-github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60=
+github.com/DataDog/sketches-go v0.0.1 h1:RtG+76WKgZuz6FIaGsjoPePmadDBkuD/KC6+ZWu78b8=
+github.com/DataDog/sketches-go v0.0.1/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60=
 github.com/benbjohnson/clock v1.0.3 h1:vkLuvpK4fmtSCuo60+yC63p7y0BmQ8gm5ZXGuBCJyXg=
 github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@@ -77,10 +77,10 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
-github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
-github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
+github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
 github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@@ -123,8 +123,10 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
 go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opentelemetry.io/otel v0.9.0 h1:nsdCDHzQx1Yv8E2nwCPcMXMfg+EMIlx1LBOXNC8qSQ8=
-go.opentelemetry.io/otel v0.9.0/go.mod h1:ckxzUEfk7tAkTwEMVdkllBM+YOfE/K9iwg6zYntFYSg=
+go.opentelemetry.io/otel v0.10.0 h1:2y/HYj1dIfG1nPh0Z15X4se8WwYWuTyKHLSgRb/mbQ0=
+go.opentelemetry.io/otel v0.10.0/go.mod h1:n3v1JGUBpn5DafiF1UeoDs5fr5XZMG+43kigDtFB8Vk=
+go.opentelemetry.io/otel/sdk v0.10.0 h1:iQWVDfmGB+5TjbrO9yFlezGCWBaJ73vxJTHB+ttdTQk=
+go.opentelemetry.io/otel/sdk v0.10.0/go.mod h1:T5752PMr00aUHAVEbaDAYU5tzM2PWOmyy7Lc5OzSrs8=
 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/go.mod b/example/trace/http/go.mod
index 4e89265..b8b17ca 100644
--- a/example/trace/http/go.mod
+++ b/example/trace/http/go.mod
@@ -5,7 +5,8 @@ go 1.13
 replace github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace => ../../../exporter/trace
 
 require (
-	github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace v0.2.0
-	go.opentelemetry.io/otel v0.8.0
+	github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace v0.10.0
+	go.opentelemetry.io/otel v0.10.0
+	go.opentelemetry.io/otel/sdk v0.10.0
 	google.golang.org/grpc v1.30.0
 )
diff --git a/example/trace/http/go.sum b/example/trace/http/go.sum
index 0018cff..5a13be6 100644
--- a/example/trace/http/go.sum
+++ b/example/trace/http/go.sum
@@ -33,8 +33,7 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7 h1:qELHH0AWCvf98Yf+CNIJx9vOZOfHFDDzgDRYsnNk/vs=
-github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60=
+github.com/DataDog/sketches-go v0.0.1/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60=
 github.com/benbjohnson/clock v1.0.3 h1:vkLuvpK4fmtSCuo60+yC63p7y0BmQ8gm5ZXGuBCJyXg=
 github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@@ -87,8 +86,9 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
 github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
-github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
 github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
 github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@@ -134,8 +134,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.8.0 h1:he/8j/EBlKjENVtDvFalawIUcQ+1E3uHRsvJZWLIa7M=
-go.opentelemetry.io/otel v0.8.0/go.mod h1:ckxzUEfk7tAkTwEMVdkllBM+YOfE/K9iwg6zYntFYSg=
+go.opentelemetry.io/otel v0.10.0 h1:2y/HYj1dIfG1nPh0Z15X4se8WwYWuTyKHLSgRb/mbQ0=
+go.opentelemetry.io/otel v0.10.0/go.mod h1:n3v1JGUBpn5DafiF1UeoDs5fr5XZMG+43kigDtFB8Vk=
+go.opentelemetry.io/otel/sdk v0.10.0 h1:iQWVDfmGB+5TjbrO9yFlezGCWBaJ73vxJTHB+ttdTQk=
+go.opentelemetry.io/otel/sdk v0.10.0/go.mod h1:T5752PMr00aUHAVEbaDAYU5tzM2PWOmyy7Lc5OzSrs8=
 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 6728606..9a15483 100644
--- a/exporter/metric/go.mod
+++ b/exporter/metric/go.mod
@@ -7,7 +7,8 @@ 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.9.0
+	go.opentelemetry.io/otel v0.10.0
+	go.opentelemetry.io/otel/sdk v0.10.0
 	golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
 	google.golang.org/api v0.24.0
 	google.golang.org/genproto v0.0.0-20200605102947-12044bf5ea91
diff --git a/exporter/metric/go.sum b/exporter/metric/go.sum
index 2e99051..c1d92dc 100644
--- a/exporter/metric/go.sum
+++ b/exporter/metric/go.sum
@@ -28,8 +28,8 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7 h1:qELHH0AWCvf98Yf+CNIJx9vOZOfHFDDzgDRYsnNk/vs=
-github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60=
+github.com/DataDog/sketches-go v0.0.1 h1:RtG+76WKgZuz6FIaGsjoPePmadDBkuD/KC6+ZWu78b8=
+github.com/DataDog/sketches-go v0.0.1/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60=
 github.com/benbjohnson/clock v1.0.3 h1:vkLuvpK4fmtSCuo60+yC63p7y0BmQ8gm5ZXGuBCJyXg=
 github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@@ -82,10 +82,10 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
-github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
-github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
+github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
 github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@@ -129,8 +129,10 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
 go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opentelemetry.io/otel v0.9.0 h1:nsdCDHzQx1Yv8E2nwCPcMXMfg+EMIlx1LBOXNC8qSQ8=
-go.opentelemetry.io/otel v0.9.0/go.mod h1:ckxzUEfk7tAkTwEMVdkllBM+YOfE/K9iwg6zYntFYSg=
+go.opentelemetry.io/otel v0.10.0 h1:2y/HYj1dIfG1nPh0Z15X4se8WwYWuTyKHLSgRb/mbQ0=
+go.opentelemetry.io/otel v0.10.0/go.mod h1:n3v1JGUBpn5DafiF1UeoDs5fr5XZMG+43kigDtFB8Vk=
+go.opentelemetry.io/otel/sdk v0.10.0 h1:iQWVDfmGB+5TjbrO9yFlezGCWBaJ73vxJTHB+ttdTQk=
+go.opentelemetry.io/otel/sdk v0.10.0/go.mod h1:T5752PMr00aUHAVEbaDAYU5tzM2PWOmyy7Lc5OzSrs8=
 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/version.go b/exporter/metric/version.go
new file mode 100644
index 0000000..3d35bc8
--- /dev/null
+++ b/exporter/metric/version.go
@@ -0,0 +1,21 @@
+// Copyright 2020, Google Inc.
+//
+// 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 metric
+
+// Version is the current release version of the OpenTelemetry
+// Operations Metric Exporter in use.
+func Version() string {
+	return "0.10.0"
+}
diff --git a/exporter/trace/go.mod b/exporter/trace/go.mod
index ee2b1da..0db3365 100644
--- a/exporter/trace/go.mod
+++ b/exporter/trace/go.mod
@@ -7,7 +7,8 @@ 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.8.0
+	go.opentelemetry.io/otel v0.10.0
+	go.opentelemetry.io/otel/sdk v0.10.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
diff --git a/exporter/trace/go.sum b/exporter/trace/go.sum
index 0018cff..5a13be6 100644
--- a/exporter/trace/go.sum
+++ b/exporter/trace/go.sum
@@ -33,8 +33,7 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7 h1:qELHH0AWCvf98Yf+CNIJx9vOZOfHFDDzgDRYsnNk/vs=
-github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60=
+github.com/DataDog/sketches-go v0.0.1/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60=
 github.com/benbjohnson/clock v1.0.3 h1:vkLuvpK4fmtSCuo60+yC63p7y0BmQ8gm5ZXGuBCJyXg=
 github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@@ -87,8 +86,9 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
 github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
-github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
 github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
 github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@@ -134,8 +134,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.8.0 h1:he/8j/EBlKjENVtDvFalawIUcQ+1E3uHRsvJZWLIa7M=
-go.opentelemetry.io/otel v0.8.0/go.mod h1:ckxzUEfk7tAkTwEMVdkllBM+YOfE/K9iwg6zYntFYSg=
+go.opentelemetry.io/otel v0.10.0 h1:2y/HYj1dIfG1nPh0Z15X4se8WwYWuTyKHLSgRb/mbQ0=
+go.opentelemetry.io/otel v0.10.0/go.mod h1:n3v1JGUBpn5DafiF1UeoDs5fr5XZMG+43kigDtFB8Vk=
+go.opentelemetry.io/otel/sdk v0.10.0 h1:iQWVDfmGB+5TjbrO9yFlezGCWBaJ73vxJTHB+ttdTQk=
+go.opentelemetry.io/otel/sdk v0.10.0/go.mod h1:T5752PMr00aUHAVEbaDAYU5tzM2PWOmyy7Lc5OzSrs8=
 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_proto.go b/exporter/trace/trace_proto.go
index 253374d..5a0649c 100644
--- a/exporter/trace/trace_proto.go
+++ b/exporter/trace/trace_proto.go
@@ -28,7 +28,6 @@ import (
 	"google.golang.org/grpc/codes"
 
 	"go.opentelemetry.io/otel/api/kv"
-	"go.opentelemetry.io/otel/api/kv/value"
 	opentelemetry "go.opentelemetry.io/otel/sdk"
 	export "go.opentelemetry.io/otel/sdk/export/trace"
 )
@@ -114,7 +113,10 @@ func protoFromSpanData(s *export.SpanData, projectID string, format DisplayNameF
 		sp.ParentSpanId = s.ParentSpanID.String()
 	}
 	if s.StatusCode != codes.OK {
-		sp.Status = &statuspb.Status{Code: int32(s.StatusCode)}
+		sp.Status = &statuspb.Status{Code: int32(s.StatusCode), Message: s.StatusMessage}
+	}
+	if s.StatusCode == codes.OK && s.StatusMessage != "" {
+		sp.Status = &statuspb.Status{Code: int32(s.StatusCode), Message: s.StatusMessage}
 	}
 
 	copyAttributes(&sp.Attributes, s.Attributes)
@@ -220,25 +222,25 @@ func copyAttributes(out **tracepb.Span_Attributes, in []kv.KeyValue) {
 	(*out).DroppedAttributesCount = dropped
 }
 
-func attributeValue(kv kv.KeyValue) *tracepb.AttributeValue {
-	v := kv.Value
+func attributeValue(keyValue kv.KeyValue) *tracepb.AttributeValue {
+	v := keyValue.Value
 	switch v.Type() {
-	case value.BOOL:
+	case kv.BOOL:
 		return &tracepb.AttributeValue{
 			Value: &tracepb.AttributeValue_BoolValue{BoolValue: v.AsBool()},
 		}
-	case value.INT64:
+	case kv.INT64:
 		return &tracepb.AttributeValue{
 			Value: &tracepb.AttributeValue_IntValue{IntValue: v.AsInt64()},
 		}
-	case value.FLOAT64:
+	case kv.FLOAT64:
 		// TODO: set double value if Google Cloud Trace support it in the future.
 		return &tracepb.AttributeValue{
 			Value: &tracepb.AttributeValue_StringValue{
 				StringValue: trunc(strconv.FormatFloat(v.AsFloat64(), 'f', -1, 64),
 					maxAttributeStringValue)},
 		}
-	case value.STRING:
+	case kv.STRING:
 		return &tracepb.AttributeValue{
 			Value: &tracepb.AttributeValue_StringValue{StringValue: trunc(v.AsString(), maxAttributeStringValue)},
 		}
diff --git a/exporter/trace/version.go b/exporter/trace/version.go
new file mode 100644
index 0000000..c7c2f53
--- /dev/null
+++ b/exporter/trace/version.go
@@ -0,0 +1,21 @@
+// Copyright 2020, Google Inc.
+//
+// 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 trace
+
+// Version is the current release version of the OpenTelemetry
+// Operations Trace Exporter in use.
+func Version() string {
+	return "0.10.0"
+}
diff --git a/get_main_pkgs.sh b/get_main_pkgs.sh
new file mode 100755
index 0000000..25aa14b
--- /dev/null
+++ b/get_main_pkgs.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+
+# Copyright 2020, Google Inc.
+#
+# 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.
+
+set -euo pipefail
+
+top_dir='.'
+if [[ $# -gt 0 ]]; then
+    top_dir="${1}"
+fi
+
+p=$(pwd)
+mod_dirs=()
+mapfile -t mod_dirs < <(find "${top_dir}" -type f -name 'go.mod' -exec dirname {} \; | sort)
+
+for mod_dir in "${mod_dirs[@]}"; do
+    cd "${mod_dir}"
+    main_dirs=()
+    mapfile -t main_dirs < <(go list --find -f '{{.Name}}|{{.Dir}}' ./... | grep '^main|' | cut -f 2- -d '|')
+    for main_dir in "${main_dirs[@]}"; do
+        echo ".${main_dir#${p}}"
+    done
+    cd "${p}"
+done
diff --git a/internal/buildscripts/update-dep b/internal/buildscripts/update-dep
new file mode 100755
index 0000000..cd0a179
--- /dev/null
+++ b/internal/buildscripts/update-dep
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# Updates MODULE inside go.mod if it is already present to version VERSION.
+
+set -e
+
+if grep -q "$MODULE " go.mod; then
+  go get $MODULE@$VERSION
+fi
+
diff --git a/pre_release.sh b/pre_release.sh
new file mode 100755
index 0000000..71fe963
--- /dev/null
+++ b/pre_release.sh
@@ -0,0 +1,100 @@
+#!/bin/bash
+
+# Copyright 2020, Google Inc.
+#
+# 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.
+
+set -e
+
+help()
+{
+   printf "\n"
+   printf "Usage: $0 -t tag\n"
+   printf "\t-t Unreleased tag. Update all go.mod with this tag.\n"
+   exit 1 # Exit script after printing help
+}
+
+while getopts "t:" opt
+do
+   case "$opt" in
+      t ) TAG="$OPTARG" ;;
+      ? ) help ;; # Print help
+   esac
+done
+
+# Print help in case parameters are empty
+if [ -z "$TAG" ]
+then
+   printf "Tag is missing\n";
+   help
+fi
+
+# Validate semver
+SEMVER_REGEX="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(\\-[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?(\\+[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?$"
+if [[ "${TAG}" =~ ${SEMVER_REGEX} ]]; then
+	printf "${TAG} is valid semver tag.\n"
+else
+	printf "${TAG} is not a valid semver tag.\n"
+	exit -1
+fi
+
+TAG_FOUND=`git tag --list ${TAG}`
+if [[ ${TAG_FOUND} = ${TAG} ]] ; then
+        printf "Tag ${TAG} already exists\n"
+        exit -1
+fi
+
+# Get version for exporter/<trace|metric>/version.go
+OTELOPS_VERSION=$(echo "${TAG}" | grep -o '^v[0-9]\+\.[0-9]\+\.[0-9]\+')
+# Strip leading v
+OTELOPS_VERSION="${OTELOPS_VERSION#v}"
+
+cd $(dirname $0)
+
+if ! git diff --quiet; then \
+	printf "Working tree is not clean, can't proceed with the release process\n"
+	git status
+	git diff
+	exit 1
+fi
+
+# Update go.mod
+git checkout -b pre_release_${TAG} master
+PACKAGE_DIRS=$(find . -mindepth 2 -type f -name 'go.mod' -exec dirname {} \; | egrep -v 'tools' | sed 's/^\.\///' | sort)
+
+# Update exporter/trace/version.go
+cp ./exporter/trace/version.go ./exporter/trace/version.go.bak
+sed "s/\(return \"\)[0-9]*\.[0-9]*\.[0-9]*\"/\1${OTELOPS_VERSION}\"/" ./exporter/trace/version.go.bak >./exporter/trace/version.go
+rm -f ./exporter/trace/version.go.bak
+
+# Update exporter/metric/version.go
+cp ./exporter/metric/version.go ./exporter/metric/version.go.bak
+sed "s/\(return \"\)[0-9]*\.[0-9]*\.[0-9]*\"/\1${OTELOPS_VERSION}\"/" ./exporter/metric/version.go.bak >./exporter/metric/version.go
+rm -f ./exporter/metric/version.go.bak
+
+for dir in $PACKAGE_DIRS; do
+	cp "${dir}/go.mod" "${dir}/go.mod.bak"
+	sed "s/GoogleCloudPlatform\/opentelemetry-operations-go\([^ ]*\) v[0-9]*\.[0-9]*\.[0-9]/GoogleCloudPlatform\/opentelemetry-operations-go\1 ${TAG}/" "${dir}/go.mod.bak" >"${dir}/go.mod"
+	rm -f "${dir}/go.mod.bak"
+done
+
+# Run lint to update go.sum
+make lint
+
+# Add changes and commit.
+git add .
+make ci
+git commit -m "Prepare for releasing $TAG"
+
+printf "Now run following to verify the changes.\ngit diff master\n"
+printf "\nThen push the changes to upstream\n"
diff --git a/tag.sh b/tag.sh
new file mode 100755
index 0000000..4e33afd
--- /dev/null
+++ b/tag.sh
@@ -0,0 +1,175 @@
+#!/usr/bin/env bash
+
+# Copyright 2020, Google Inc.
+#
+# 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.
+
+readonly PROGNAME=$(basename "$0")
+readonly PROGDIR=$(pwd)
+
+readonly EXCLUDE_PACKAGES="tools"
+readonly SEMVER_REGEX="v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(\\-[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?(\\+[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?"
+
+usage() {
+    cat <<- EOF
+Usage: $PROGNAME [OPTIONS] SEMVER_TAG COMMIT_HASH
+Creates git tag for all Go packages in project.
+OPTIONS:
+  -h --help        Show this help.
+ARGUMENTS:
+  SEMVER_TAG       Semantic version to tag with.
+  COMMIT_HASH      Git commit hash to tag.
+EOF
+}
+
+cmdline() {
+    local arg commit
+
+    for arg
+    do
+        local delim=""
+        case "$arg" in
+            # Translate long form options to short form.
+            --help)           args="${args}-h ";;
+            # Pass through for everything else.
+            *) [[ "${arg:0:1}" == "-" ]] || delim="\""
+                args="${args}${delim}${arg}${delim} ";;
+        esac
+    done
+
+    # Reset and process short form options.
+    eval set -- "$args"
+
+    while getopts "h" OPTION
+    do
+         case $OPTION in
+         h)
+             usage
+             exit 0
+             ;;
+         *)
+             echo "unknown option: $OPTION"
+             usage
+             exit 1
+             ;;
+        esac
+    done
+
+    # Positional arguments.
+    shift $((OPTIND-1))
+    readonly TAG="$1"
+    if [ -z "$TAG" ]
+    then
+        echo "missing SEMVER_TAG"
+        usage
+        exit 1
+    fi
+    if [[ ! "$TAG" =~ $SEMVER_REGEX ]]
+    then
+        printf "invalid semantic version: %s\n" "$TAG"
+        exit 2
+    fi
+    if [[ "$( git tag --list "$TAG" )" ]]
+    then
+        printf "tag already exists: %s\n" "$TAG"
+        exit 2
+    fi
+
+    shift
+    commit="$1"
+    if [ -z "$commit" ]
+    then
+        echo "missing COMMIT_HASH"
+        usage
+        exit 1
+    fi
+    # Verify rev is for a commit and unify hashes into a complete SHA1.
+    readonly SHA="$( git rev-parse --quiet --verify "${commit}^{commit}" )"
+    if [ -z "$SHA" ]
+    then
+        printf "invalid commit hash: %s\n" "$commit"
+        exit 2
+    fi
+    if [ "$( git merge-base "$SHA" HEAD )" != "$SHA" ]
+    then
+        printf "commit '%s' not found on this branch\n" "$commit"
+        exit 2
+    fi
+}
+
+package_dirs() {
+    # Return a list of package directories in the form:
+    #
+    #  package/directory/a
+    #  package/directory/b
+    #  deeper/package/directory/a
+    #  ...
+    #
+    # Making sure to exclude any packages in the EXCLUDE_PACKAGES regexp.
+    find . -mindepth 2 -type f -name 'go.mod' -exec dirname {} \; \
+        | grep -E -v "$EXCLUDE_PACKAGES" \
+        | sed 's/^\.\///' \
+        | sort
+}
+
+git_tag() {
+    local tag="$1"
+    local commit="$2"
+
+    git tag -a "$tag" -m "Version $tag" "$commit"
+}
+
+previous_version() {
+    local current="$1"
+
+    # Requires git > 2.0
+    git tag -l --sort=v:refname \
+        | grep -E "^${SEMVER_REGEX}$" \
+        | grep -v "$current" \
+        | tail -1
+}
+
+print_changes() {
+    local tag="$1"
+    local previous
+
+    previous="$( previous_version "$tag" )"
+    if [ -n "$previous" ]
+    then
+        printf "\nRaw changes made between %s and %s\n" "$previous" "$tag"
+        printf "======================================\n"
+        git --no-pager log --pretty=oneline "${previous}..$tag"
+    fi
+}
+
+main() {
+    local dir
+
+    cmdline "$@"
+
+    cd "$PROGDIR" || exit 3
+
+    # Create tag for root package.
+    git_tag "$TAG" "$SHA"
+    printf "created tag: %s\n" "$TAG"
+
+    # Create tag for all sub-packages.
+    for dir in $( package_dirs )
+    do
+        git_tag "${dir}/$TAG" "$SHA"
+        printf "created tag: %s\n" "${dir}/$TAG"
+    done
+
+    print_changes "$TAG"
+}
+main "$@"
diff --git a/verify_examples.sh b/verify_examples.sh
new file mode 100755
index 0000000..9196fcd
--- /dev/null
+++ b/verify_examples.sh
@@ -0,0 +1,85 @@
+#!/usr/bin/env bash
+
+# Copyright 2020, Google Inc.
+#
+# 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.
+
+set -euo pipefail
+
+cd $(dirname $0)
+TOOLS_DIR=$(pwd)/.tools
+
+if [ -z "${GOPATH}" ] ; then
+	printf "GOPATH is not defined.\n"
+	exit -1
+fi
+
+if [ ! -d "${GOPATH}" ] ; then
+	printf "GOPATH ${GOPATH} is invalid \n"
+	exit -1
+fi
+
+# Pre-requisites
+if ! git diff --quiet; then \
+	git status
+	printf "\n\nError: working tree is not clean\n"
+	exit -1
+fi
+
+if [ "$(git tag --contains $(git log -1 --pretty=format:"%H"))" = "" ] ; then
+	printf "$(git log -1)"
+	printf "\n\nError: HEAD is not pointing to a tagged version"
+fi
+
+make ${TOOLS_DIR}/gojq
+
+DIR_TMP="${GOPATH}/src/otelopstmp/"
+rm -rf $DIR_TMP
+mkdir -p $DIR_TMP
+
+printf "Copy examples to ${DIR_TMP}\n"
+cp -a ./example ${DIR_TMP}
+
+# Update go.mod files
+printf "Update go.mod: rename module and remove replace\n"
+
+PACKAGE_DIRS=$(find . -mindepth 2 -type f -name 'go.mod' -exec dirname {} \; | egrep 'example' | sed 's/^\.\///' | sort)
+
+for dir in $PACKAGE_DIRS; do
+	printf "  Update go.mod for $dir\n"
+	(cd "${DIR_TMP}/${dir}" && \
+	 # replaces is ("mod1" "mod2" …)
+	 replaces=($(go mod edit -json | ${TOOLS_DIR}/gojq '.Replace[].Old.Path')) && \
+	 # strip double quotes
+	 replaces=("${replaces[@]%\"}") && \
+	 replaces=("${replaces[@]#\"}") && \
+	 # make an array (-dropreplace=mod1 -dropreplace=mod2 …)
+	 dropreplaces=("${replaces[@]/#/-dropreplace=}") && \
+	 go mod edit -module "oteltmp/${dir}" "${dropreplaces[@]}" && \
+	 go mod tidy)
+done
+printf "Update done:\n\n"
+
+# Build directories that contain main package. These directories are different than
+# directories that contain go.mod files.
+printf "Build examples:\n"
+EXAMPLES=$(./get_main_pkgs.sh ./example)
+for ex in $EXAMPLES; do
+	printf "  Build $ex in ${DIR_TMP}/${ex}\n"
+	(cd "${DIR_TMP}/${ex}" && \
+	 go build .)
+done
+
+# Cleanup
+printf "Remove copied files.\n"
+rm -rf $DIR_TMP


Test patch:
diff --git a/exporter/metric/metric_test.go b/exporter/metric/metric_test.go
index ce4e7a9..ad1ee38 100644
--- a/exporter/metric/metric_test.go
+++ b/exporter/metric/metric_test.go
@@ -25,10 +25,10 @@ import (
 	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/metric"
 	apimetric "go.opentelemetry.io/otel/api/metric"
-	"go.opentelemetry.io/otel/exporters/metric/test"
 	export "go.opentelemetry.io/otel/sdk/export/metric"
+	"go.opentelemetry.io/otel/sdk/export/metric/metrictest"
+	aggtest "go.opentelemetry.io/otel/sdk/metric/aggregator/aggregatortest"
 	"go.opentelemetry.io/otel/sdk/metric/aggregator/lastvalue"
-	aggtest "go.opentelemetry.io/otel/sdk/metric/aggregator/test"
 	"go.opentelemetry.io/otel/sdk/metric/controller/push"
 	"go.opentelemetry.io/otel/sdk/resource"
 
@@ -48,7 +48,7 @@ func TestExportMetrics(t *testing.T) {
 
 	clientOpt := option.WithGRPCConn(cloudMock.ClientConn())
 	res := &resource.Resource{}
-	cps := test.NewCheckpointSet(res)
+	cps := metrictest.NewCheckpointSet(res)
 	ctx := context.Background()
 	desc := apimetric.NewDescriptor("testing", apimetric.ValueRecorderKind, apimetric.Float64NumberKind)
 
@@ -138,7 +138,7 @@ func TestDescToMetricType(t *testing.T) {
 
 func TestRecordToMpb(t *testing.T) {
 	res := &resource.Resource{}
-	cps := test.NewCheckpointSet(res)
+	cps := metrictest.NewCheckpointSet(res)
 	ctx := context.Background()
 
 	desc := apimetric.NewDescriptor("testing", apimetric.ValueRecorderKind, apimetric.Float64NumberKind)
diff --git a/exporter/trace/cloudtrace_test.go b/exporter/trace/cloudtrace_test.go
index 5ddc00b..01a51a9 100644
--- a/exporter/trace/cloudtrace_test.go
+++ b/exporter/trace/cloudtrace_test.go
@@ -21,6 +21,8 @@ import (
 	"testing"
 	"time"
 
+	"google.golang.org/grpc/codes"
+
 	"github.com/googleinterns/cloud-operations-api-mock/cloudmock"
 	"github.com/stretchr/testify/assert"
 
@@ -53,12 +55,19 @@ func TestExporter_ExportSpan(t *testing.T) {
 	assert.NoError(t, err)
 
 	_, span := global.TraceProvider().Tracer("test-tracer").Start(context.Background(), "test-span")
+	span.SetStatus(codes.OK, "Status Message")
 	span.End()
 	assert.True(t, span.SpanContext().IsValid())
 
+	_, span = global.TraceProvider().Tracer("test-tracer").Start(context.Background(), "test-span-with-error-status")
+	span.SetStatus(codes.NotFound, "Error Message")
+	span.End()
+
 	// wait exporter to flush
 	flush()
-	assert.EqualValues(t, 1, mock.GetNumSpans())
+	assert.EqualValues(t, 2, mock.GetNumSpans())
+	assert.EqualValues(t, "Status Message", mock.GetSpan(0).GetStatus().Message)
+	assert.EqualValues(t, "Error Message", mock.GetSpan(1).GetStatus().Message)
 }
 
 func TestExporter_DisplayNameFormatter(t *testing.T) {