From a4b690e8a4e30acb3e0b6e94727c56bc3390409d Mon Sep 17 00:00:00 2001
From: ale <ale@incal.net>
Date: Sun, 18 Nov 2018 17:15:16 +0000
Subject: [PATCH] Upgrade go-common (add tracing)

---
 .../ai3/go-common/clientutil/transport.go     |   6 +-
 .../ai3/go-common/serverutil/http.go          |  26 +-
 .../ai3/go-common/tracing/tracing.go          | 130 +++++
 .../github.com/openzipkin/zipkin-go/LICENSE   | 201 +++++++
 .../github.com/openzipkin/zipkin-go/Makefile  |  28 +
 .../github.com/openzipkin/zipkin-go/README.md |  79 +++
 .../openzipkin/zipkin-go/appveyor.yml         |  21 +
 .../openzipkin/zipkin-go/circle.yml           |  11 +
 .../openzipkin/zipkin-go/context.go           |  23 +
 vendor/github.com/openzipkin/zipkin-go/doc.go |   6 +
 .../openzipkin/zipkin-go/endpoint.go          |  66 +++
 .../zipkin-go/idgenerator/idgenerator.go      | 116 ++++
 .../openzipkin/zipkin-go/model/annotation.go  |  46 ++
 .../openzipkin/zipkin-go/model/doc.go         |   9 +
 .../openzipkin/zipkin-go/model/endpoint.go    |  17 +
 .../openzipkin/zipkin-go/model/kind.go        |  13 +
 .../openzipkin/zipkin-go/model/span.go        | 124 +++++
 .../openzipkin/zipkin-go/model/span_id.go     |  30 +
 .../openzipkin/zipkin-go/model/traceid.go     |  61 +++
 .../github.com/openzipkin/zipkin-go/noop.go   |  25 +
 .../zipkin-go/propagation/propagation.go      |  16 +
 .../zipkin-go/reporter/http/http.go           | 218 ++++++++
 .../openzipkin/zipkin-go/reporter/reporter.go |  27 +
 .../github.com/openzipkin/zipkin-go/sample.go | 113 ++++
 .../github.com/openzipkin/zipkin-go/span.go   |  38 ++
 .../zipkin-go/span_implementation.go          |  78 +++
 .../openzipkin/zipkin-go/span_options.go      |  74 +++
 .../github.com/openzipkin/zipkin-go/tags.go   |  23 +
 .../github.com/openzipkin/zipkin-go/tracer.go | 173 ++++++
 .../openzipkin/zipkin-go/tracer_options.go    | 124 +++++
 vendor/go.opencensus.io/AUTHORS               |   1 +
 vendor/go.opencensus.io/CONTRIBUTING.md       |  56 ++
 vendor/go.opencensus.io/Gopkg.lock            | 231 ++++++++
 vendor/go.opencensus.io/Gopkg.toml            |  36 ++
 vendor/go.opencensus.io/LICENSE               | 202 +++++++
 vendor/go.opencensus.io/README.md             | 263 +++++++++
 vendor/go.opencensus.io/appveyor.yml          |  24 +
 vendor/go.opencensus.io/exemplar/exemplar.go  |  78 +++
 .../exporter/zipkin/zipkin.go                 | 194 +++++++
 vendor/go.opencensus.io/go.mod                |  25 +
 vendor/go.opencensus.io/go.sum                |  48 ++
 vendor/go.opencensus.io/internal/internal.go  |  37 ++
 vendor/go.opencensus.io/internal/sanitize.go  |  50 ++
 .../internal/tagencoding/tagencoding.go       |  72 +++
 .../internal/traceinternals.go                |  52 ++
 vendor/go.opencensus.io/opencensus.go         |  21 +
 .../go.opencensus.io/plugin/ochttp/client.go  | 117 ++++
 .../plugin/ochttp/client_stats.go             | 135 +++++
 vendor/go.opencensus.io/plugin/ochttp/doc.go  |  19 +
 .../plugin/ochttp/propagation/b3/b3.go        | 123 +++++
 .../go.opencensus.io/plugin/ochttp/route.go   |  51 ++
 .../go.opencensus.io/plugin/ochttp/server.go  | 440 +++++++++++++++
 .../ochttp/span_annotating_client_trace.go    | 169 ++++++
 .../go.opencensus.io/plugin/ochttp/stats.go   | 265 +++++++++
 .../go.opencensus.io/plugin/ochttp/trace.go   | 228 ++++++++
 vendor/go.opencensus.io/stats/doc.go          |  69 +++
 .../go.opencensus.io/stats/internal/record.go |  25 +
 .../stats/internal/validation.go              |  28 +
 vendor/go.opencensus.io/stats/measure.go      | 123 +++++
 .../go.opencensus.io/stats/measure_float64.go |  36 ++
 .../go.opencensus.io/stats/measure_int64.go   |  36 ++
 vendor/go.opencensus.io/stats/record.go       |  69 +++
 vendor/go.opencensus.io/stats/units.go        |  25 +
 .../stats/view/aggregation.go                 | 120 ++++
 .../stats/view/aggregation_data.go            | 235 ++++++++
 .../go.opencensus.io/stats/view/collector.go  |  87 +++
 vendor/go.opencensus.io/stats/view/doc.go     |  47 ++
 vendor/go.opencensus.io/stats/view/export.go  |  58 ++
 vendor/go.opencensus.io/stats/view/view.go    | 185 +++++++
 vendor/go.opencensus.io/stats/view/worker.go  | 229 ++++++++
 .../stats/view/worker_commands.go             | 183 +++++++
 vendor/go.opencensus.io/tag/context.go        |  67 +++
 vendor/go.opencensus.io/tag/doc.go            |  26 +
 vendor/go.opencensus.io/tag/key.go            |  35 ++
 vendor/go.opencensus.io/tag/map.go            | 197 +++++++
 vendor/go.opencensus.io/tag/map_codec.go      | 234 ++++++++
 vendor/go.opencensus.io/tag/profile_19.go     |  31 ++
 vendor/go.opencensus.io/tag/profile_not19.go  |  23 +
 vendor/go.opencensus.io/tag/validate.go       |  56 ++
 vendor/go.opencensus.io/trace/basetypes.go    | 114 ++++
 vendor/go.opencensus.io/trace/config.go       |  48 ++
 vendor/go.opencensus.io/trace/doc.go          |  53 ++
 vendor/go.opencensus.io/trace/exemplar.go     |  43 ++
 vendor/go.opencensus.io/trace/export.go       |  90 +++
 .../trace/internal/internal.go                |  21 +
 .../trace/propagation/propagation.go          | 108 ++++
 vendor/go.opencensus.io/trace/sampling.go     |  75 +++
 vendor/go.opencensus.io/trace/spanbucket.go   | 130 +++++
 vendor/go.opencensus.io/trace/spanstore.go    | 306 +++++++++++
 vendor/go.opencensus.io/trace/status_codes.go |  37 ++
 vendor/go.opencensus.io/trace/trace.go        | 516 ++++++++++++++++++
 vendor/go.opencensus.io/trace/trace_go11.go   |  32 ++
 .../go.opencensus.io/trace/trace_nongo11.go   |  25 +
 .../trace/tracestate/tracestate.go            | 147 +++++
 vendor/vendor.json                            | 148 ++++-
 95 files changed, 8963 insertions(+), 13 deletions(-)
 create mode 100644 vendor/git.autistici.org/ai3/go-common/tracing/tracing.go
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/LICENSE
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/Makefile
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/README.md
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/appveyor.yml
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/circle.yml
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/context.go
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/doc.go
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/endpoint.go
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/idgenerator/idgenerator.go
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/model/annotation.go
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/model/doc.go
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/model/endpoint.go
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/model/kind.go
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/model/span.go
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/model/span_id.go
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/model/traceid.go
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/noop.go
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/propagation/propagation.go
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/reporter/http/http.go
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/reporter/reporter.go
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/sample.go
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/span.go
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/span_implementation.go
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/span_options.go
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/tags.go
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/tracer.go
 create mode 100644 vendor/github.com/openzipkin/zipkin-go/tracer_options.go
 create mode 100644 vendor/go.opencensus.io/AUTHORS
 create mode 100644 vendor/go.opencensus.io/CONTRIBUTING.md
 create mode 100644 vendor/go.opencensus.io/Gopkg.lock
 create mode 100644 vendor/go.opencensus.io/Gopkg.toml
 create mode 100644 vendor/go.opencensus.io/LICENSE
 create mode 100644 vendor/go.opencensus.io/README.md
 create mode 100644 vendor/go.opencensus.io/appveyor.yml
 create mode 100644 vendor/go.opencensus.io/exemplar/exemplar.go
 create mode 100644 vendor/go.opencensus.io/exporter/zipkin/zipkin.go
 create mode 100644 vendor/go.opencensus.io/go.mod
 create mode 100644 vendor/go.opencensus.io/go.sum
 create mode 100644 vendor/go.opencensus.io/internal/internal.go
 create mode 100644 vendor/go.opencensus.io/internal/sanitize.go
 create mode 100644 vendor/go.opencensus.io/internal/tagencoding/tagencoding.go
 create mode 100644 vendor/go.opencensus.io/internal/traceinternals.go
 create mode 100644 vendor/go.opencensus.io/opencensus.go
 create mode 100644 vendor/go.opencensus.io/plugin/ochttp/client.go
 create mode 100644 vendor/go.opencensus.io/plugin/ochttp/client_stats.go
 create mode 100644 vendor/go.opencensus.io/plugin/ochttp/doc.go
 create mode 100644 vendor/go.opencensus.io/plugin/ochttp/propagation/b3/b3.go
 create mode 100644 vendor/go.opencensus.io/plugin/ochttp/route.go
 create mode 100644 vendor/go.opencensus.io/plugin/ochttp/server.go
 create mode 100644 vendor/go.opencensus.io/plugin/ochttp/span_annotating_client_trace.go
 create mode 100644 vendor/go.opencensus.io/plugin/ochttp/stats.go
 create mode 100644 vendor/go.opencensus.io/plugin/ochttp/trace.go
 create mode 100644 vendor/go.opencensus.io/stats/doc.go
 create mode 100644 vendor/go.opencensus.io/stats/internal/record.go
 create mode 100644 vendor/go.opencensus.io/stats/internal/validation.go
 create mode 100644 vendor/go.opencensus.io/stats/measure.go
 create mode 100644 vendor/go.opencensus.io/stats/measure_float64.go
 create mode 100644 vendor/go.opencensus.io/stats/measure_int64.go
 create mode 100644 vendor/go.opencensus.io/stats/record.go
 create mode 100644 vendor/go.opencensus.io/stats/units.go
 create mode 100644 vendor/go.opencensus.io/stats/view/aggregation.go
 create mode 100644 vendor/go.opencensus.io/stats/view/aggregation_data.go
 create mode 100644 vendor/go.opencensus.io/stats/view/collector.go
 create mode 100644 vendor/go.opencensus.io/stats/view/doc.go
 create mode 100644 vendor/go.opencensus.io/stats/view/export.go
 create mode 100644 vendor/go.opencensus.io/stats/view/view.go
 create mode 100644 vendor/go.opencensus.io/stats/view/worker.go
 create mode 100644 vendor/go.opencensus.io/stats/view/worker_commands.go
 create mode 100644 vendor/go.opencensus.io/tag/context.go
 create mode 100644 vendor/go.opencensus.io/tag/doc.go
 create mode 100644 vendor/go.opencensus.io/tag/key.go
 create mode 100644 vendor/go.opencensus.io/tag/map.go
 create mode 100644 vendor/go.opencensus.io/tag/map_codec.go
 create mode 100644 vendor/go.opencensus.io/tag/profile_19.go
 create mode 100644 vendor/go.opencensus.io/tag/profile_not19.go
 create mode 100644 vendor/go.opencensus.io/tag/validate.go
 create mode 100644 vendor/go.opencensus.io/trace/basetypes.go
 create mode 100644 vendor/go.opencensus.io/trace/config.go
 create mode 100644 vendor/go.opencensus.io/trace/doc.go
 create mode 100644 vendor/go.opencensus.io/trace/exemplar.go
 create mode 100644 vendor/go.opencensus.io/trace/export.go
 create mode 100644 vendor/go.opencensus.io/trace/internal/internal.go
 create mode 100644 vendor/go.opencensus.io/trace/propagation/propagation.go
 create mode 100644 vendor/go.opencensus.io/trace/sampling.go
 create mode 100644 vendor/go.opencensus.io/trace/spanbucket.go
 create mode 100644 vendor/go.opencensus.io/trace/spanstore.go
 create mode 100644 vendor/go.opencensus.io/trace/status_codes.go
 create mode 100644 vendor/go.opencensus.io/trace/trace.go
 create mode 100644 vendor/go.opencensus.io/trace/trace_go11.go
 create mode 100644 vendor/go.opencensus.io/trace/trace_nongo11.go
 create mode 100644 vendor/go.opencensus.io/trace/tracestate/tracestate.go

diff --git a/vendor/git.autistici.org/ai3/go-common/clientutil/transport.go b/vendor/git.autistici.org/ai3/go-common/clientutil/transport.go
index 843a760..1cc6c6d 100644
--- a/vendor/git.autistici.org/ai3/go-common/clientutil/transport.go
+++ b/vendor/git.autistici.org/ai3/go-common/clientutil/transport.go
@@ -7,6 +7,8 @@ import (
 	"net/http"
 	"sync"
 	"time"
+
+	"git.autistici.org/ai3/go-common/tracing"
 )
 
 // The transportCache is just a cache of http transports, each
@@ -29,12 +31,12 @@ func newTransportCache(tlsConfig *tls.Config) *transportCache {
 }
 
 func (m *transportCache) newTransport(addr string) http.RoundTripper {
-	return &http.Transport{
+	return tracing.WrapTransport(&http.Transport{
 		TLSClientConfig: m.tlsConfig,
 		DialContext: func(ctx context.Context, network, _ string) (net.Conn, error) {
 			return netDialContext(ctx, network, addr)
 		},
-	}
+	})
 }
 
 func (m *transportCache) getTransport(addr string) http.RoundTripper {
diff --git a/vendor/git.autistici.org/ai3/go-common/serverutil/http.go b/vendor/git.autistici.org/ai3/go-common/serverutil/http.go
index 09cc9bb..604ca98 100644
--- a/vendor/git.autistici.org/ai3/go-common/serverutil/http.go
+++ b/vendor/git.autistici.org/ai3/go-common/serverutil/http.go
@@ -3,16 +3,18 @@ package serverutil
 import (
 	"context"
 	"crypto/tls"
+	"fmt"
 	"io"
 	"log"
 	"net"
 	"net/http"
-	"net/http/pprof"
+	_ "net/http/pprof"
 	"os"
 	"os/signal"
 	"syscall"
 	"time"
 
+	"git.autistici.org/ai3/go-common/tracing"
 	"github.com/coreos/go-systemd/daemon"
 	"github.com/prometheus/client_golang/prometheus"
 	"github.com/prometheus/client_golang/prometheus/promhttp"
@@ -77,6 +79,10 @@ func (config *ServerConfig) buildHTTPServer(h http.Handler) (*http.Server, error
 // the listener, otherwise it will handle graceful termination on
 // SIGINT or SIGTERM and return nil.
 func Serve(h http.Handler, config *ServerConfig, addr string) error {
+	// Wrap with tracing handler (exclude metrics and other
+	// debugging endpoints).
+	h = tracing.WrapHandler(h, guessEndpointName(addr))
+
 	// Create the HTTP server.
 	srv, err := config.buildHTTPServer(h)
 	if err != nil {
@@ -139,8 +145,10 @@ func defaultHandler(h http.Handler) http.Handler {
 	// Add an endpoint to serve Prometheus metrics.
 	root.Handle("/metrics", promhttp.Handler())
 
-	// Add the net/http/pprof debug handlers.
-	root.Handle("/debug/pprof/", pprof.Handler(""))
+	// Let the default net/http handler deal with /debug/
+	// URLs. Packages such as net/http/pprof register their
+	// handlers there in ways that aren't reproducible.
+	root.Handle("/debug/", http.DefaultServeMux)
 
 	// Forward everything else to the main handler, adding
 	// Prometheus instrumentation (requests to /metrics and
@@ -151,6 +159,18 @@ func defaultHandler(h http.Handler) http.Handler {
 	return root
 }
 
+func guessEndpointName(addr string) string {
+	_, port, err := net.SplitHostPort(addr)
+	if err != nil {
+		return addr
+	}
+	host, err := os.Hostname()
+	if err != nil {
+		return addr
+	}
+	return fmt.Sprintf("%s:%s", host, port)
+}
+
 // HTTP-related metrics.
 var (
 	// Since we instrument the root HTTP handler, we don't really
diff --git a/vendor/git.autistici.org/ai3/go-common/tracing/tracing.go b/vendor/git.autistici.org/ai3/go-common/tracing/tracing.go
new file mode 100644
index 0000000..df6144b
--- /dev/null
+++ b/vendor/git.autistici.org/ai3/go-common/tracing/tracing.go
@@ -0,0 +1,130 @@
+package tracing
+
+import (
+	"encoding/json"
+	"errors"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"os"
+	"path/filepath"
+	"sync"
+
+	openzipkin "github.com/openzipkin/zipkin-go"
+	zipkinHTTP "github.com/openzipkin/zipkin-go/reporter/http"
+	"go.opencensus.io/exporter/zipkin"
+	"go.opencensus.io/plugin/ochttp"
+	"go.opencensus.io/trace"
+)
+
+var (
+	// Enabled reports whether tracing is globally enabled or not.
+	Enabled bool
+
+	// The active tracing configuration, if Enabled is true.
+	config tracingConfig
+
+	initOnce sync.Once
+)
+
+const globalTracingConfigPath = "/etc/tracing/client.conf"
+
+type tracingConfig struct {
+	ReportURL string `json:"report_url"`
+}
+
+// Read the global tracing configuration file. Its location is
+// hardcoded, but it can be overriden using the TRACING_CONFIG
+// environment variable.
+func readTracingConfig() error {
+	// Read and decode configuration.
+	cfgPath := globalTracingConfigPath
+	if s := os.Getenv("TRACING_CONFIG"); s != "" {
+		cfgPath = s
+	}
+	data, err := ioutil.ReadFile(cfgPath)
+	if err != nil {
+		return err
+	}
+
+	if err := json.Unmarshal(data, &config); err != nil {
+		log.Printf("warning: error in tracing configuration: %v, tracing disabled", err)
+		return err
+	}
+
+	if config.ReportURL == "" {
+		log.Printf("warning: tracing configuration contains no report_url, tracing disabled")
+		return errors.New("no report_url")
+	}
+
+	return nil
+}
+
+// Compute the service name for Zipkin: this is usually the program
+// name (without path), but it can be overriden by the TRACING_SERVICE
+// environment variable.
+func getServiceName() string {
+	if s := os.Getenv("TRACING_SERVICE"); s != "" {
+		return s
+	}
+	return filepath.Base(os.Args[0])
+}
+
+// Initialize tracing. Tracing will be enabled if the system-wide
+// tracing configuration file is present and valid. Explicitly set
+// TRACING_ENABLE=0 in the environment to disable tracing.
+//
+// We need to check the configuration as soon as possible, because
+// it's likely that client transports are created before HTTP servers,
+// and we need to wrap them with opencensus at creation time.
+func init() {
+	// Kill switch from environment.
+	if s := os.Getenv("TRACING_ENABLE"); s == "0" {
+		return
+	}
+
+	if err := readTracingConfig(); err != nil {
+		return
+	}
+
+	Enabled = true
+}
+
+func initTracing(endpointAddr string) {
+	initOnce.Do(func() {
+		localEndpoint, err := openzipkin.NewEndpoint(getServiceName(), endpointAddr)
+		if err != nil {
+			log.Printf("warning: error creating tracing endpoint: %v, tracing disabled", err)
+			return
+		}
+
+		reporter := zipkinHTTP.NewReporter(config.ReportURL)
+		ze := zipkin.NewExporter(reporter, localEndpoint)
+
+		trace.RegisterExporter(ze)
+		trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
+
+		log.Printf("tracing enabled (report_url %s)", config.ReportURL)
+
+		Enabled = true
+	})
+}
+
+// WrapTransport optionally wraps a http.RoundTripper with OpenCensus
+// tracing functionality, if it is globally enabled.
+func WrapTransport(t http.RoundTripper) http.RoundTripper {
+	if Enabled {
+		t = &ochttp.Transport{Base: t}
+	}
+	return t
+}
+
+// WrapHandler wraps a http.Handler with OpenCensus tracing
+// functionality, if globally enabled.
+func WrapHandler(h http.Handler, endpointAddr string) http.Handler {
+	if Enabled {
+		initTracing(endpointAddr)
+		h = &ochttp.Handler{Handler: h}
+	}
+	return h
+}
diff --git a/vendor/github.com/openzipkin/zipkin-go/LICENSE b/vendor/github.com/openzipkin/zipkin-go/LICENSE
new file mode 100644
index 0000000..2ff7224
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/LICENSE
@@ -0,0 +1,201 @@
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction,
+and distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by
+the copyright owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all
+other entities that control, are controlled by, or are under common
+control with that entity. For the purposes of this definition,
+"control" means (i) the power, direct or indirect, to cause the
+direction or management of such entity, whether by contract or
+otherwise, or (ii) ownership of fifty percent (50%) or more of the
+outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity
+exercising permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications,
+including but not limited to software source code, documentation
+source, and configuration files.
+
+"Object" form shall mean any form resulting from mechanical
+transformation or translation of a Source form, including but
+not limited to compiled object code, generated documentation,
+and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or
+Object form, made available under the License, as indicated by a
+copyright notice that is included in or attached to the work
+(an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object
+form, that is based on (or derived from) the Work and for which the
+editorial revisions, annotations, elaborations, or other modifications
+represent, as a whole, an original work of authorship. For the purposes
+of this License, Derivative Works shall not include works that remain
+separable from, or merely link (or bind by name) to the interfaces of,
+the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including
+the original version of the Work and any modifications or additions
+to that Work or Derivative Works thereof, that is intentionally
+submitted to Licensor for inclusion in the Work by the copyright owner
+or by an individual or Legal Entity authorized to submit on behalf of
+the copyright owner. For the purposes of this definition, "submitted"
+means any form of electronic, verbal, or written communication sent
+to the Licensor or its representatives, including but not limited to
+communication on electronic mailing lists, source code control systems,
+and issue tracking systems that are managed by, or on behalf of, the
+Licensor for the purpose of discussing and improving the Work, but
+excluding communication that is conspicuously marked or otherwise
+designated in writing by the copyright owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity
+on behalf of whom a Contribution has been received by Licensor and
+subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+this License, each Contributor hereby grants to You a perpetual,
+worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+copyright license to reproduce, prepare Derivative Works of,
+publicly display, publicly perform, sublicense, and distribute the
+Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+this License, each Contributor hereby grants to You a perpetual,
+worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+(except as stated in this section) patent license to make, have made,
+use, offer to sell, sell, import, and otherwise transfer the Work,
+where such license applies only to those patent claims licensable
+by such Contributor that are necessarily infringed by their
+Contribution(s) alone or by combination of their Contribution(s)
+with the Work to which such Contribution(s) was submitted. If You
+institute patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Work
+or a Contribution incorporated within the Work constitutes direct
+or contributory patent infringement, then any patent licenses
+granted to You under this License for that Work shall terminate
+as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+Work or Derivative Works thereof in any medium, with or without
+modifications, and in Source or Object form, provided that You
+meet the following conditions:
+
+(a) You must give any other recipients of the Work or
+Derivative Works a copy of this License; and
+
+(b) You must cause any modified files to carry prominent notices
+stating that You changed the files; and
+
+(c) You must retain, in the Source form of any Derivative Works
+that You distribute, all copyright, patent, trademark, and
+attribution notices from the Source form of the Work,
+excluding those notices that do not pertain to any part of
+the Derivative Works; and
+
+(d) If the Work includes a "NOTICE" text file as part of its
+distribution, then any Derivative Works that You distribute must
+include a readable copy of the attribution notices contained
+within such NOTICE file, excluding those notices that do not
+pertain to any part of the Derivative Works, in at least one
+of the following places: within a NOTICE text file distributed
+as part of the Derivative Works; within the Source form or
+documentation, if provided along with the Derivative Works; or,
+within a display generated by the Derivative Works, if and
+wherever such third-party notices normally appear. The contents
+of the NOTICE file are for informational purposes only and
+do not modify the License. You may add Your own attribution
+notices within Derivative Works that You distribute, alongside
+or as an addendum to the NOTICE text from the Work, provided
+that such additional attribution notices cannot be construed
+as modifying the License.
+
+You may add Your own copyright statement to Your modifications and
+may provide additional or different license terms and conditions
+for use, reproduction, or distribution of Your modifications, or
+for any such Derivative Works as a whole, provided Your use,
+reproduction, and distribution of the Work otherwise complies with
+the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+any Contribution intentionally submitted for inclusion in the Work
+by You to the Licensor shall be under the terms and conditions of
+this License, without any additional terms or conditions.
+Notwithstanding the above, nothing herein shall supersede or modify
+the terms of any separate license agreement you may have executed
+with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+names, trademarks, service marks, or product names of the Licensor,
+except as required for reasonable and customary use in describing the
+origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+agreed to in writing, Licensor provides the Work (and each
+Contributor provides its Contributions) on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+implied, including, without limitation, any warranties or conditions
+of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+PARTICULAR PURPOSE. You are solely responsible for determining the
+appropriateness of using or redistributing the Work and assume any
+risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+whether in tort (including negligence), contract, or otherwise,
+unless required by applicable law (such as deliberate and grossly
+negligent acts) or agreed to in writing, shall any Contributor be
+liable to You for damages, including any direct, indirect, special,
+incidental, or consequential damages of any character arising as a
+result of this License or out of the use or inability to use the
+Work (including but not limited to damages for loss of goodwill,
+work stoppage, computer failure or malfunction, or any and all
+other commercial damages or losses), even if such Contributor
+has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+the Work or Derivative Works thereof, You may choose to offer,
+and charge a fee for, acceptance of support, warranty, indemnity,
+or other liability obligations and/or rights consistent with this
+License. However, in accepting such obligations, You may act only
+on Your own behalf and on Your sole responsibility, not on behalf
+of any other Contributor, and only if You agree to indemnify,
+defend, and hold each Contributor harmless for any liability
+incurred by, or claims asserted against, such Contributor by reason
+of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+To apply the Apache License to your work, attach the following
+boilerplate notice, with the fields enclosed by brackets "{}"
+replaced with your own identifying information. (Don't include
+the brackets!)  The text should be enclosed in the appropriate
+comment syntax for the file format. We also recommend that a
+file or class name and description of purpose be included on the
+same "printed page" as the copyright notice for easier
+identification within third-party archives.
+
+Copyright 2017 The OpenZipkin 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.
diff --git a/vendor/github.com/openzipkin/zipkin-go/Makefile b/vendor/github.com/openzipkin/zipkin-go/Makefile
new file mode 100644
index 0000000..bfee671
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/Makefile
@@ -0,0 +1,28 @@
+
+.DEFAULT_GOAL := test
+
+.PHONY: test
+test:
+	go test -v -race -cover ./...
+
+.PHONY: bench
+bench:
+	go test -v -run - -bench . -benchmem ./...
+
+.PHONY: protoc
+protoc:
+	protoc --go_out=. proto/v2/zipkin.proto
+
+.PHONY: lint
+lint:
+	# Ignore grep's exit code since no match returns 1.
+	-if [[ ! $TRAVIS_GO_VERSION = 1.8* ]]; then echo 'linting...' ; golint ./... ; fi
+
+.PHONY: vet
+vet:
+	go vet ./...
+
+.PHONY: all
+all: vet lint test bench
+
+.PHONY: example
diff --git a/vendor/github.com/openzipkin/zipkin-go/README.md b/vendor/github.com/openzipkin/zipkin-go/README.md
new file mode 100644
index 0000000..8ebf387
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/README.md
@@ -0,0 +1,79 @@
+# Zipkin Library for Go
+
+[![Travis CI](https://travis-ci.org/openzipkin/zipkin-go.svg?branch=master)](https://travis-ci.org/openzipkin/zipkin-go)
+[![CircleCI](https://circleci.com/gh/openzipkin/zipkin-go.svg?style=shield)](https://circleci.com/gh/openzipkin/zipkin-go)
+[![Appveyor CI](https://ci.appveyor.com/api/projects/status/1d0e5k96g10ajl63/branch/master?svg=true)](https://ci.appveyor.com/project/basvanbeek/zipkin-go)
+[![Coverage Status](https://img.shields.io/coveralls/github/openzipkin/zipkin-go.svg)](https://coveralls.io/github/openzipkin/zipkin-go?branch=master)
+[![Go Report Card](https://goreportcard.com/badge/github.com/openzipkin/zipkin-go)](https://goreportcard.com/report/github.com/openzipkin/zipkin-go)
+[![GoDoc](https://godoc.org/github.com/openzipkin/zipkin-go?status.svg)](https://godoc.org/github.com/openzipkin/zipkin-go)
+[![Gitter chat](https://badges.gitter.im/openzipkin/zipkin.svg)](https://gitter.im/openzipkin/zipkin?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+[![Sourcegraph](https://sourcegraph.com/github.com/openzipkin/zipkin-go/-/badge.svg)](https://sourcegraph.com/github.com/openzipkin/zipkin-go?badge)
+
+Zipkin Go is the official Go Tracer implementation for Zipkin, supported by the
+OpenZipkin community.
+
+## package organization
+`zipkin-go` is built with interoperability in mind within the OpenZipkin
+community and even 3rd parties, the library consists of several packages.
+
+The main tracing implementation can be found in the root folder of this
+repository. Reusable parts not considered core implementation or deemed
+beneficiary for usage by others are placed in their own packages within this
+repository.
+
+### model
+This library implements the Zipkin V2 Span Model which is available in the model
+package. It contains a Go data model compatible with the Zipkin V2 API and can
+automatically sanitize, parse and (de)serialize to and from the required JSON
+representation as used by the official Zipkin V2 Collectors.
+
+### propagation
+The propagation package and B3 subpackage hold the logic for propagating
+SpanContext (span identifiers and sampling flags) between services participating
+in traces. Currently Zipkin B3 Propagation is supported for HTTP and GRPC.
+
+### middleware
+The middleware subpackages contain officially supported middleware handlers and
+tracing wrappers.
+
+#### http
+An easy to use http.Handler middleware for tracing server side requests is
+provided. This allows one to use this middleware in applications using
+standard library servers as well as most available higher level frameworks. Some
+frameworks will have their own instrumentation and middleware that maps better
+for their ecosystem.
+
+For HTTP client operations `NewTransport` can return a `http.RoundTripper`
+implementation that can either wrap the standard http.Client's Transport or a
+custom provided one and add per request tracing. Since HTTP Requests can have
+one or multiple redirects it is advisable to always enclose HTTP Client calls
+with a `Span` either around the `*http.Client` call level or parent function
+level.
+
+For convenience `NewClient` is provided which returns a HTTP Client which embeds
+`*http.Client` and provides an `application span` around the HTTP calls when
+calling the `DoWithAppSpan()` method.
+
+#### grpc
+gRPC middleware / interceptors are planned for the near future.
+
+### reporter
+The reporter package holds the interface which the various Reporter
+implementations use. It is exported into its own package as it can be used by
+3rd parties to use these Reporter packages in their own libraries for exporting
+to the Zipkin ecosystem. The `zipkin-go` tracer also uses the interface to
+accept 3rd party Reporter implementations.
+
+#### HTTP Reporter
+Most common Reporter type used by Zipkin users transporting Spans to the Zipkin
+server using JSON over HTTP. The reporter holds a buffer and reports to the
+backend asynchronously.
+
+#### Kafka Reporter
+High performance Reporter transporting Spans to the Zipkin server using a Kafka
+Producer digesting JSON V2 Spans. The reporter uses the
+[Sarama async producer](https://godoc.org/github.com/Shopify/sarama#AsyncProducer)
+underneath.
+
+## usage and examples
+[HTTP Server Example](example_httpserver_test.go)
diff --git a/vendor/github.com/openzipkin/zipkin-go/appveyor.yml b/vendor/github.com/openzipkin/zipkin-go/appveyor.yml
new file mode 100644
index 0000000..cb2baf3
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/appveyor.yml
@@ -0,0 +1,21 @@
+version: v1.0.0.{build}
+
+platform: x64
+
+clone_folder: c:\gopath\src\github.com\openzipkin\zipkin-go
+
+environment:
+  GOPATH: c:\gopath
+
+install:
+  - echo %PATH%
+  - echo %GOPATH%
+  - set PATH=%GOPATH%\bin;c:\go\bin;%PATH%
+  - go version
+  - go env
+
+build_script:
+  - go get -t -v ./...
+  - go vet ./...
+  - go test -v -race -cover ./...
+  - go test -v -run - -bench . -benchmem ./...
diff --git a/vendor/github.com/openzipkin/zipkin-go/circle.yml b/vendor/github.com/openzipkin/zipkin-go/circle.yml
new file mode 100644
index 0000000..808b54c
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/circle.yml
@@ -0,0 +1,11 @@
+version: 2
+jobs:
+  build:
+    working_directory: /go/src/github.com/openzipkin/zipkin-go
+    parallelism: 1
+    docker:
+      - image: circleci/golang
+    steps:
+      - checkout
+      - run: go get -t -v -d ./...
+      - run: make vet test bench
diff --git a/vendor/github.com/openzipkin/zipkin-go/context.go b/vendor/github.com/openzipkin/zipkin-go/context.go
new file mode 100644
index 0000000..171db90
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/context.go
@@ -0,0 +1,23 @@
+package zipkin
+
+import (
+	"context"
+)
+
+// SpanFromContext retrieves a Zipkin Span from Go's context propagation
+// mechanism if found. If not found, returns nil.
+func SpanFromContext(ctx context.Context) Span {
+	if s, ok := ctx.Value(spanKey).(Span); ok {
+		return s
+	}
+	return nil
+}
+
+// NewContext stores a Zipkin Span into Go's context propagation mechanism.
+func NewContext(ctx context.Context, s Span) context.Context {
+	return context.WithValue(ctx, spanKey, s)
+}
+
+type ctxKey struct{}
+
+var spanKey = ctxKey{}
diff --git a/vendor/github.com/openzipkin/zipkin-go/doc.go b/vendor/github.com/openzipkin/zipkin-go/doc.go
new file mode 100644
index 0000000..a49deba
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/doc.go
@@ -0,0 +1,6 @@
+/*
+Package zipkin implements a native Zipkin instrumentation library for Go.
+
+See https://zipkin.io for more information about Zipkin.
+*/
+package zipkin
diff --git a/vendor/github.com/openzipkin/zipkin-go/endpoint.go b/vendor/github.com/openzipkin/zipkin-go/endpoint.go
new file mode 100644
index 0000000..530091f
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/endpoint.go
@@ -0,0 +1,66 @@
+package zipkin
+
+import (
+	"net"
+	"strconv"
+	"strings"
+
+	"github.com/openzipkin/zipkin-go/model"
+)
+
+// NewEndpoint creates a new endpoint given the provided serviceName and
+// hostPort.
+func NewEndpoint(serviceName string, hostPort string) (*model.Endpoint, error) {
+	e := &model.Endpoint{
+		ServiceName: serviceName,
+	}
+
+	if hostPort == "" || hostPort == ":0" {
+		if serviceName == "" {
+			// if all properties are empty we should not have an Endpoint object.
+			return nil, nil
+		}
+		return e, nil
+	}
+
+	if strings.IndexByte(hostPort, ':') < 0 {
+		hostPort += ":0"
+	}
+
+	host, port, err := net.SplitHostPort(hostPort)
+	if err != nil {
+		return nil, err
+	}
+
+	p, err := strconv.ParseUint(port, 10, 16)
+	if err != nil {
+		return nil, err
+	}
+	e.Port = uint16(p)
+
+	addrs, err := net.LookupIP(host)
+	if err != nil {
+		return nil, err
+	}
+
+	for i := range addrs {
+		addr := addrs[i].To4()
+		if addr == nil {
+			// IPv6 - 16 bytes
+			if e.IPv6 == nil {
+				e.IPv6 = addrs[i].To16()
+			}
+		} else {
+			// IPv4 - 4 bytes
+			if e.IPv4 == nil {
+				e.IPv4 = addr
+			}
+		}
+		if e.IPv4 != nil && e.IPv6 != nil {
+			// Both IPv4 & IPv6 have been set, done...
+			break
+		}
+	}
+
+	return e, nil
+}
diff --git a/vendor/github.com/openzipkin/zipkin-go/idgenerator/idgenerator.go b/vendor/github.com/openzipkin/zipkin-go/idgenerator/idgenerator.go
new file mode 100644
index 0000000..a9de100
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/idgenerator/idgenerator.go
@@ -0,0 +1,116 @@
+/*
+Package idgenerator contains several Span and Trace ID generators which can be
+used by the Zipkin tracer. Additional third party generators can be plugged in
+if they adhere to the IDGenerator interface.
+*/
+package idgenerator
+
+import (
+	"math/rand"
+	"sync"
+	"time"
+
+	"github.com/openzipkin/zipkin-go/model"
+)
+
+var (
+	seededIDGen = rand.New(rand.NewSource(time.Now().UnixNano()))
+	// NewSource returns a new pseudo-random Source seeded with the given value.
+	// Unlike the default Source used by top-level functions, this source is not
+	// safe for concurrent use by multiple goroutines. Hence the need for a mutex.
+	seededIDLock sync.Mutex
+)
+
+// IDGenerator interface can be used to provide the Zipkin Tracer with custom
+// implementations to generate Span and Trace IDs.
+type IDGenerator interface {
+	SpanID(traceID model.TraceID) model.ID // Generates a new Span ID
+	TraceID() model.TraceID                // Generates a new Trace ID
+}
+
+// NewRandom64 returns an ID Generator which can generate 64 bit trace and span
+// id's
+func NewRandom64() IDGenerator {
+	return &randomID64{}
+}
+
+// NewRandom128 returns an ID Generator which can generate 128 bit trace and 64
+// bit span id's
+func NewRandom128() IDGenerator {
+	return &randomID128{}
+}
+
+// NewRandomTimestamped generates 128 bit time sortable traceid's and 64 bit
+// spanid's.
+func NewRandomTimestamped() IDGenerator {
+	return &randomTimestamped{}
+}
+
+// randomID64 can generate 64 bit traceid's and 64 bit spanid's.
+type randomID64 struct{}
+
+func (r *randomID64) TraceID() (id model.TraceID) {
+	seededIDLock.Lock()
+	id = model.TraceID{
+		Low: uint64(seededIDGen.Int63()),
+	}
+	seededIDLock.Unlock()
+	return
+}
+
+func (r *randomID64) SpanID(traceID model.TraceID) (id model.ID) {
+	if !traceID.Empty() {
+		return model.ID(traceID.Low)
+	}
+	seededIDLock.Lock()
+	id = model.ID(seededIDGen.Int63())
+	seededIDLock.Unlock()
+	return
+}
+
+// randomID128 can generate 128 bit traceid's and 64 bit spanid's.
+type randomID128 struct{}
+
+func (r *randomID128) TraceID() (id model.TraceID) {
+	seededIDLock.Lock()
+	id = model.TraceID{
+		High: uint64(seededIDGen.Int63()),
+		Low:  uint64(seededIDGen.Int63()),
+	}
+	seededIDLock.Unlock()
+	return
+}
+
+func (r *randomID128) SpanID(traceID model.TraceID) (id model.ID) {
+	if !traceID.Empty() {
+		return model.ID(traceID.Low)
+	}
+	seededIDLock.Lock()
+	id = model.ID(seededIDGen.Int63())
+	seededIDLock.Unlock()
+	return
+}
+
+// randomTimestamped can generate 128 bit time sortable traceid's compatible
+// with AWS X-Ray and 64 bit spanid's.
+type randomTimestamped struct{}
+
+func (t *randomTimestamped) TraceID() (id model.TraceID) {
+	seededIDLock.Lock()
+	id = model.TraceID{
+		High: uint64(time.Now().Unix()<<32) + uint64(seededIDGen.Int31()),
+		Low:  uint64(seededIDGen.Int63()),
+	}
+	seededIDLock.Unlock()
+	return
+}
+
+func (t *randomTimestamped) SpanID(traceID model.TraceID) (id model.ID) {
+	if !traceID.Empty() {
+		return model.ID(traceID.Low)
+	}
+	seededIDLock.Lock()
+	id = model.ID(seededIDGen.Int63())
+	seededIDLock.Unlock()
+	return
+}
diff --git a/vendor/github.com/openzipkin/zipkin-go/model/annotation.go b/vendor/github.com/openzipkin/zipkin-go/model/annotation.go
new file mode 100644
index 0000000..751f81f
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/model/annotation.go
@@ -0,0 +1,46 @@
+package model
+
+import (
+	"encoding/json"
+	"errors"
+	"time"
+)
+
+// ErrValidTimestampRequired error
+var ErrValidTimestampRequired = errors.New("valid annotation timestamp required")
+
+// Annotation associates an event that explains latency with a timestamp.
+type Annotation struct {
+	Timestamp time.Time
+	Value     string
+}
+
+// MarshalJSON implements custom JSON encoding
+func (a *Annotation) MarshalJSON() ([]byte, error) {
+	return json.Marshal(&struct {
+		Timestamp int64  `json:"timestamp"`
+		Value     string `json:"value"`
+	}{
+		Timestamp: a.Timestamp.Round(time.Microsecond).UnixNano() / 1e3,
+		Value:     a.Value,
+	})
+}
+
+// UnmarshalJSON implements custom JSON decoding
+func (a *Annotation) UnmarshalJSON(b []byte) error {
+	type Alias Annotation
+	annotation := &struct {
+		TimeStamp uint64 `json:"timestamp"`
+		*Alias
+	}{
+		Alias: (*Alias)(a),
+	}
+	if err := json.Unmarshal(b, &annotation); err != nil {
+		return err
+	}
+	if annotation.TimeStamp < 1 {
+		return ErrValidTimestampRequired
+	}
+	a.Timestamp = time.Unix(0, int64(annotation.TimeStamp)*1e3)
+	return nil
+}
diff --git a/vendor/github.com/openzipkin/zipkin-go/model/doc.go b/vendor/github.com/openzipkin/zipkin-go/model/doc.go
new file mode 100644
index 0000000..99c2ec3
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/model/doc.go
@@ -0,0 +1,9 @@
+/*
+Package model contains the Zipkin V2 model which is used by the Zipkin Go
+tracer implementation.
+
+Third party instrumentation libraries can use the model and transport packages
+found in this Zipkin Go library to directly interface with the Zipkin Server or
+Zipkin Collectors without the need to use the tracer implementation itself.
+*/
+package model
diff --git a/vendor/github.com/openzipkin/zipkin-go/model/endpoint.go b/vendor/github.com/openzipkin/zipkin-go/model/endpoint.go
new file mode 100644
index 0000000..9a2aa0c
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/model/endpoint.go
@@ -0,0 +1,17 @@
+package model
+
+import "net"
+
+// Endpoint holds the network context of a node in the service graph.
+type Endpoint struct {
+	ServiceName string `json:"serviceName,omitempty"`
+	IPv4        net.IP `json:"ipv4,omitempty"`
+	IPv6        net.IP `json:"ipv6,omitempty"`
+	Port        uint16 `json:"port,omitempty"`
+}
+
+// Empty returns if all Endpoint properties are empty / unspecified.
+func (e *Endpoint) Empty() bool {
+	return e == nil ||
+		(e.ServiceName == "" && e.Port == 0 && len(e.IPv4) == 0 && len(e.IPv6) == 0)
+}
diff --git a/vendor/github.com/openzipkin/zipkin-go/model/kind.go b/vendor/github.com/openzipkin/zipkin-go/model/kind.go
new file mode 100644
index 0000000..8da3c9b
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/model/kind.go
@@ -0,0 +1,13 @@
+package model
+
+// Kind clarifies context of timestamp, duration and remoteEndpoint in a span.
+type Kind string
+
+// Available Kind values
+const (
+	Undetermined Kind = ""
+	Client       Kind = "CLIENT"
+	Server       Kind = "SERVER"
+	Producer     Kind = "PRODUCER"
+	Consumer     Kind = "CONSUMER"
+)
diff --git a/vendor/github.com/openzipkin/zipkin-go/model/span.go b/vendor/github.com/openzipkin/zipkin-go/model/span.go
new file mode 100644
index 0000000..fbdb7c7
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/model/span.go
@@ -0,0 +1,124 @@
+package model
+
+import (
+	"encoding/json"
+	"errors"
+	"time"
+)
+
+// unmarshal errors
+var (
+	ErrValidTraceIDRequired  = errors.New("valid traceId required")
+	ErrValidIDRequired       = errors.New("valid span id required")
+	ErrValidDurationRequired = errors.New("valid duration required")
+)
+
+// SpanContext holds the context of a Span.
+type SpanContext struct {
+	TraceID  TraceID `json:"traceId"`
+	ID       ID      `json:"id"`
+	ParentID *ID     `json:"parentId,omitempty"`
+	Debug    bool    `json:"debug,omitempty"`
+	Sampled  *bool   `json:"-"`
+	Err      error   `json:"-"`
+}
+
+// SpanModel structure.
+//
+// If using this library to instrument your application you will not need to
+// directly access or modify this representation. The SpanModel is exported for
+// use cases involving 3rd party Go instrumentation libraries desiring to
+// export data to a Zipkin server using the Zipkin V2 Span model.
+type SpanModel struct {
+	SpanContext
+	Name           string            `json:"name,omitempty"`
+	Kind           Kind              `json:"kind,omitempty"`
+	Timestamp      time.Time         `json:"-"`
+	Duration       time.Duration     `json:"-"`
+	Shared         bool              `json:"shared,omitempty"`
+	LocalEndpoint  *Endpoint         `json:"localEndpoint,omitempty"`
+	RemoteEndpoint *Endpoint         `json:"remoteEndpoint,omitempty"`
+	Annotations    []Annotation      `json:"annotations,omitempty"`
+	Tags           map[string]string `json:"tags,omitempty"`
+}
+
+// MarshalJSON exports our Model into the correct format for the Zipkin V2 API.
+func (s SpanModel) MarshalJSON() ([]byte, error) {
+	type Alias SpanModel
+
+	var timestamp int64
+	if !s.Timestamp.IsZero() {
+		if s.Timestamp.Unix() < 1 {
+			// Zipkin does not allow Timestamps before Unix epoch
+			return nil, ErrValidTimestampRequired
+		}
+		timestamp = s.Timestamp.Round(time.Microsecond).UnixNano() / 1e3
+	}
+
+	if s.Duration < time.Microsecond {
+		if s.Duration < 0 {
+			// negative duration is not allowed and signals a timing logic error
+			return nil, ErrValidDurationRequired
+		} else if s.Duration > 0 {
+			// sub microsecond durations are reported as 1 microsecond
+			s.Duration = 1 * time.Microsecond
+		}
+	} else {
+		// Duration will be rounded to nearest microsecond representation.
+		//
+		// NOTE: Duration.Round() is not available in Go 1.8 which we still support.
+		// To handle microsecond resolution rounding we'll add 500 nanoseconds to
+		// the duration. When truncated to microseconds in the call to marshal, it
+		// will be naturally rounded. See TestSpanDurationRounding in span_test.go
+		s.Duration += 500 * time.Nanosecond
+	}
+
+	if s.LocalEndpoint.Empty() {
+		s.LocalEndpoint = nil
+	}
+
+	if s.RemoteEndpoint.Empty() {
+		s.RemoteEndpoint = nil
+	}
+
+	return json.Marshal(&struct {
+		T int64 `json:"timestamp,omitempty"`
+		D int64 `json:"duration,omitempty"`
+		Alias
+	}{
+		T:     timestamp,
+		D:     s.Duration.Nanoseconds() / 1e3,
+		Alias: (Alias)(s),
+	})
+}
+
+// UnmarshalJSON imports our Model from a Zipkin V2 API compatible span
+// representation.
+func (s *SpanModel) UnmarshalJSON(b []byte) error {
+	type Alias SpanModel
+	span := &struct {
+		T uint64 `json:"timestamp,omitempty"`
+		D uint64 `json:"duration,omitempty"`
+		*Alias
+	}{
+		Alias: (*Alias)(s),
+	}
+	if err := json.Unmarshal(b, &span); err != nil {
+		return err
+	}
+	if s.ID < 1 {
+		return ErrValidIDRequired
+	}
+	if span.T > 0 {
+		s.Timestamp = time.Unix(0, int64(span.T)*1e3)
+	}
+	s.Duration = time.Duration(span.D*1e3) * time.Nanosecond
+	if s.LocalEndpoint.Empty() {
+		s.LocalEndpoint = nil
+	}
+
+	if s.RemoteEndpoint.Empty() {
+		s.RemoteEndpoint = nil
+	}
+	return nil
+}
diff --git a/vendor/github.com/openzipkin/zipkin-go/model/span_id.go b/vendor/github.com/openzipkin/zipkin-go/model/span_id.go
new file mode 100644
index 0000000..1b5486a
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/model/span_id.go
@@ -0,0 +1,30 @@
+package model
+
+import (
+	"fmt"
+	"strconv"
+)
+
+// ID type
+type ID uint64
+
+// String outputs the 64-bit ID as hex string.
+func (i ID) String() string {
+	return fmt.Sprintf("%016x", uint64(i))
+}
+
+// MarshalJSON serializes an ID type (SpanID, ParentSpanID) to HEX.
+func (i ID) MarshalJSON() ([]byte, error) {
+	return []byte(fmt.Sprintf("%q", i.String())), nil
+}
+
+// UnmarshalJSON deserializes an ID type (SpanID, ParentSpanID) from HEX.
+func (i *ID) UnmarshalJSON(b []byte) (err error) {
+	var id uint64
+	if len(b) < 3 {
+		return nil
+	}
+	id, err = strconv.ParseUint(string(b[1:len(b)-1]), 16, 64)
+	*i = ID(id)
+	return err
+}
diff --git a/vendor/github.com/openzipkin/zipkin-go/model/traceid.go b/vendor/github.com/openzipkin/zipkin-go/model/traceid.go
new file mode 100644
index 0000000..fcbbcf7
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/model/traceid.go
@@ -0,0 +1,61 @@
+package model
+
+import (
+	"fmt"
+	"strconv"
+)
+
+// TraceID is a 128 bit number internally stored as 2x uint64 (high & low).
+// In case of 64 bit traceIDs, the value can be found in Low.
+type TraceID struct {
+	High uint64
+	Low  uint64
+}
+
+// Empty returns if TraceID has zero value.
+func (t TraceID) Empty() bool {
+	return t.Low == 0 && t.High == 0
+}
+
+// String outputs the 128-bit traceID as hex string.
+func (t TraceID) String() string {
+	if t.High == 0 {
+		return fmt.Sprintf("%016x", t.Low)
+	}
+	return fmt.Sprintf("%016x%016x", t.High, t.Low)
+}
+
+// TraceIDFromHex returns the TraceID from a hex string.
+func TraceIDFromHex(h string) (t TraceID, err error) {
+	if len(h) > 16 {
+		if t.High, err = strconv.ParseUint(h[0:len(h)-16], 16, 64); err != nil {
+			return
+		}
+		t.Low, err = strconv.ParseUint(h[len(h)-16:], 16, 64)
+		return
+	}
+	t.Low, err = strconv.ParseUint(h, 16, 64)
+	return
+}
+
+// MarshalJSON custom JSON serializer to export the TraceID in the required
+// zero padded hex representation.
+func (t TraceID) MarshalJSON() ([]byte, error) {
+	return []byte(fmt.Sprintf("%q", t.String())), nil
+}
+
+// UnmarshalJSON custom JSON deserializer to retrieve the traceID from the hex
+// encoded representation.
+func (t *TraceID) UnmarshalJSON(traceID []byte) error {
+	if len(traceID) < 3 {
+		return ErrValidTraceIDRequired
+	}
+	// A valid JSON string is encoded wrapped in double quotes. We need to trim
+	// these before converting the hex payload.
+	tID, err := TraceIDFromHex(string(traceID[1 : len(traceID)-1]))
+	if err != nil {
+		return err
+	}
+	*t = tID
+	return nil
+}
diff --git a/vendor/github.com/openzipkin/zipkin-go/noop.go b/vendor/github.com/openzipkin/zipkin-go/noop.go
new file mode 100644
index 0000000..d1e3f75
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/noop.go
@@ -0,0 +1,25 @@
+package zipkin
+
+import (
+	"time"
+
+	"github.com/openzipkin/zipkin-go/model"
+)
+
+type noopSpan struct {
+	model.SpanContext
+}
+
+func (n *noopSpan) Context() model.SpanContext { return n.SpanContext }
+
+func (n *noopSpan) SetName(string) {}
+
+func (*noopSpan) SetRemoteEndpoint(*model.Endpoint) {}
+
+func (*noopSpan) Annotate(time.Time, string) {}
+
+func (*noopSpan) Tag(string, string) {}
+
+func (*noopSpan) Finish() {}
+
+func (*noopSpan) Flush() {}
diff --git a/vendor/github.com/openzipkin/zipkin-go/propagation/propagation.go b/vendor/github.com/openzipkin/zipkin-go/propagation/propagation.go
new file mode 100644
index 0000000..4168508
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/propagation/propagation.go
@@ -0,0 +1,16 @@
+/*
+Package propagation holds the required function signatures for Injection and
+Extraction as used by the Zipkin Tracer.
+
+Subpackages of this package contain officially supported standard propagation
+implementations.
+*/
+package propagation
+
+import "github.com/openzipkin/zipkin-go/model"
+
+// Extractor function signature
+type Extractor func() (*model.SpanContext, error)
+
+// Injector function signature
+type Injector func(model.SpanContext) error
diff --git a/vendor/github.com/openzipkin/zipkin-go/reporter/http/http.go b/vendor/github.com/openzipkin/zipkin-go/reporter/http/http.go
new file mode 100644
index 0000000..af3b8ee
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/reporter/http/http.go
@@ -0,0 +1,218 @@
+/*
+Package http implements a HTTP reporter to send spans to Zipkin V2 collectors.
+*/
+package http
+
+import (
+	"bytes"
+	"encoding/json"
+	"log"
+	"net/http"
+	"os"
+	"sync"
+	"time"
+
+	"github.com/openzipkin/zipkin-go/model"
+	"github.com/openzipkin/zipkin-go/reporter"
+)
+
+// defaults
+const (
+	defaultTimeout       = time.Second * 5 // timeout for http request in seconds
+	defaultBatchInterval = time.Second * 1 // BatchInterval in seconds
+	defaultBatchSize     = 100
+	defaultMaxBacklog    = 1000
+)
+
+// httpReporter will send spans to a Zipkin HTTP Collector using Zipkin V2 API.
+type httpReporter struct {
+	url           string
+	client        *http.Client
+	logger        *log.Logger
+	batchInterval time.Duration
+	batchSize     int
+	maxBacklog    int
+	sendMtx       *sync.Mutex
+	batchMtx      *sync.Mutex
+	batch         []*model.SpanModel
+	spanC         chan *model.SpanModel
+	quit          chan struct{}
+	shutdown      chan error
+	reqCallback   RequestCallbackFn
+}
+
+// Send implements reporter
+func (r *httpReporter) Send(s model.SpanModel) {
+	r.spanC <- &s
+}
+
+// Close implements reporter
+func (r *httpReporter) Close() error {
+	close(r.quit)
+	return <-r.shutdown
+}
+
+func (r *httpReporter) loop() {
+	var (
+		nextSend   = time.Now().Add(r.batchInterval)
+		ticker     = time.NewTicker(r.batchInterval / 10)
+		tickerChan = ticker.C
+	)
+	defer ticker.Stop()
+
+	for {
+		select {
+		case span := <-r.spanC:
+			currentBatchSize := r.append(span)
+			if currentBatchSize >= r.batchSize {
+				nextSend = time.Now().Add(r.batchInterval)
+				go func() {
+					_ = r.sendBatch()
+				}()
+			}
+		case <-tickerChan:
+			if time.Now().After(nextSend) {
+				nextSend = time.Now().Add(r.batchInterval)
+				go func() {
+					_ = r.sendBatch()
+				}()
+			}
+		case <-r.quit:
+			r.shutdown <- r.sendBatch()
+			return
+		}
+	}
+}
+
+func (r *httpReporter) append(span *model.SpanModel) (newBatchSize int) {
+	r.batchMtx.Lock()
+
+	r.batch = append(r.batch, span)
+	if len(r.batch) > r.maxBacklog {
+		dispose := len(r.batch) - r.maxBacklog
+		r.logger.Printf("backlog too long, disposing %d spans", dispose)
+		r.batch = r.batch[dispose:]
+	}
+	newBatchSize = len(r.batch)
+
+	r.batchMtx.Unlock()
+	return
+}
+
+func (r *httpReporter) sendBatch() error {
+	// in order to prevent sending the same batch twice
+	r.sendMtx.Lock()
+	defer r.sendMtx.Unlock()
+
+	// Select all current spans in the batch to be sent
+	r.batchMtx.Lock()
+	sendBatch := r.batch[:]
+	r.batchMtx.Unlock()
+
+	if len(sendBatch) == 0 {
+		return nil
+	}
+
+	body, err := json.Marshal(sendBatch)
+	if err != nil {
+		r.logger.Printf("failed when marshalling the spans batch: %s\n", err.Error())
+		return err
+	}
+
+	req, err := http.NewRequest("POST", r.url, bytes.NewReader(body))
+	if err != nil {
+		r.logger.Printf("failed when creating the request: %s\n", err.Error())
+		return err
+	}
+	req.Header.Set("Content-Type", "application/json")
+	if r.reqCallback != nil {
+		r.reqCallback(req)
+	}
+
+	resp, err := r.client.Do(req)
+	if err != nil {
+		r.logger.Printf("failed to send the request: %s\n", err.Error())
+		return err
+	}
+	_ = resp.Body.Close()
+	if resp.StatusCode < 200 || resp.StatusCode > 299 {
+		r.logger.Printf("failed the request with status code %d\n", resp.StatusCode)
+	}
+
+	// Remove sent spans from the batch even if they were not saved
+	r.batchMtx.Lock()
+	r.batch = r.batch[len(sendBatch):]
+	r.batchMtx.Unlock()
+
+	return nil
+}
+
+// RequestCallbackFn receives the initialized request from the Collector before
+// sending it over the wire. This allows one to plug in additional headers or
+// do other customization.
+type RequestCallbackFn func(*http.Request)
+
+// ReporterOption sets a parameter for the HTTP Reporter
+type ReporterOption func(r *httpReporter)
+
+// Timeout sets maximum timeout for http request.
+func Timeout(duration time.Duration) ReporterOption {
+	return func(r *httpReporter) { r.client.Timeout = duration }
+}
+
+// BatchSize sets the maximum batch size, after which a collect will be
+// triggered. The default batch size is 100 traces.
+func BatchSize(n int) ReporterOption {
+	return func(r *httpReporter) { r.batchSize = n }
+}
+
+// MaxBacklog sets the maximum backlog size. When batch size reaches this
+// threshold, spans from the beginning of the batch will be disposed.
+func MaxBacklog(n int) ReporterOption {
+	return func(r *httpReporter) { r.maxBacklog = n }
+}
+
+// BatchInterval sets the maximum duration we will buffer traces before
+// emitting them to the collector. The default batch interval is 1 second.
+func BatchInterval(d time.Duration) ReporterOption {
+	return func(r *httpReporter) { r.batchInterval = d }
+}
+
+// Client sets a custom http client to use.
+func Client(client *http.Client) ReporterOption {
+	return func(r *httpReporter) { r.client = client }
+}
+
+// RequestCallback registers a callback function to adjust the reporter
+// *http.Request before it sends the request to Zipkin.
+func RequestCallback(rc RequestCallbackFn) ReporterOption {
+	return func(r *httpReporter) { r.reqCallback = rc }
+}
+
+// NewReporter returns a new HTTP Reporter.
+// url should be the endpoint to send the spans to, e.g.
+// http://localhost:9411/api/v2/spans
+func NewReporter(url string, opts ...ReporterOption) reporter.Reporter {
+	r := httpReporter{
+		url:           url,
+		logger:        log.New(os.Stderr, "", log.LstdFlags),
+		client:        &http.Client{Timeout: defaultTimeout},
+		batchInterval: defaultBatchInterval,
+		batchSize:     defaultBatchSize,
+		maxBacklog:    defaultMaxBacklog,
+		batch:         []*model.SpanModel{},
+		spanC:         make(chan *model.SpanModel),
+		quit:          make(chan struct{}, 1),
+		shutdown:      make(chan error, 1),
+		sendMtx:       &sync.Mutex{},
+		batchMtx:      &sync.Mutex{},
+	}
+
+	for _, opt := range opts {
+		opt(&r)
+	}
+
+	go r.loop()
+
+	return &r
+}
diff --git a/vendor/github.com/openzipkin/zipkin-go/reporter/reporter.go b/vendor/github.com/openzipkin/zipkin-go/reporter/reporter.go
new file mode 100644
index 0000000..09b877e
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/reporter/reporter.go
@@ -0,0 +1,27 @@
+/*
+Package reporter holds the Reporter interface which is used by the Zipkin
+Tracer to send finished spans.
+
+Subpackages of package reporter contain officially supported standard
+reporter implementations.
+*/
+package reporter
+
+import "github.com/openzipkin/zipkin-go/model"
+
+// Reporter interface can be used to provide the Zipkin Tracer with custom
+// implementations to publish Zipkin Span data.
+type Reporter interface {
+	Send(model.SpanModel) // Send Span data to the reporter
+	Close() error         // Close the reporter
+}
+
+type noopReporter struct{}
+
+func (r *noopReporter) Send(model.SpanModel) {}
+func (r *noopReporter) Close() error         { return nil }
+
+// NewNoopReporter returns a no-op Reporter implementation.
+func NewNoopReporter() Reporter {
+	return &noopReporter{}
+}
diff --git a/vendor/github.com/openzipkin/zipkin-go/sample.go b/vendor/github.com/openzipkin/zipkin-go/sample.go
new file mode 100644
index 0000000..248b8f5
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/sample.go
@@ -0,0 +1,113 @@
+package zipkin
+
+import (
+	"fmt"
+	"math"
+	"math/rand"
+	"sync"
+	"time"
+)
+
+// Sampler functions return if a Zipkin span should be sampled, based on its
+// traceID.
+type Sampler func(id uint64) bool
+
+// NeverSample will always return false. If used by a service it will not allow
+// the service to start traces but will still allow the service to participate 
+// in traces started upstream.
+func NeverSample(_ uint64) bool { return false }
+
+// AlwaysSample will always return true. If used by a service it will always start
+// traces if no upstream trace has been propagated. If an incoming upstream trace 
+// is not sampled the service will adhere to this and only propagate the context.
+func AlwaysSample(_ uint64) bool { return true }
+
+// NewModuloSampler provides a generic type Sampler.
+func NewModuloSampler(mod uint64) Sampler {
+	if mod < 2 {
+		return AlwaysSample
+	}
+	return func(id uint64) bool {
+		return (id % mod) == 0
+	}
+}
+
+// NewBoundarySampler is appropriate for high-traffic instrumentation who
+// provision random trace ids, and make the sampling decision only once.
+// It defends against nodes in the cluster selecting exactly the same ids.
+func NewBoundarySampler(rate float64, salt int64) (Sampler, error) {
+	if rate == 0.0 {
+		return NeverSample, nil
+	}
+	if rate == 1.0 {
+		return AlwaysSample, nil
+	}
+	if rate < 0.0001 || rate > 1 {
+		return nil, fmt.Errorf("rate should be 0.0 or between 0.0001 and 1: was %f", rate)
+	}
+
+	var (
+		boundary = int64(rate * 10000)
+		usalt    = uint64(salt)
+	)
+	return func(id uint64) bool {
+		return int64(math.Abs(float64(id^usalt)))%10000 < boundary
+	}, nil
+}
+
+// NewCountingSampler is appropriate for low-traffic instrumentation or
+// those who do not provision random trace ids. It is not appropriate for
+// collectors as the sampling decision isn't idempotent (consistent based
+// on trace id).
+func NewCountingSampler(rate float64) (Sampler, error) {
+	if rate == 0.0 {
+		return NeverSample, nil
+	}
+	if rate == 1.0 {
+		return AlwaysSample, nil
+	}
+	if rate < 0.01 || rate > 1 {
+		return nil, fmt.Errorf("rate should be 0.0 or between 0.01 and 1: was %f", rate)
+	}
+	var (
+		i         = 0
+		outOf100  = int(rate*100 + math.Copysign(0.5, rate*100)) // for rounding float to int conversion instead of truncation
+		decisions = randomBitSet(100, outOf100, rand.New(rand.NewSource(time.Now().UnixNano())))
+		mtx       = &sync.Mutex{}
+	)
+
+	return func(_ uint64) bool {
+		mtx.Lock()
+		result := decisions[i]
+		i++
+		if i == 100 {
+			i = 0
+		}
+		mtx.Unlock()
+		return result
+	}, nil
+}
+
+/**
+ * Reservoir sampling algorithm borrowed from Stack Overflow.
+ *
+ * http://stackoverflow.com/questions/12817946/generate-a-random-bitset-with-n-1s
+ */
+func randomBitSet(size int, cardinality int, rnd *rand.Rand) []bool {
+	result := make([]bool, size)
+	chosen := make([]int, cardinality)
+	var i int
+	for i = 0; i < cardinality; i++ {
+		chosen[i] = i
+		result[i] = true
+	}
+	for ; i < size; i++ {
+		j := rnd.Intn(i + 1)
+		if j < cardinality {
+			result[chosen[j]] = false
+			result[i] = true
+			chosen[j] = i
+		}
+	}
+	return result
+}
diff --git a/vendor/github.com/openzipkin/zipkin-go/span.go b/vendor/github.com/openzipkin/zipkin-go/span.go
new file mode 100644
index 0000000..7d03924
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/span.go
@@ -0,0 +1,38 @@
+package zipkin
+
+import (
+	"time"
+
+	"github.com/openzipkin/zipkin-go/model"
+)
+
+// Span interface as returned by Tracer.StartSpan()
+type Span interface {
+	// Context returns the Span's SpanContext.
+	Context() model.SpanContext
+
+	// SetName updates the Span's name.
+	SetName(string)
+
+	// SetRemoteEndpoint updates the Span's Remote Endpoint.
+	SetRemoteEndpoint(*model.Endpoint)
+
+	// Annotate adds a timed event to the Span.
+	Annotate(time.Time, string)
+
+	// Tag sets Tag with given key and value to the Span. If key already exists in
+	// the Span the value will be overridden except for error tags where the first
+	// value is persisted.
+	Tag(string, string)
+
+	// Finish the Span and send to Reporter. If DelaySend option was used at
+	// Span creation time, Finish will not send the Span to the Reporter. It then
+	// becomes the user's responsibility to get the Span reported (by using
+	// span.Flush).
+	Finish()
+
+	// Flush the Span to the Reporter (regardless of being finished or not).
+	// This can be used if the DelaySend SpanOption was set or when dealing with
+	// one-way RPC tracing where duration might not be measured.
+	Flush()
+}
diff --git a/vendor/github.com/openzipkin/zipkin-go/span_implementation.go b/vendor/github.com/openzipkin/zipkin-go/span_implementation.go
new file mode 100644
index 0000000..5872308
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/span_implementation.go
@@ -0,0 +1,78 @@
+package zipkin
+
+import (
+	"sync"
+	"sync/atomic"
+	"time"
+
+	"github.com/openzipkin/zipkin-go/model"
+)
+
+type spanImpl struct {
+	mtx sync.RWMutex
+	model.SpanModel
+	tracer        *Tracer
+	mustCollect   int32 // used as atomic bool (1 = true, 0 = false)
+	flushOnFinish bool
+}
+
+func (s *spanImpl) Context() model.SpanContext {
+	return s.SpanContext
+}
+
+func (s *spanImpl) SetName(name string) {
+	s.mtx.Lock()
+	s.Name = name
+	s.mtx.Unlock()
+}
+
+func (s *spanImpl) SetRemoteEndpoint(e *model.Endpoint) {
+	s.mtx.Lock()
+	if e == nil {
+		s.RemoteEndpoint = nil
+	} else {
+		s.RemoteEndpoint = &model.Endpoint{}
+		*s.RemoteEndpoint = *e
+	}
+	s.mtx.Unlock()
+}
+
+func (s *spanImpl) Annotate(t time.Time, value string) {
+	a := model.Annotation{
+		Timestamp: t,
+		Value:     value,
+	}
+
+	s.mtx.Lock()
+	s.Annotations = append(s.Annotations, a)
+	s.mtx.Unlock()
+}
+
+func (s *spanImpl) Tag(key, value string) {
+	s.mtx.Lock()
+
+	if key == string(TagError) {
+		if _, found := s.Tags[key]; found {
+			s.mtx.Unlock()
+			return
+		}
+	}
+
+	s.Tags[key] = value
+	s.mtx.Unlock()
+}
+
+func (s *spanImpl) Finish() {
+	if atomic.CompareAndSwapInt32(&s.mustCollect, 1, 0) {
+		s.Duration = time.Since(s.Timestamp)
+		if s.flushOnFinish {
+			s.tracer.reporter.Send(s.SpanModel)
+		}
+	}
+}
+
+func (s *spanImpl) Flush() {
+	if s.SpanModel.Debug || (s.SpanModel.Sampled != nil && *s.SpanModel.Sampled) {
+		s.tracer.reporter.Send(s.SpanModel)
+	}
+}
diff --git a/vendor/github.com/openzipkin/zipkin-go/span_options.go b/vendor/github.com/openzipkin/zipkin-go/span_options.go
new file mode 100644
index 0000000..e6fbcf0
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/span_options.go
@@ -0,0 +1,74 @@
+package zipkin
+
+import (
+	"time"
+
+	"github.com/openzipkin/zipkin-go/model"
+)
+
+// SpanOption allows for functional options to adjust behavior and payload of
+// the Span to be created with tracer.StartSpan().
+type SpanOption func(t *Tracer, s *spanImpl)
+
+// Kind sets the kind of the span being created..
+func Kind(kind model.Kind) SpanOption {
+	return func(t *Tracer, s *spanImpl) {
+		s.Kind = kind
+	}
+}
+
+// Parent will use provided SpanContext as parent to the span being created.
+func Parent(sc model.SpanContext) SpanOption {
+	return func(t *Tracer, s *spanImpl) {
+		if sc.Err != nil {
+			// encountered an extraction error
+			switch t.extractFailurePolicy {
+			case ExtractFailurePolicyRestart:
+			case ExtractFailurePolicyError:
+				panic(s.SpanContext.Err)
+			case ExtractFailurePolicyTagAndRestart:
+				s.Tags["error.extract"] = sc.Err.Error()
+			default:
+				panic(ErrInvalidExtractFailurePolicy)
+			}
+			/* don't use provided SpanContext, but restart trace */
+			return
+		}
+		s.SpanContext = sc
+	}
+}
+
+// StartTime uses a given start time for the span being created.
+func StartTime(start time.Time) SpanOption {
+	return func(t *Tracer, s *spanImpl) {
+		s.Timestamp = start
+	}
+}
+
+// RemoteEndpoint sets the remote endpoint of the span being created.
+func RemoteEndpoint(e *model.Endpoint) SpanOption {
+	return func(t *Tracer, s *spanImpl) {
+		s.RemoteEndpoint = e
+	}
+}
+
+// Tags sets initial tags for the span being created. If default tracer tags
+// are present they will be overwritten on key collisions.
+func Tags(tags map[string]string) SpanOption {
+	return func(t *Tracer, s *spanImpl) {
+		for k, v := range tags {
+			s.Tags[k] = v
+		}
+	}
+}
+
+// FlushOnFinish when set to false will disable span.Finish() to send the Span
+// to the Reporter automatically (which is the default behavior). If set to
+// false, having the Span be reported becomes the responsibility of the user.
+// This is available if late tag data is expected to be only available after the
+// required finish time of the Span.
+func FlushOnFinish(b bool) SpanOption {
+	return func(t *Tracer, s *spanImpl) {
+		s.flushOnFinish = b
+	}
+}
diff --git a/vendor/github.com/openzipkin/zipkin-go/tags.go b/vendor/github.com/openzipkin/zipkin-go/tags.go
new file mode 100644
index 0000000..28be6dd
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/tags.go
@@ -0,0 +1,23 @@
+package zipkin
+
+// Tag holds available types
+type Tag string
+
+// Common Tag values
+const (
+	TagHTTPMethod       Tag = "http.method"
+	TagHTTPPath         Tag = "http.path"
+	TagHTTPUrl          Tag = "http.url"
+	TagHTTPRoute        Tag = "http.route"
+	TagHTTPStatusCode   Tag = "http.status_code"
+	TagHTTPRequestSize  Tag = "http.request.size"
+	TagHTTPResponseSize Tag = "http.response.size"
+	TagGRPCStatusCode   Tag = "grpc.status_code"
+	TagSQLQuery         Tag = "sql.query"
+	TagError            Tag = "error"
+)
+
+// Set a standard Tag with a payload on provided Span.
+func (t Tag) Set(s Span, value string) {
+	s.Tag(string(t), value)
+}
diff --git a/vendor/github.com/openzipkin/zipkin-go/tracer.go b/vendor/github.com/openzipkin/zipkin-go/tracer.go
new file mode 100644
index 0000000..a050e30
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/tracer.go
@@ -0,0 +1,173 @@
+package zipkin
+
+import (
+	"context"
+	"sync/atomic"
+	"time"
+
+	"github.com/openzipkin/zipkin-go/idgenerator"
+	"github.com/openzipkin/zipkin-go/model"
+	"github.com/openzipkin/zipkin-go/propagation"
+	"github.com/openzipkin/zipkin-go/reporter"
+)
+
+// Tracer is our Zipkin tracer implementation. It should be initialized using
+// the NewTracer method.
+type Tracer struct {
+	defaultTags          map[string]string
+	extractFailurePolicy ExtractFailurePolicy
+	sampler              Sampler
+	generate             idgenerator.IDGenerator
+	reporter             reporter.Reporter
+	localEndpoint        *model.Endpoint
+	noop                 int32 // used as atomic bool (1 = true, 0 = false)
+	sharedSpans          bool
+	unsampledNoop        bool
+}
+
+// NewTracer returns a new Zipkin Tracer.
+func NewTracer(rep reporter.Reporter, opts ...TracerOption) (*Tracer, error) {
+	// set default tracer options
+	t := &Tracer{
+		defaultTags:          make(map[string]string),
+		extractFailurePolicy: ExtractFailurePolicyRestart,
+		sampler:              AlwaysSample,
+		generate:             idgenerator.NewRandom64(),
+		reporter:             rep,
+		localEndpoint:        nil,
+		noop:                 0,
+		sharedSpans:          true,
+		unsampledNoop:        false,
+	}
+
+	// if no reporter was provided we default to noop implementation.
+	if t.reporter == nil {
+		t.reporter = reporter.NewNoopReporter()
+		t.noop = 1
+	}
+
+	// process functional options
+	for _, opt := range opts {
+		if err := opt(t); err != nil {
+			return nil, err
+		}
+	}
+
+	return t, nil
+}
+
+// StartSpanFromContext creates and starts a span using the span found in
+// context as parent. If no parent span is found a root span is created.
+func (t *Tracer) StartSpanFromContext(ctx context.Context, name string, options ...SpanOption) (Span, context.Context) {
+	if parentSpan := SpanFromContext(ctx); parentSpan != nil {
+		options = append(options, Parent(parentSpan.Context()))
+	}
+	span := t.StartSpan(name, options...)
+	return span, NewContext(ctx, span)
+}
+
+// StartSpan creates and starts a span.
+func (t *Tracer) StartSpan(name string, options ...SpanOption) Span {
+	if atomic.LoadInt32(&t.noop) == 1 {
+		return &noopSpan{}
+	}
+	s := &spanImpl{
+		SpanModel: model.SpanModel{
+			Kind:          model.Undetermined,
+			Name:          name,
+			LocalEndpoint: t.localEndpoint,
+			Annotations:   make([]model.Annotation, 0),
+			Tags:          make(map[string]string),
+		},
+		flushOnFinish: true,
+		tracer:        t,
+	}
+
+	// add default tracer tags to span
+	for k, v := range t.defaultTags {
+		s.Tag(k, v)
+	}
+
+	// handle provided functional options
+	for _, option := range options {
+		option(t, s)
+	}
+
+	if s.TraceID.Empty() {
+		// create root span
+		s.SpanContext.TraceID = t.generate.TraceID()
+		s.SpanContext.ID = t.generate.SpanID(s.SpanContext.TraceID)
+	} else {
+		// valid parent context found
+		if t.sharedSpans && s.Kind == model.Server {
+			// join span
+			s.Shared = true
+		} else {
+			// regular child span
+			parentID := s.SpanContext.ID
+			s.SpanContext.ParentID = &parentID
+			s.SpanContext.ID = t.generate.SpanID(model.TraceID{})
+		}
+	}
+
+	if !s.SpanContext.Debug && s.Sampled == nil {
+		// deferred sampled context found, invoke sampler
+		sampled := t.sampler(s.SpanContext.TraceID.Low)
+		s.SpanContext.Sampled = &sampled
+		if sampled {
+			s.mustCollect = 1
+		}
+	} else {
+		if s.SpanContext.Debug || *s.Sampled {
+			s.mustCollect = 1
+		}
+	}
+
+	if t.unsampledNoop && s.mustCollect == 0 {
+		// trace not being sampled and noop requested
+		return &noopSpan{
+			SpanContext: s.SpanContext,
+		}
+	}
+
+	// add start time
+	if s.Timestamp.IsZero() {
+		s.Timestamp = time.Now()
+	}
+
+	return s
+}
+
+// Extract extracts a SpanContext using the provided Extractor function.
+func (t *Tracer) Extract(extractor propagation.Extractor) (sc model.SpanContext) {
+	if atomic.LoadInt32(&t.noop) == 1 {
+		return
+	}
+	psc, err := extractor()
+	if psc != nil {
+		sc = *psc
+	}
+	sc.Err = err
+	return
+}
+
+// SetNoop allows for killswitch behavior. If set to true the tracer will return
+// noopSpans and all data is dropped. This allows operators to stop tracing in
+// risk scenarios. Set back to false to resume tracing.
+func (t *Tracer) SetNoop(noop bool) {
+	if noop {
+		atomic.CompareAndSwapInt32(&t.noop, 0, 1)
+	} else {
+		atomic.CompareAndSwapInt32(&t.noop, 1, 0)
+	}
+}
+
+// LocalEndpoint returns a copy of the currently set local endpoint of the
+// tracer instance.
+func (t *Tracer) LocalEndpoint() *model.Endpoint {
+	if t.localEndpoint == nil {
+		return nil
+	}
+	ep := *t.localEndpoint
+	return &ep
+}
diff --git a/vendor/github.com/openzipkin/zipkin-go/tracer_options.go b/vendor/github.com/openzipkin/zipkin-go/tracer_options.go
new file mode 100644
index 0000000..7a3608f
--- /dev/null
+++ b/vendor/github.com/openzipkin/zipkin-go/tracer_options.go
@@ -0,0 +1,124 @@
+package zipkin
+
+import (
+	"errors"
+
+	"github.com/openzipkin/zipkin-go/idgenerator"
+	"github.com/openzipkin/zipkin-go/model"
+)
+
+// Tracer Option Errors
+var (
+	ErrInvalidEndpoint             = errors.New("requires valid local endpoint")
+	ErrInvalidExtractFailurePolicy = errors.New("invalid extract failure policy provided")
+)
+
+// ExtractFailurePolicy deals with Extraction errors
+type ExtractFailurePolicy int
+
+// ExtractFailurePolicyOptions
+const (
+	ExtractFailurePolicyRestart ExtractFailurePolicy = iota
+	ExtractFailurePolicyError
+	ExtractFailurePolicyTagAndRestart
+)
+
+// TracerOption allows for functional options to adjust behavior of the Tracer
+// to be created with NewTracer().
+type TracerOption func(o *Tracer) error
+
+// WithLocalEndpoint sets the local endpoint of the tracer.
+func WithLocalEndpoint(e *model.Endpoint) TracerOption {
+	return func(o *Tracer) error {
+		if e == nil {
+			o.localEndpoint = nil
+			return nil
+		}
+		ep := *e
+		o.localEndpoint = &ep
+		return nil
+	}
+}
+
+// WithExtractFailurePolicy allows one to set the ExtractFailurePolicy.
+func WithExtractFailurePolicy(p ExtractFailurePolicy) TracerOption {
+	return func(o *Tracer) error {
+		if p < 0 || p > ExtractFailurePolicyTagAndRestart {
+			return ErrInvalidExtractFailurePolicy
+		}
+		o.extractFailurePolicy = p
+		return nil
+	}
+}
+
+// WithNoopSpan if set to true will switch to a NoopSpan implementation
+// if the trace is not sampled.
+func WithNoopSpan(unsampledNoop bool) TracerOption {
+	return func(o *Tracer) error {
+		o.unsampledNoop = unsampledNoop
+		return nil
+	}
+}
+
+// WithSharedSpans allows to place client-side and server-side annotations
+// for a RPC call in the same span (Zipkin V1 behavior) or different spans
+// (more in line with other tracing solutions). By default this Tracer
+// uses shared host spans (so client-side and server-side in the same span).
+func WithSharedSpans(val bool) TracerOption {
+	return func(o *Tracer) error {
+		o.sharedSpans = val
+		return nil
+	}
+}
+
+// WithSampler allows one to set a Sampler function
+func WithSampler(sampler Sampler) TracerOption {
+	return func(o *Tracer) error {
+		o.sampler = sampler
+		return nil
+	}
+}
+
+// WithTraceID128Bit if set to true will instruct the Tracer to start traces
+// with 128 bit TraceID's. If set to false the Tracer will start traces with
+// 64 bits.
+func WithTraceID128Bit(val bool) TracerOption {
+	return func(o *Tracer) error {
+		if val {
+			o.generate = idgenerator.NewRandom128()
+		} else {
+			o.generate = idgenerator.NewRandom64()
+		}
+		return nil
+	}
+}
+
+// WithIDGenerator allows one to set a custom ID Generator
+func WithIDGenerator(generator idgenerator.IDGenerator) TracerOption {
+	return func(o *Tracer) error {
+		o.generate = generator
+		return nil
+	}
+}
+
+// WithTags allows one to set default tags to be added to each created span
+func WithTags(tags map[string]string) TracerOption {
+	return func(o *Tracer) error {
+		for k, v := range tags {
+			o.defaultTags[k] = v
+		}
+		return nil
+	}
+}
+
+// WithNoopTracer allows one to start the Tracer as Noop implementation.
+func WithNoopTracer(tracerNoop bool) TracerOption {
+	return func(o *Tracer) error {
+		if tracerNoop {
+			o.noop = 1
+		} else {
+			o.noop = 0
+		}
+		return nil
+	}
+}
diff --git a/vendor/go.opencensus.io/AUTHORS b/vendor/go.opencensus.io/AUTHORS
new file mode 100644
index 0000000..e491a9e
--- /dev/null
+++ b/vendor/go.opencensus.io/AUTHORS
@@ -0,0 +1 @@
+Google Inc.
diff --git a/vendor/go.opencensus.io/CONTRIBUTING.md b/vendor/go.opencensus.io/CONTRIBUTING.md
new file mode 100644
index 0000000..3f3aed3
--- /dev/null
+++ b/vendor/go.opencensus.io/CONTRIBUTING.md
@@ -0,0 +1,56 @@
+# How to contribute
+
+We'd love to accept your patches and contributions to this project. There are
+just a few small guidelines you need to follow.
+
+## Contributor License Agreement
+
+Contributions to this project must be accompanied by a Contributor License
+Agreement. You (or your employer) retain the copyright to your contribution,
+this simply gives us permission to use and redistribute your contributions as
+part of the project. Head over to <https://cla.developers.google.com/> to see
+your current agreements on file or to sign a new one.
+
+You generally only need to submit a CLA once, so if you've already submitted one
+(even if it was for a different project), you probably don't need to do it
+again.
+
+## Code reviews
+
+All submissions, including submissions by project members, require review. We
+use GitHub pull requests for this purpose. Consult [GitHub Help] for more
+information on using pull requests.
+
+[GitHub Help]: https://help.github.com/articles/about-pull-requests/
+
+## Instructions
+
+Fork the repo, checkout the upstream repo to your GOPATH by:
+
+```
+$ go get -d go.opencensus.io
+```
+
+Add your fork as an origin:
+
+```
+cd $(go env GOPATH)/src/go.opencensus.io
+git remote add fork git@github.com:YOUR_GITHUB_USERNAME/opencensus-go.git
+```
+
+Run tests:
+
+```
+$ go test ./...
+```
+
+Checkout a new branch, make modifications and push the branch to your fork:
+
+```
+$ git checkout -b feature
+# edit files
+$ git commit
+$ git push fork feature
+```
+
+Open a pull request against the main opencensus-go repo.
diff --git a/vendor/go.opencensus.io/Gopkg.lock b/vendor/go.opencensus.io/Gopkg.lock
new file mode 100644
index 0000000..3be12ac
--- /dev/null
+++ b/vendor/go.opencensus.io/Gopkg.lock
@@ -0,0 +1,231 @@
+# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
+
+
+[[projects]]
+  branch = "master"
+  digest = "1:eee9386329f4fcdf8d6c0def0c9771b634bdd5ba460d888aa98c17d59b37a76c"
+  name = "git.apache.org/thrift.git"
+  packages = ["lib/go/thrift"]
+  pruneopts = "UT"
+  revision = "6e67faa92827ece022380b211c2caaadd6145bf5"
+  source = "github.com/apache/thrift"
+
+[[projects]]
+  branch = "master"
+  digest = "1:d6afaeed1502aa28e80a4ed0981d570ad91b2579193404256ce672ed0a609e0d"
+  name = "github.com/beorn7/perks"
+  packages = ["quantile"]
+  pruneopts = "UT"
+  revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
+
+[[projects]]
+  digest = "1:4c0989ca0bcd10799064318923b9bc2db6b4d6338dd75f3f2d86c3511aaaf5cf"
+  name = "github.com/golang/protobuf"
+  packages = [
+    "proto",
+    "ptypes",
+    "ptypes/any",
+    "ptypes/duration",
+    "ptypes/timestamp",
+  ]
+  pruneopts = "UT"
+  revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
+  version = "v1.2.0"
+
+[[projects]]
+  digest = "1:ff5ebae34cfbf047d505ee150de27e60570e8c394b3b8fdbb720ff6ac71985fc"
+  name = "github.com/matttproud/golang_protobuf_extensions"
+  packages = ["pbutil"]
+  pruneopts = "UT"
+  revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
+  version = "v1.0.1"
+
+[[projects]]
+  digest = "1:824c8f3aa4c5f23928fa84ebbd5ed2e9443b3f0cb958a40c1f2fbed5cf5e64b1"
+  name = "github.com/openzipkin/zipkin-go"
+  packages = [
+    ".",
+    "idgenerator",
+    "model",
+    "propagation",
+    "reporter",
+    "reporter/http",
+  ]
+  pruneopts = "UT"
+  revision = "d455a5674050831c1e187644faa4046d653433c2"
+  version = "v0.1.1"
+
+[[projects]]
+  digest = "1:d14a5f4bfecf017cb780bdde1b6483e5deb87e12c332544d2c430eda58734bcb"
+  name = "github.com/prometheus/client_golang"
+  packages = [
+    "prometheus",
+    "prometheus/promhttp",
+  ]
+  pruneopts = "UT"
+  revision = "c5b7fccd204277076155f10851dad72b76a49317"
+  version = "v0.8.0"
+
+[[projects]]
+  branch = "master"
+  digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4"
+  name = "github.com/prometheus/client_model"
+  packages = ["go"]
+  pruneopts = "UT"
+  revision = "5c3871d89910bfb32f5fcab2aa4b9ec68e65a99f"
+
+[[projects]]
+  branch = "master"
+  digest = "1:63b68062b8968092eb86bedc4e68894bd096ea6b24920faca8b9dcf451f54bb5"
+  name = "github.com/prometheus/common"
+  packages = [
+    "expfmt",
+    "internal/bitbucket.org/ww/goautoneg",
+    "model",
+  ]
+  pruneopts = "UT"
+  revision = "c7de2306084e37d54b8be01f3541a8464345e9a5"
+
+[[projects]]
+  branch = "master"
+  digest = "1:8c49953a1414305f2ff5465147ee576dd705487c35b15918fcd4efdc0cb7a290"
+  name = "github.com/prometheus/procfs"
+  packages = [
+    ".",
+    "internal/util",
+    "nfs",
+    "xfs",
+  ]
+  pruneopts = "UT"
+  revision = "05ee40e3a273f7245e8777337fc7b46e533a9a92"
+
+[[projects]]
+  branch = "master"
+  digest = "1:deafe4ab271911fec7de5b693d7faae3f38796d9eb8622e2b9e7df42bb3dfea9"
+  name = "golang.org/x/net"
+  packages = [
+    "context",
+    "http/httpguts",
+    "http2",
+    "http2/hpack",
+    "idna",
+    "internal/timeseries",
+    "trace",
+  ]
+  pruneopts = "UT"
+  revision = "922f4815f713f213882e8ef45e0d315b164d705c"
+
+[[projects]]
+  branch = "master"
+  digest = "1:e0140c0c868c6e0f01c0380865194592c011fe521d6e12d78bfd33e756fe018a"
+  name = "golang.org/x/sync"
+  packages = ["semaphore"]
+  pruneopts = "UT"
+  revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca"
+
+[[projects]]
+  branch = "master"
+  digest = "1:a3f00ac457c955fe86a41e1495e8f4c54cb5399d609374c5cc26aa7d72e542c8"
+  name = "golang.org/x/sys"
+  packages = ["unix"]
+  pruneopts = "UT"
+  revision = "3b58ed4ad3395d483fc92d5d14123ce2c3581fec"
+
+[[projects]]
+  digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18"
+  name = "golang.org/x/text"
+  packages = [
+    "collate",
+    "collate/build",
+    "internal/colltab",
+    "internal/gen",
+    "internal/tag",
+    "internal/triegen",
+    "internal/ucd",
+    "language",
+    "secure/bidirule",
+    "transform",
+    "unicode/bidi",
+    "unicode/cldr",
+    "unicode/norm",
+    "unicode/rangetable",
+  ]
+  pruneopts = "UT"
+  revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
+  version = "v0.3.0"
+
+[[projects]]
+  branch = "master"
+  digest = "1:c0c17c94fe8bc1ab34e7f586a4a8b788c5e1f4f9f750ff23395b8b2f5a523530"
+  name = "google.golang.org/api"
+  packages = ["support/bundler"]
+  pruneopts = "UT"
+  revision = "e21acd801f91da814261b938941d193bb036441a"
+
+[[projects]]
+  branch = "master"
+  digest = "1:077c1c599507b3b3e9156d17d36e1e61928ee9b53a5b420f10f28ebd4a0b275c"
+  name = "google.golang.org/genproto"
+  packages = ["googleapis/rpc/status"]
+  pruneopts = "UT"
+  revision = "c66870c02cf823ceb633bcd05be3c7cda29976f4"
+
+[[projects]]
+  digest = "1:3dd7996ce6bf52dec6a2f69fa43e7c4cefea1d4dfa3c8ab7a5f8a9f7434e239d"
+  name = "google.golang.org/grpc"
+  packages = [
+    ".",
+    "balancer",
+    "balancer/base",
+    "balancer/roundrobin",
+    "codes",
+    "connectivity",
+    "credentials",
+    "encoding",
+    "encoding/proto",
+    "grpclog",
+    "internal",
+    "internal/backoff",
+    "internal/channelz",
+    "internal/envconfig",
+    "internal/grpcrand",
+    "internal/transport",
+    "keepalive",
+    "metadata",
+    "naming",
+    "peer",
+    "resolver",
+    "resolver/dns",
+    "resolver/passthrough",
+    "stats",
+    "status",
+    "tap",
+  ]
+  pruneopts = "UT"
+  revision = "32fb0ac620c32ba40a4626ddf94d90d12cce3455"
+  version = "v1.14.0"
+
+[solve-meta]
+  analyzer-name = "dep"
+  analyzer-version = 1
+  input-imports = [
+    "git.apache.org/thrift.git/lib/go/thrift",
+    "github.com/golang/protobuf/proto",
+    "github.com/openzipkin/zipkin-go",
+    "github.com/openzipkin/zipkin-go/model",
+    "github.com/openzipkin/zipkin-go/reporter",
+    "github.com/openzipkin/zipkin-go/reporter/http",
+    "github.com/prometheus/client_golang/prometheus",
+    "github.com/prometheus/client_golang/prometheus/promhttp",
+    "golang.org/x/net/context",
+    "golang.org/x/net/http2",
+    "google.golang.org/api/support/bundler",
+    "google.golang.org/grpc",
+    "google.golang.org/grpc/codes",
+    "google.golang.org/grpc/grpclog",
+    "google.golang.org/grpc/metadata",
+    "google.golang.org/grpc/stats",
+    "google.golang.org/grpc/status",
+  ]
+  solver-name = "gps-cdcl"
+  solver-version = 1
diff --git a/vendor/go.opencensus.io/Gopkg.toml b/vendor/go.opencensus.io/Gopkg.toml
new file mode 100644
index 0000000..a9f3cd6
--- /dev/null
+++ b/vendor/go.opencensus.io/Gopkg.toml
@@ -0,0 +1,36 @@
+# For v0.x.y dependencies, prefer adding a constraints of the form: version=">= 0.x.y"
+# to avoid locking to a particular minor version which can cause dep to not be
+# able to find a satisfying dependency graph.
+
+[[constraint]]
+  branch = "master"
+  name = "git.apache.org/thrift.git"
+  source = "github.com/apache/thrift"
+
+[[constraint]]
+  name = "github.com/golang/protobuf"
+  version = "1.0.0"
+
+[[constraint]]
+  name = "github.com/openzipkin/zipkin-go"
+  version = ">=0.1.0"
+
+[[constraint]]
+  name = "github.com/prometheus/client_golang"
+  version = ">=0.8.0"
+
+[[constraint]]
+  branch = "master"
+  name = "golang.org/x/net"
+
+[[constraint]]
+  branch = "master"
+  name = "google.golang.org/api"
+
+[[constraint]]
+  name = "google.golang.org/grpc"
+  version = "1.11.3"
+
+[prune]
+  go-tests = true
+  unused-packages = true
diff --git a/vendor/go.opencensus.io/LICENSE b/vendor/go.opencensus.io/LICENSE
new file mode 100644
index 0000000..7a4a3ea
--- /dev/null
+++ b/vendor/go.opencensus.io/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
\ No newline at end of file
diff --git a/vendor/go.opencensus.io/README.md b/vendor/go.opencensus.io/README.md
new file mode 100644
index 0000000..b8a5107
--- /dev/null
+++ b/vendor/go.opencensus.io/README.md
@@ -0,0 +1,263 @@
+# OpenCensus Libraries for Go
+
+[![Build Status][travis-image]][travis-url]
+[![Windows Build Status][appveyor-image]][appveyor-url]
+[![GoDoc][godoc-image]][godoc-url]
+[![Gitter chat][gitter-image]][gitter-url]
+
+OpenCensus Go is a Go implementation of OpenCensus, a toolkit for
+collecting application performance and behavior monitoring data.
+Currently it consists of three major components: tags, stats and tracing.
+
+## Installation
+
+```
+$ go get -u go.opencensus.io
+```
+
+The API of this project is still evolving, see: [Deprecation Policy](#deprecation-policy).
+The use of vendoring or a dependency management tool is recommended.
+
+## Prerequisites
+
+OpenCensus Go libraries require Go 1.8 or later.
+
+## Getting Started
+
+The easiest way to get started using OpenCensus in your application is to use an existing
+integration with your RPC framework:
+
+* [net/http](https://godoc.org/go.opencensus.io/plugin/ochttp)
+* [gRPC](https://godoc.org/go.opencensus.io/plugin/ocgrpc)
+* [database/sql](https://godoc.org/github.com/opencensus-integrations/ocsql)
+* [Go kit](https://godoc.org/github.com/go-kit/kit/tracing/opencensus)
+* [Groupcache](https://godoc.org/github.com/orijtech/groupcache)
+* [Caddy webserver](https://godoc.org/github.com/orijtech/caddy)
+* [MongoDB](https://godoc.org/github.com/orijtech/mongo-go-driver)
+* [Redis gomodule/redigo](https://godoc.org/github.com/orijtech/redigo)
+* [Redis goredis/redis](https://godoc.org/github.com/orijtech/redis)
+* [Memcache](https://godoc.org/github.com/orijtech/gomemcache)
+
+If you're using a framework not listed here, you could either implement your own middleware for your
+framework or use [custom stats](#stats) and [spans](#spans) directly in your application.
+
+## Exporters
+
+OpenCensus can export instrumentation data to various backends.
+OpenCensus has exporter implementations for the following, users
+can implement their own exporters by implementing the exporter interfaces
+([stats](https://godoc.org/go.opencensus.io/stats/view#Exporter),
+[trace](https://godoc.org/go.opencensus.io/trace#Exporter)):
+
+* [Prometheus][exporter-prom] for stats
+* [OpenZipkin][exporter-zipkin] for traces
+* [Stackdriver][exporter-stackdriver] Monitoring for stats and Trace for traces
+* [Jaeger][exporter-jaeger] for traces
+* [AWS X-Ray][exporter-xray] for traces
+* [Datadog][exporter-datadog] for stats and traces
+* [Graphite][exporter-graphite] for stats
+* [Honeycomb][exporter-honeycomb] for traces
+
+## Overview
+
+![OpenCensus Overview](https://i.imgur.com/cf4ElHE.jpg)
+
+In a microservices environment, a user request may go through
+multiple services until there is a response. OpenCensus allows
+you to instrument your services and collect diagnostics data all
+through your services end-to-end.
+
+## Tags
+
+Tags represent propagated key-value pairs. They are propagated using `context.Context`
+in the same process or can be encoded to be transmitted on the wire. Usually, this will
+be handled by an integration plugin, e.g. `ocgrpc.ServerHandler` and `ocgrpc.ClientHandler`
+for gRPC.
+
+Package `tag` allows adding or modifying tags in the current context.
+
+[embedmd]:# (internal/readme/tags.go new)
+```go
+ctx, err = tag.New(ctx,
+	tag.Insert(osKey, "macOS-10.12.5"),
+	tag.Upsert(userIDKey, "cde36753ed"),
+)
+if err != nil {
+	log.Fatal(err)
+}
+```
+
+## Stats
+
+OpenCensus is a low-overhead framework even if instrumentation is always enabled.
+In order to be so, it is optimized to make recording of data points fast
+and separate from the data aggregation.
+
+OpenCensus stats collection happens in two stages:
+
+* Definition of measures and recording of data points
+* Definition of views and aggregation of the recorded data
+
+### Recording
+
+Measurements are data points associated with a measure.
+Recording implicitly tags the set of Measurements with the tags from the
+provided context:
+
+[embedmd]:# (internal/readme/stats.go record)
+```go
+stats.Record(ctx, videoSize.M(102478))
+```
+
+### Views
+
+Views are how Measures are aggregated. You can think of them as queries over the
+set of recorded data points (measurements).
+
+Views have two parts: the tags to group by and the aggregation type used.
+
+Currently three types of aggregations are supported:
+* CountAggregation is used to count the number of times a sample was recorded.
+* DistributionAggregation is used to provide a histogram of the values of the samples.
+* SumAggregation is used to sum up all sample values.
+
+[embedmd]:# (internal/readme/stats.go aggs)
+```go
+distAgg := view.Distribution(0, 1<<32, 2<<32, 3<<32)
+countAgg := view.Count()
+sumAgg := view.Sum()
+```
+
+Here we create a view with the DistributionAggregation over our measure.
+
+[embedmd]:# (internal/readme/stats.go view)
+```go
+if err := view.Register(&view.View{
+	Name:        "example.com/video_size_distribution",
+	Description: "distribution of processed video size over time",
+	Measure:     videoSize,
+	Aggregation: view.Distribution(0, 1<<32, 2<<32, 3<<32),
+}); err != nil {
+	log.Fatalf("Failed to register view: %v", err)
+}
+```
+
+Register begins collecting data for the view. Registered views' data will be
+exported via the registered exporters.
+
+## Traces
+
+A distributed trace tracks the progression of a single user request as
+it is handled by the services and processes that make up an application.
+Each step is called a span in the trace. Spans include metadata about the step,
+including especially the time spent in the step, called the span’s latency.
+
+Below you see a trace and several spans underneath it.
+
+![Traces and spans](https://i.imgur.com/7hZwRVj.png)
+
+### Spans
+
+Span is the unit step in a trace. Each span has a name, latency, status and
+additional metadata.
+
+Below we are starting a span for a cache read and ending it
+when we are done:
+
+[embedmd]:# (internal/readme/trace.go startend)
+```go
+ctx, span := trace.StartSpan(ctx, "cache.Get")
+defer span.End()
+
+// Do work to get from cache.
+```
+
+### Propagation
+
+Spans can have parents or can be root spans if they don't have any parents.
+The current span is propagated in-process and across the network to allow associating
+new child spans with the parent.
+
+In the same process, `context.Context` is used to propagate spans.
+`trace.StartSpan` creates a new span as a root if the current context
+doesn't contain a span. Or, it creates a child of the span that is
+already in current context. The returned context can be used to keep
+propagating the newly created span in the current context.
+
+[embedmd]:# (internal/readme/trace.go startend)
+```go
+ctx, span := trace.StartSpan(ctx, "cache.Get")
+defer span.End()
+
+// Do work to get from cache.
+```
+
+Across the network, OpenCensus provides different propagation
+methods for different protocols.
+
+* gRPC integrations use the OpenCensus' [binary propagation format](https://godoc.org/go.opencensus.io/trace/propagation).
+* HTTP integrations use Zipkin's [B3](https://github.com/openzipkin/b3-propagation)
+  by default but can be configured to use a custom propagation method by setting another
+  [propagation.HTTPFormat](https://godoc.org/go.opencensus.io/trace/propagation#HTTPFormat).
+
+## Execution Tracer
+
+With Go 1.11, OpenCensus Go will support integration with the Go execution tracer.
+See [Debugging Latency in Go](https://medium.com/observability/debugging-latency-in-go-1-11-9f97a7910d68)
+for an example of their mutual use.
+
+## Profiles
+
+OpenCensus tags can be applied as profiler labels
+for users who are on Go 1.9 and above.
+
+[embedmd]:# (internal/readme/tags.go profiler)
+```go
+ctx, err = tag.New(ctx,
+	tag.Insert(osKey, "macOS-10.12.5"),
+	tag.Insert(userIDKey, "fff0989878"),
+)
+if err != nil {
+	log.Fatal(err)
+}
+tag.Do(ctx, func(ctx context.Context) {
+	// Do work.
+	// When profiling is on, samples will be
+	// recorded with the key/values from the tag map.
+})
+```
+
+A screenshot of the CPU profile from the program above:
+
+![CPU profile](https://i.imgur.com/jBKjlkw.png)
+
+## Deprecation Policy
+
+Before version 1.0.0, the following deprecation policy will be observed:
+
+No backwards-incompatible changes will be made except for the removal of symbols that have
+been marked as *Deprecated* for at least one minor release (e.g. 0.9.0 to 0.10.0). A release
+removing the *Deprecated* functionality will be made no sooner than 28 days after the first
+release in which the functionality was marked *Deprecated*.
+
+[travis-image]: https://travis-ci.org/census-instrumentation/opencensus-go.svg?branch=master
+[travis-url]: https://travis-ci.org/census-instrumentation/opencensus-go
+[appveyor-image]: https://ci.appveyor.com/api/projects/status/vgtt29ps1783ig38?svg=true
+[appveyor-url]: https://ci.appveyor.com/project/opencensusgoteam/opencensus-go/branch/master
+[godoc-image]: https://godoc.org/go.opencensus.io?status.svg
+[godoc-url]: https://godoc.org/go.opencensus.io
+[gitter-image]: https://badges.gitter.im/census-instrumentation/lobby.svg
+[gitter-url]: https://gitter.im/census-instrumentation/lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
+
+
+[new-ex]: https://godoc.org/go.opencensus.io/tag#example-NewMap
+[new-replace-ex]: https://godoc.org/go.opencensus.io/tag#example-NewMap--Replace
+
+[exporter-prom]: https://godoc.org/go.opencensus.io/exporter/prometheus
+[exporter-stackdriver]: https://godoc.org/contrib.go.opencensus.io/exporter/stackdriver
+[exporter-zipkin]: https://godoc.org/go.opencensus.io/exporter/zipkin
+[exporter-jaeger]: https://godoc.org/go.opencensus.io/exporter/jaeger
+[exporter-xray]: https://github.com/census-ecosystem/opencensus-go-exporter-aws
+[exporter-datadog]: https://github.com/DataDog/opencensus-go-exporter-datadog
+[exporter-graphite]: https://github.com/census-ecosystem/opencensus-go-exporter-graphite
+[exporter-honeycomb]: https://github.com/honeycombio/opencensus-exporter
diff --git a/vendor/go.opencensus.io/appveyor.yml b/vendor/go.opencensus.io/appveyor.yml
new file mode 100644
index 0000000..9805788
--- /dev/null
+++ b/vendor/go.opencensus.io/appveyor.yml
@@ -0,0 +1,24 @@
+version: "{build}"
+
+platform: x64
+
+clone_folder: c:\gopath\src\go.opencensus.io
+
+environment:
+  GOPATH: 'c:\gopath'
+  GOVERSION: '1.11'
+  GO111MODULE: 'on'
+  CGO_ENABLED: '0' # See: https://github.com/appveyor/ci/issues/2613
+
+install:
+  - set PATH=%GOPATH%\bin;c:\go\bin;%PATH%
+  - go version
+  - go env
+
+build: false
+deploy: false
+
+test_script:
+  - cd %APPVEYOR_BUILD_FOLDER%
+  - go build -v .\...
+  - go test -v .\... # No -race because cgo is disabled
diff --git a/vendor/go.opencensus.io/exemplar/exemplar.go b/vendor/go.opencensus.io/exemplar/exemplar.go
new file mode 100644
index 0000000..e676df8
--- /dev/null
+++ b/vendor/go.opencensus.io/exemplar/exemplar.go
@@ -0,0 +1,78 @@
+// Copyright 2018, 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 exemplar implements support for exemplars. Exemplars are additional
+// data associated with each measurement.
+//
+// Their purpose it to provide an example of the kind of thing
+// (request, RPC, trace span, etc.) that resulted in that measurement.
+package exemplar
+
+import (
+	"context"
+	"time"
+)
+
+const (
+	KeyTraceID   = "trace_id"
+	KeySpanID    = "span_id"
+	KeyPrefixTag = "tag:"
+)
+
+// Exemplar is an example data point associated with each bucket of a
+// distribution type aggregation.
+type Exemplar struct {
+	Value       float64     // the value that was recorded
+	Timestamp   time.Time   // the time the value was recorded
+	Attachments Attachments // attachments (if any)
+}
+
+// Attachments is a map of extra values associated with a recorded data point.
+// The map should only be mutated from AttachmentExtractor functions.
+type Attachments map[string]string
+
+// AttachmentExtractor is a function capable of extracting exemplar attachments
+// from the context used to record measurements.
+// The map passed to the function should be mutated and returned. It will
+// initially be nil: the first AttachmentExtractor that would like to add keys to the
+// map is responsible for initializing it.
+type AttachmentExtractor func(ctx context.Context, a Attachments) Attachments
+
+var extractors []AttachmentExtractor
+
+// RegisterAttachmentExtractor registers the given extractor associated with the exemplar
+// type name.
+//
+// Extractors will be used to attempt to extract exemplars from the context
+// associated with each recorded measurement.
+//
+// Packages that support exemplars should register their extractor functions on
+// initialization.
+//
+// RegisterAttachmentExtractor should not be called after any measurements have
+// been recorded.
+func RegisterAttachmentExtractor(e AttachmentExtractor) {
+	extractors = append(extractors, e)
+}
+
+// NewFromContext extracts exemplars from the given context.
+// Each registered AttachmentExtractor (see RegisterAttachmentExtractor) is called in an
+// unspecified order to add attachments to the exemplar.
+func AttachmentsFromContext(ctx context.Context) Attachments {
+	var a Attachments
+	for _, extractor := range extractors {
+		a = extractor(ctx, a)
+	}
+	return a
+}
diff --git a/vendor/go.opencensus.io/exporter/zipkin/zipkin.go b/vendor/go.opencensus.io/exporter/zipkin/zipkin.go
new file mode 100644
index 0000000..30d2fa4
--- /dev/null
+++ b/vendor/go.opencensus.io/exporter/zipkin/zipkin.go
@@ -0,0 +1,194 @@
+// 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 zipkin contains an trace exporter for Zipkin.
+package zipkin // import "go.opencensus.io/exporter/zipkin"
+
+import (
+	"encoding/binary"
+	"strconv"
+
+	"github.com/openzipkin/zipkin-go/model"
+	"github.com/openzipkin/zipkin-go/reporter"
+	"go.opencensus.io/trace"
+)
+
+// Exporter is an implementation of trace.Exporter that uploads spans to a
+// Zipkin server.
+type Exporter struct {
+	reporter      reporter.Reporter
+	localEndpoint *model.Endpoint
+}
+
+// NewExporter returns an implementation of trace.Exporter that uploads spans
+// to a Zipkin server.
+//
+// reporter is a Zipkin Reporter which will be used to send the spans.  These
+// can be created with the openzipkin library, using one of the packages under
+// github.com/openzipkin/zipkin-go/reporter.
+//
+// localEndpoint sets the local endpoint of exported spans.  It can be
+// constructed with github.com/openzipkin/zipkin-go.NewEndpoint, e.g.:
+// 	localEndpoint, err := NewEndpoint("my server", listener.Addr().String())
+// localEndpoint can be nil.
+func NewExporter(reporter reporter.Reporter, localEndpoint *model.Endpoint) *Exporter {
+	return &Exporter{
+		reporter:      reporter,
+		localEndpoint: localEndpoint,
+	}
+}
+
+// ExportSpan exports a span to a Zipkin server.
+func (e *Exporter) ExportSpan(s *trace.SpanData) {
+	e.reporter.Send(zipkinSpan(s, e.localEndpoint))
+}
+
+const (
+	statusCodeTagKey        = "error"
+	statusDescriptionTagKey = "opencensus.status_description"
+)
+
+var (
+	sampledTrue    = true
+	canonicalCodes = [...]string{
+		"OK",
+		"CANCELLED",
+		"UNKNOWN",
+		"INVALID_ARGUMENT",
+		"DEADLINE_EXCEEDED",
+		"NOT_FOUND",
+		"ALREADY_EXISTS",
+		"PERMISSION_DENIED",
+		"RESOURCE_EXHAUSTED",
+		"FAILED_PRECONDITION",
+		"ABORTED",
+		"OUT_OF_RANGE",
+		"UNIMPLEMENTED",
+		"INTERNAL",
+		"UNAVAILABLE",
+		"DATA_LOSS",
+		"UNAUTHENTICATED",
+	}
+)
+
+func canonicalCodeString(code int32) string {
+	if code < 0 || int(code) >= len(canonicalCodes) {
+		return "error code " + strconv.FormatInt(int64(code), 10)
+	}
+	return canonicalCodes[code]
+}
+
+func convertTraceID(t trace.TraceID) model.TraceID {
+	return model.TraceID{
+		High: binary.BigEndian.Uint64(t[:8]),
+		Low:  binary.BigEndian.Uint64(t[8:]),
+	}
+}
+
+func convertSpanID(s trace.SpanID) model.ID {
+	return model.ID(binary.BigEndian.Uint64(s[:]))
+}
+
+func spanKind(s *trace.SpanData) model.Kind {
+	switch s.SpanKind {
+	case trace.SpanKindClient:
+		return model.Client
+	case trace.SpanKindServer:
+		return model.Server
+	}
+	return model.Undetermined
+}
+
+func zipkinSpan(s *trace.SpanData, localEndpoint *model.Endpoint) model.SpanModel {
+	sc := s.SpanContext
+	z := model.SpanModel{
+		SpanContext: model.SpanContext{
+			TraceID: convertTraceID(sc.TraceID),
+			ID:      convertSpanID(sc.SpanID),
+			Sampled: &sampledTrue,
+		},
+		Kind:          spanKind(s),
+		Name:          s.Name,
+		Timestamp:     s.StartTime,
+		Shared:        false,
+		LocalEndpoint: localEndpoint,
+	}
+
+	if s.ParentSpanID != (trace.SpanID{}) {
+		id := convertSpanID(s.ParentSpanID)
+		z.ParentID = &id
+	}
+
+	if s, e := s.StartTime, s.EndTime; !s.IsZero() && !e.IsZero() {
+		z.Duration = e.Sub(s)
+	}
+
+	// construct Tags from s.Attributes and s.Status.
+	if len(s.Attributes) != 0 {
+		m := make(map[string]string, len(s.Attributes)+2)
+		for key, value := range s.Attributes {
+			switch v := value.(type) {
+			case string:
+				m[key] = v
+			case bool:
+				if v {
+					m[key] = "true"
+				} else {
+					m[key] = "false"
+				}
+			case int64:
+				m[key] = strconv.FormatInt(v, 10)
+			}
+		}
+		z.Tags = m
+	}
+	if s.Status.Code != 0 || s.Status.Message != "" {
+		if z.Tags == nil {
+			z.Tags = make(map[string]string, 2)
+		}
+		if s.Status.Code != 0 {
+			z.Tags[statusCodeTagKey] = canonicalCodeString(s.Status.Code)
+		}
+		if s.Status.Message != "" {
+			z.Tags[statusDescriptionTagKey] = s.Status.Message
+		}
+	}
+
+	// construct Annotations from s.Annotations and s.MessageEvents.
+	if len(s.Annotations) != 0 || len(s.MessageEvents) != 0 {
+		z.Annotations = make([]model.Annotation, 0, len(s.Annotations)+len(s.MessageEvents))
+		for _, a := range s.Annotations {
+			z.Annotations = append(z.Annotations, model.Annotation{
+				Timestamp: a.Time,
+				Value:     a.Message,
+			})
+		}
+		for _, m := range s.MessageEvents {
+			a := model.Annotation{
+				Timestamp: m.Time,
+			}
+			switch m.EventType {
+			case trace.MessageEventTypeSent:
+				a.Value = "SENT"
+			case trace.MessageEventTypeRecv:
+				a.Value = "RECV"
+			default:
+				a.Value = "<?>"
+			}
+			z.Annotations = append(z.Annotations, a)
+		}
+	}
+
+	return z
+}
diff --git a/vendor/go.opencensus.io/go.mod b/vendor/go.opencensus.io/go.mod
new file mode 100644
index 0000000..1236f4c
--- /dev/null
+++ b/vendor/go.opencensus.io/go.mod
@@ -0,0 +1,25 @@
+module go.opencensus.io
+
+require (
+	git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999
+	github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973
+	github.com/ghodss/yaml v1.0.0 // indirect
+	github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
+	github.com/golang/protobuf v1.2.0
+	github.com/google/go-cmp v0.2.0
+	github.com/grpc-ecosystem/grpc-gateway v1.5.0 // indirect
+	github.com/matttproud/golang_protobuf_extensions v1.0.1
+	github.com/openzipkin/zipkin-go v0.1.1
+	github.com/prometheus/client_golang v0.8.0
+	github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910
+	github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e
+	github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273
+	golang.org/x/net v0.0.0-20180906233101-161cd47e91fd
+	golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f
+	golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e
+	golang.org/x/text v0.3.0
+	google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf
+	google.golang.org/genproto v0.0.0-20180831171423-11092d34479b
+	google.golang.org/grpc v1.14.0
+	gopkg.in/yaml.v2 v2.2.1 // indirect
+)
diff --git a/vendor/go.opencensus.io/go.sum b/vendor/go.opencensus.io/go.sum
new file mode 100644
index 0000000..3e0bab8
--- /dev/null
+++ b/vendor/go.opencensus.io/go.sum
@@ -0,0 +1,48 @@
+git.apache.org/thrift.git v0.0.0-20180807212849-6e67faa92827/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
+git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999 h1:sihTnRgTOUSCQz0iS0pjZuFQy/z7GXCJgSBg3+rZKHw=
+git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/grpc-ecosystem/grpc-gateway v1.5.0 h1:WcmKMm43DR7RdtlkEXQJyo5ws8iTp98CyhCCbOHMvNI=
+github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
+github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/openzipkin/zipkin-go v0.1.1 h1:A/ADD6HaPnAKj3yS7HjGHRK77qi41Hi0DirOOIQAeIw=
+github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
+github.com/prometheus/client_golang v0.8.0 h1:1921Yw9Gc3iSc4VQh3PIoOqgPCZS7G/4xQNVUp8Mda8=
+github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e h1:n/3MEhJQjQxrOUCzh1Y3Re6aJUUWRp2M9+Oc3eVn/54=
+github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273 h1:agujYaXJSxSo18YNX3jzl+4G6Bstwt+kqv47GS12uL0=
+github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+golang.org/x/net v0.0.0-20180821023952-922f4815f713/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180821140842-3b58ed4ad339/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+google.golang.org/api v0.0.0-20180818000503-e21acd801f91/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
+google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf h1:rjxqQmxjyqerRKEj+tZW+MCm4LgpFXu18bsEoCMgDsk=
+google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw=
+google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/grpc v1.14.0 h1:ArxJuB1NWfPY6r9Gp9gqwplT0Ge7nqv9msgu03lHLmo=
+google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/vendor/go.opencensus.io/internal/internal.go b/vendor/go.opencensus.io/internal/internal.go
new file mode 100644
index 0000000..e1d1238
--- /dev/null
+++ b/vendor/go.opencensus.io/internal/internal.go
@@ -0,0 +1,37 @@
+// 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 internal // import "go.opencensus.io/internal"
+
+import (
+	"fmt"
+	"time"
+
+	"go.opencensus.io"
+)
+
+// UserAgent is the user agent to be added to the outgoing
+// requests from the exporters.
+var UserAgent = fmt.Sprintf("opencensus-go [%s]", opencensus.Version())
+
+// MonotonicEndTime returns the end time at present
+// but offset from start, monotonically.
+//
+// The monotonic clock is used in subtractions hence
+// the duration since start added back to start gives
+// end as a monotonic time.
+// See https://golang.org/pkg/time/#hdr-Monotonic_Clocks
+func MonotonicEndTime(start time.Time) time.Time {
+	return start.Add(time.Now().Sub(start))
+}
diff --git a/vendor/go.opencensus.io/internal/sanitize.go b/vendor/go.opencensus.io/internal/sanitize.go
new file mode 100644
index 0000000..de8ccf2
--- /dev/null
+++ b/vendor/go.opencensus.io/internal/sanitize.go
@@ -0,0 +1,50 @@
+// 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 internal
+
+import (
+	"strings"
+	"unicode"
+)
+
+const labelKeySizeLimit = 100
+
+// Sanitize returns a string that is trunacated to 100 characters if it's too
+// long, and replaces non-alphanumeric characters to underscores.
+func Sanitize(s string) string {
+	if len(s) == 0 {
+		return s
+	}
+	if len(s) > labelKeySizeLimit {
+		s = s[:labelKeySizeLimit]
+	}
+	s = strings.Map(sanitizeRune, s)
+	if unicode.IsDigit(rune(s[0])) {
+		s = "key_" + s
+	}
+	if s[0] == '_' {
+		s = "key" + s
+	}
+	return s
+}
+
+// converts anything that is not a letter or digit to an underscore
+func sanitizeRune(r rune) rune {
+	if unicode.IsLetter(r) || unicode.IsDigit(r) {
+		return r
+	}
+	// Everything else turns into an underscore
+	return '_'
+}
diff --git a/vendor/go.opencensus.io/internal/tagencoding/tagencoding.go b/vendor/go.opencensus.io/internal/tagencoding/tagencoding.go
new file mode 100644
index 0000000..3b1af8b
--- /dev/null
+++ b/vendor/go.opencensus.io/internal/tagencoding/tagencoding.go
@@ -0,0 +1,72 @@
+// 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 tagencoding contains the tag encoding
+// used interally by the stats collector.
+package tagencoding // import "go.opencensus.io/internal/tagencoding"
+
+type Values struct {
+	Buffer     []byte
+	WriteIndex int
+	ReadIndex  int
+}
+
+func (vb *Values) growIfRequired(expected int) {
+	if len(vb.Buffer)-vb.WriteIndex < expected {
+		tmp := make([]byte, 2*(len(vb.Buffer)+1)+expected)
+		copy(tmp, vb.Buffer)
+		vb.Buffer = tmp
+	}
+}
+
+func (vb *Values) WriteValue(v []byte) {
+	length := len(v) & 0xff
+	vb.growIfRequired(1 + length)
+
+	// writing length of v
+	vb.Buffer[vb.WriteIndex] = byte(length)
+	vb.WriteIndex++
+
+	if length == 0 {
+		// No value was encoded for this key
+		return
+	}
+
+	// writing v
+	copy(vb.Buffer[vb.WriteIndex:], v[:length])
+	vb.WriteIndex += length
+}
+
+// ReadValue is the helper method to read the values when decoding valuesBytes to a map[Key][]byte.
+func (vb *Values) ReadValue() []byte {
+	// read length of v
+	length := int(vb.Buffer[vb.ReadIndex])
+	vb.ReadIndex++
+	if length == 0 {
+		// No value was encoded for this key
+		return nil
+	}
+
+	// read value of v
+	v := make([]byte, length)
+	endIdx := vb.ReadIndex + length
+	copy(v, vb.Buffer[vb.ReadIndex:endIdx])
+	vb.ReadIndex = endIdx
+	return v
+}
+
+func (vb *Values) Bytes() []byte {
+	return vb.Buffer[:vb.WriteIndex]
+}
diff --git a/vendor/go.opencensus.io/internal/traceinternals.go b/vendor/go.opencensus.io/internal/traceinternals.go
new file mode 100644
index 0000000..553ca68
--- /dev/null
+++ b/vendor/go.opencensus.io/internal/traceinternals.go
@@ -0,0 +1,52 @@
+// 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 internal
+
+import (
+	"time"
+)
+
+// Trace allows internal access to some trace functionality.
+// TODO(#412): remove this
+var Trace interface{}
+
+var LocalSpanStoreEnabled bool
+
+// BucketConfiguration stores the number of samples to store for span buckets
+// for successful and failed spans for a particular span name.
+type BucketConfiguration struct {
+	Name                 string
+	MaxRequestsSucceeded int
+	MaxRequestsErrors    int
+}
+
+// PerMethodSummary is a summary of the spans stored for a single span name.
+type PerMethodSummary struct {
+	Active         int
+	LatencyBuckets []LatencyBucketSummary
+	ErrorBuckets   []ErrorBucketSummary
+}
+
+// LatencyBucketSummary is a summary of a latency bucket.
+type LatencyBucketSummary struct {
+	MinLatency, MaxLatency time.Duration
+	Size                   int
+}
+
+// ErrorBucketSummary is a summary of an error bucket.
+type ErrorBucketSummary struct {
+	ErrorCode int32
+	Size      int
+}
diff --git a/vendor/go.opencensus.io/opencensus.go b/vendor/go.opencensus.io/opencensus.go
new file mode 100644
index 0000000..7faf9e8
--- /dev/null
+++ b/vendor/go.opencensus.io/opencensus.go
@@ -0,0 +1,21 @@
+// 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 opencensus contains Go support for OpenCensus.
+package opencensus // import "go.opencensus.io"
+
+// Version is the current release version of OpenCensus in use.
+func Version() string {
+	return "0.19.0"
+}
diff --git a/vendor/go.opencensus.io/plugin/ochttp/client.go b/vendor/go.opencensus.io/plugin/ochttp/client.go
new file mode 100644
index 0000000..da815b2
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/client.go
@@ -0,0 +1,117 @@
+// Copyright 2018, 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 ochttp
+
+import (
+	"net/http"
+	"net/http/httptrace"
+
+	"go.opencensus.io/trace"
+	"go.opencensus.io/trace/propagation"
+)
+
+// Transport is an http.RoundTripper that instruments all outgoing requests with
+// OpenCensus stats and tracing.
+//
+// The zero value is intended to be a useful default, but for
+// now it's recommended that you explicitly set Propagation, since the default
+// for this may change.
+type Transport struct {
+	// Base may be set to wrap another http.RoundTripper that does the actual
+	// requests. By default http.DefaultTransport is used.
+	//
+	// If base HTTP roundtripper implements CancelRequest,
+	// the returned round tripper will be cancelable.
+	Base http.RoundTripper
+
+	// Propagation defines how traces are propagated. If unspecified, a default
+	// (currently B3 format) will be used.
+	Propagation propagation.HTTPFormat
+
+	// StartOptions are applied to the span started by this Transport around each
+	// request.
+	//
+	// StartOptions.SpanKind will always be set to trace.SpanKindClient
+	// for spans started by this transport.
+	StartOptions trace.StartOptions
+
+	// GetStartOptions allows to set start options per request. If set,
+	// StartOptions is going to be ignored.
+	GetStartOptions func(*http.Request) trace.StartOptions
+
+	// NameFromRequest holds the function to use for generating the span name
+	// from the information found in the outgoing HTTP Request. By default the
+	// name equals the URL Path.
+	FormatSpanName func(*http.Request) string
+
+	// NewClientTrace may be set to a function allowing the current *trace.Span
+	// to be annotated with HTTP request event information emitted by the
+	// httptrace package.
+	NewClientTrace func(*http.Request, *trace.Span) *httptrace.ClientTrace
+
+	// TODO: Implement tag propagation for HTTP.
+}
+
+// RoundTrip implements http.RoundTripper, delegating to Base and recording stats and traces for the request.
+func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
+	rt := t.base()
+	if isHealthEndpoint(req.URL.Path) {
+		return rt.RoundTrip(req)
+	}
+	// TODO: remove excessive nesting of http.RoundTrippers here.
+	format := t.Propagation
+	if format == nil {
+		format = defaultFormat
+	}
+	spanNameFormatter := t.FormatSpanName
+	if spanNameFormatter == nil {
+		spanNameFormatter = spanNameFromURL
+	}
+
+	startOpts := t.StartOptions
+	if t.GetStartOptions != nil {
+		startOpts = t.GetStartOptions(req)
+	}
+
+	rt = &traceTransport{
+		base:   rt,
+		format: format,
+		startOptions: trace.StartOptions{
+			Sampler:  startOpts.Sampler,
+			SpanKind: trace.SpanKindClient,
+		},
+		formatSpanName: spanNameFormatter,
+		newClientTrace: t.NewClientTrace,
+	}
+	rt = statsTransport{base: rt}
+	return rt.RoundTrip(req)
+}
+
+func (t *Transport) base() http.RoundTripper {
+	if t.Base != nil {
+		return t.Base
+	}
+	return http.DefaultTransport
+}
+
+// CancelRequest cancels an in-flight request by closing its connection.
+func (t *Transport) CancelRequest(req *http.Request) {
+	type canceler interface {
+		CancelRequest(*http.Request)
+	}
+	if cr, ok := t.base().(canceler); ok {
+		cr.CancelRequest(req)
+	}
+}
diff --git a/vendor/go.opencensus.io/plugin/ochttp/client_stats.go b/vendor/go.opencensus.io/plugin/ochttp/client_stats.go
new file mode 100644
index 0000000..066ebb8
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/client_stats.go
@@ -0,0 +1,135 @@
+// Copyright 2018, 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 ochttp
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"sync"
+	"time"
+
+	"go.opencensus.io/stats"
+	"go.opencensus.io/tag"
+)
+
+// statsTransport is an http.RoundTripper that collects stats for the outgoing requests.
+type statsTransport struct {
+	base http.RoundTripper
+}
+
+// RoundTrip implements http.RoundTripper, delegating to Base and recording stats for the request.
+func (t statsTransport) RoundTrip(req *http.Request) (*http.Response, error) {
+	ctx, _ := tag.New(req.Context(),
+		tag.Upsert(KeyClientHost, req.URL.Host),
+		tag.Upsert(Host, req.URL.Host),
+		tag.Upsert(KeyClientPath, req.URL.Path),
+		tag.Upsert(Path, req.URL.Path),
+		tag.Upsert(KeyClientMethod, req.Method),
+		tag.Upsert(Method, req.Method))
+	req = req.WithContext(ctx)
+	track := &tracker{
+		start: time.Now(),
+		ctx:   ctx,
+	}
+	if req.Body == nil {
+		// TODO: Handle cases where ContentLength is not set.
+		track.reqSize = -1
+	} else if req.ContentLength > 0 {
+		track.reqSize = req.ContentLength
+	}
+	stats.Record(ctx, ClientRequestCount.M(1))
+
+	// Perform request.
+	resp, err := t.base.RoundTrip(req)
+
+	if err != nil {
+		track.statusCode = http.StatusInternalServerError
+		track.end()
+	} else {
+		track.statusCode = resp.StatusCode
+		if resp.Body == nil {
+			track.end()
+		} else {
+			track.body = resp.Body
+			resp.Body = track
+		}
+	}
+	return resp, err
+}
+
+// CancelRequest cancels an in-flight request by closing its connection.
+func (t statsTransport) CancelRequest(req *http.Request) {
+	type canceler interface {
+		CancelRequest(*http.Request)
+	}
+	if cr, ok := t.base.(canceler); ok {
+		cr.CancelRequest(req)
+	}
+}
+
+type tracker struct {
+	ctx        context.Context
+	respSize   int64
+	reqSize    int64
+	start      time.Time
+	body       io.ReadCloser
+	statusCode int
+	endOnce    sync.Once
+}
+
+var _ io.ReadCloser = (*tracker)(nil)
+
+func (t *tracker) end() {
+	t.endOnce.Do(func() {
+		latencyMs := float64(time.Since(t.start)) / float64(time.Millisecond)
+		m := []stats.Measurement{
+			ClientSentBytes.M(t.reqSize),
+			ClientReceivedBytes.M(t.respSize),
+			ClientRoundtripLatency.M(latencyMs),
+			ClientLatency.M(latencyMs),
+			ClientResponseBytes.M(t.respSize),
+		}
+		if t.reqSize >= 0 {
+			m = append(m, ClientRequestBytes.M(t.reqSize))
+		}
+
+		stats.RecordWithTags(t.ctx, []tag.Mutator{
+			tag.Upsert(StatusCode, strconv.Itoa(t.statusCode)),
+			tag.Upsert(KeyClientStatus, strconv.Itoa(t.statusCode)),
+		}, m...)
+	})
+}
+
+func (t *tracker) Read(b []byte) (int, error) {
+	n, err := t.body.Read(b)
+	switch err {
+	case nil:
+		t.respSize += int64(n)
+		return n, nil
+	case io.EOF:
+		t.end()
+	}
+	return n, err
+}
+
+func (t *tracker) Close() error {
+	// Invoking endSpan on Close will help catch the cases
+	// in which a read returned a non-nil error, we set the
+	// span status but didn't end the span.
+	t.end()
+	return t.body.Close()
+}
diff --git a/vendor/go.opencensus.io/plugin/ochttp/doc.go b/vendor/go.opencensus.io/plugin/ochttp/doc.go
new file mode 100644
index 0000000..10e626b
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/doc.go
@@ -0,0 +1,19 @@
+// Copyright 2018, 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 ochttp provides OpenCensus instrumentation for net/http package.
+//
+// For server instrumentation, see Handler. For client-side instrumentation,
+// see Transport.
+package ochttp // import "go.opencensus.io/plugin/ochttp"
diff --git a/vendor/go.opencensus.io/plugin/ochttp/propagation/b3/b3.go b/vendor/go.opencensus.io/plugin/ochttp/propagation/b3/b3.go
new file mode 100644
index 0000000..f777772
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/propagation/b3/b3.go
@@ -0,0 +1,123 @@
+// Copyright 2018, 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 b3 contains a propagation.HTTPFormat implementation
+// for B3 propagation. See https://github.com/openzipkin/b3-propagation
+// for more details.
+package b3 // import "go.opencensus.io/plugin/ochttp/propagation/b3"
+
+import (
+	"encoding/hex"
+	"net/http"
+
+	"go.opencensus.io/trace"
+	"go.opencensus.io/trace/propagation"
+)
+
+// B3 headers that OpenCensus understands.
+const (
+	TraceIDHeader = "X-B3-TraceId"
+	SpanIDHeader  = "X-B3-SpanId"
+	SampledHeader = "X-B3-Sampled"
+)
+
+// HTTPFormat implements propagation.HTTPFormat to propagate
+// traces in HTTP headers in B3 propagation format.
+// HTTPFormat skips the X-B3-ParentId and X-B3-Flags headers
+// because there are additional fields not represented in the
+// OpenCensus span context. Spans created from the incoming
+// header will be the direct children of the client-side span.
+// Similarly, reciever of the outgoing spans should use client-side
+// span created by OpenCensus as the parent.
+type HTTPFormat struct{}
+
+var _ propagation.HTTPFormat = (*HTTPFormat)(nil)
+
+// SpanContextFromRequest extracts a B3 span context from incoming requests.
+func (f *HTTPFormat) SpanContextFromRequest(req *http.Request) (sc trace.SpanContext, ok bool) {
+	tid, ok := ParseTraceID(req.Header.Get(TraceIDHeader))
+	if !ok {
+		return trace.SpanContext{}, false
+	}
+	sid, ok := ParseSpanID(req.Header.Get(SpanIDHeader))
+	if !ok {
+		return trace.SpanContext{}, false
+	}
+	sampled, _ := ParseSampled(req.Header.Get(SampledHeader))
+	return trace.SpanContext{
+		TraceID:      tid,
+		SpanID:       sid,
+		TraceOptions: sampled,
+	}, true
+}
+
+// ParseTraceID parses the value of the X-B3-TraceId header.
+func ParseTraceID(tid string) (trace.TraceID, bool) {
+	if tid == "" {
+		return trace.TraceID{}, false
+	}
+	b, err := hex.DecodeString(tid)
+	if err != nil {
+		return trace.TraceID{}, false
+	}
+	var traceID trace.TraceID
+	if len(b) <= 8 {
+		// The lower 64-bits.
+		start := 8 + (8 - len(b))
+		copy(traceID[start:], b)
+	} else {
+		start := 16 - len(b)
+		copy(traceID[start:], b)
+	}
+
+	return traceID, true
+}
+
+// ParseSpanID parses the value of the X-B3-SpanId or X-B3-ParentSpanId headers.
+func ParseSpanID(sid string) (spanID trace.SpanID, ok bool) {
+	if sid == "" {
+		return trace.SpanID{}, false
+	}
+	b, err := hex.DecodeString(sid)
+	if err != nil {
+		return trace.SpanID{}, false
+	}
+	start := 8 - len(b)
+	copy(spanID[start:], b)
+	return spanID, true
+}
+
+// ParseSampled parses the value of the X-B3-Sampled header.
+func ParseSampled(sampled string) (trace.TraceOptions, bool) {
+	switch sampled {
+	case "true", "1":
+		return trace.TraceOptions(1), true
+	default:
+		return trace.TraceOptions(0), false
+	}
+}
+
+// SpanContextToRequest modifies the given request to include B3 headers.
+func (f *HTTPFormat) SpanContextToRequest(sc trace.SpanContext, req *http.Request) {
+	req.Header.Set(TraceIDHeader, hex.EncodeToString(sc.TraceID[:]))
+	req.Header.Set(SpanIDHeader, hex.EncodeToString(sc.SpanID[:]))
+
+	var sampled string
+	if sc.IsSampled() {
+		sampled = "1"
+	} else {
+		sampled = "0"
+	}
+	req.Header.Set(SampledHeader, sampled)
+}
diff --git a/vendor/go.opencensus.io/plugin/ochttp/route.go b/vendor/go.opencensus.io/plugin/ochttp/route.go
new file mode 100644
index 0000000..dbe22d5
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/route.go
@@ -0,0 +1,51 @@
+// Copyright 2018, 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 ochttp
+
+import (
+	"net/http"
+
+	"go.opencensus.io/tag"
+)
+
+// WithRouteTag returns an http.Handler that records stats with the
+// http_server_route tag set to the given value.
+func WithRouteTag(handler http.Handler, route string) http.Handler {
+	return taggedHandlerFunc(func(w http.ResponseWriter, r *http.Request) []tag.Mutator {
+		addRoute := []tag.Mutator{tag.Upsert(KeyServerRoute, route)}
+		ctx, _ := tag.New(r.Context(), addRoute...)
+		r = r.WithContext(ctx)
+		handler.ServeHTTP(w, r)
+		return addRoute
+	})
+}
+
+// taggedHandlerFunc is a http.Handler that returns tags describing the
+// processing of the request. These tags will be recorded along with the
+// measures in this package at the end of the request.
+type taggedHandlerFunc func(w http.ResponseWriter, r *http.Request) []tag.Mutator
+
+func (h taggedHandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	tags := h(w, r)
+	if a, ok := r.Context().Value(addedTagsKey{}).(*addedTags); ok {
+		a.t = append(a.t, tags...)
+	}
+}
+
+type addedTagsKey struct{}
+
+type addedTags struct {
+	t []tag.Mutator
+}
diff --git a/vendor/go.opencensus.io/plugin/ochttp/server.go b/vendor/go.opencensus.io/plugin/ochttp/server.go
new file mode 100644
index 0000000..ff72de9
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/server.go
@@ -0,0 +1,440 @@
+// Copyright 2018, 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 ochttp
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"sync"
+	"time"
+
+	"go.opencensus.io/stats"
+	"go.opencensus.io/tag"
+	"go.opencensus.io/trace"
+	"go.opencensus.io/trace/propagation"
+)
+
+// Handler is an http.Handler wrapper to instrument your HTTP server with
+// OpenCensus. It supports both stats and tracing.
+//
+// Tracing
+//
+// This handler is aware of the incoming request's span, reading it from request
+// headers as configured using the Propagation field.
+// The extracted span can be accessed from the incoming request's
+// context.
+//
+//    span := trace.FromContext(r.Context())
+//
+// The server span will be automatically ended at the end of ServeHTTP.
+type Handler struct {
+	// Propagation defines how traces are propagated. If unspecified,
+	// B3 propagation will be used.
+	Propagation propagation.HTTPFormat
+
+	// Handler is the handler used to handle the incoming request.
+	Handler http.Handler
+
+	// StartOptions are applied to the span started by this Handler around each
+	// request.
+	//
+	// StartOptions.SpanKind will always be set to trace.SpanKindServer
+	// for spans started by this transport.
+	StartOptions trace.StartOptions
+
+	// GetStartOptions allows to set start options per request. If set,
+	// StartOptions is going to be ignored.
+	GetStartOptions func(*http.Request) trace.StartOptions
+
+	// IsPublicEndpoint should be set to true for publicly accessible HTTP(S)
+	// servers. If true, any trace metadata set on the incoming request will
+	// be added as a linked trace instead of being added as a parent of the
+	// current trace.
+	IsPublicEndpoint bool
+
+	// FormatSpanName holds the function to use for generating the span name
+	// from the information found in the incoming HTTP Request. By default the
+	// name equals the URL Path.
+	FormatSpanName func(*http.Request) string
+}
+
+func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	var tags addedTags
+	r, traceEnd := h.startTrace(w, r)
+	defer traceEnd()
+	w, statsEnd := h.startStats(w, r)
+	defer statsEnd(&tags)
+	handler := h.Handler
+	if handler == nil {
+		handler = http.DefaultServeMux
+	}
+	r = r.WithContext(context.WithValue(r.Context(), addedTagsKey{}, &tags))
+	handler.ServeHTTP(w, r)
+}
+
+func (h *Handler) startTrace(w http.ResponseWriter, r *http.Request) (*http.Request, func()) {
+	if isHealthEndpoint(r.URL.Path) {
+		return r, func() {}
+	}
+	var name string
+	if h.FormatSpanName == nil {
+		name = spanNameFromURL(r)
+	} else {
+		name = h.FormatSpanName(r)
+	}
+	ctx := r.Context()
+
+	startOpts := h.StartOptions
+	if h.GetStartOptions != nil {
+		startOpts = h.GetStartOptions(r)
+	}
+
+	var span *trace.Span
+	sc, ok := h.extractSpanContext(r)
+	if ok && !h.IsPublicEndpoint {
+		ctx, span = trace.StartSpanWithRemoteParent(ctx, name, sc,
+			trace.WithSampler(startOpts.Sampler),
+			trace.WithSpanKind(trace.SpanKindServer))
+	} else {
+		ctx, span = trace.StartSpan(ctx, name,
+			trace.WithSampler(startOpts.Sampler),
+			trace.WithSpanKind(trace.SpanKindServer),
+		)
+		if ok {
+			span.AddLink(trace.Link{
+				TraceID:    sc.TraceID,
+				SpanID:     sc.SpanID,
+				Type:       trace.LinkTypeChild,
+				Attributes: nil,
+			})
+		}
+	}
+	span.AddAttributes(requestAttrs(r)...)
+	return r.WithContext(ctx), span.End
+}
+
+func (h *Handler) extractSpanContext(r *http.Request) (trace.SpanContext, bool) {
+	if h.Propagation == nil {
+		return defaultFormat.SpanContextFromRequest(r)
+	}
+	return h.Propagation.SpanContextFromRequest(r)
+}
+
+func (h *Handler) startStats(w http.ResponseWriter, r *http.Request) (http.ResponseWriter, func(tags *addedTags)) {
+	ctx, _ := tag.New(r.Context(),
+		tag.Upsert(Host, r.URL.Host),
+		tag.Upsert(Path, r.URL.Path),
+		tag.Upsert(Method, r.Method))
+	track := &trackingResponseWriter{
+		start:  time.Now(),
+		ctx:    ctx,
+		writer: w,
+	}
+	if r.Body == nil {
+		// TODO: Handle cases where ContentLength is not set.
+		track.reqSize = -1
+	} else if r.ContentLength > 0 {
+		track.reqSize = r.ContentLength
+	}
+	stats.Record(ctx, ServerRequestCount.M(1))
+	return track.wrappedResponseWriter(), track.end
+}
+
+type trackingResponseWriter struct {
+	ctx        context.Context
+	reqSize    int64
+	respSize   int64
+	start      time.Time
+	statusCode int
+	statusLine string
+	endOnce    sync.Once
+	writer     http.ResponseWriter
+}
+
+// Compile time assertion for ResponseWriter interface
+var _ http.ResponseWriter = (*trackingResponseWriter)(nil)
+
+var logTagsErrorOnce sync.Once
+
+func (t *trackingResponseWriter) end(tags *addedTags) {
+	t.endOnce.Do(func() {
+		if t.statusCode == 0 {
+			t.statusCode = 200
+		}
+
+		span := trace.FromContext(t.ctx)
+		span.SetStatus(TraceStatus(t.statusCode, t.statusLine))
+		span.AddAttributes(trace.Int64Attribute(StatusCodeAttribute, int64(t.statusCode)))
+
+		m := []stats.Measurement{
+			ServerLatency.M(float64(time.Since(t.start)) / float64(time.Millisecond)),
+			ServerResponseBytes.M(t.respSize),
+		}
+		if t.reqSize >= 0 {
+			m = append(m, ServerRequestBytes.M(t.reqSize))
+		}
+		allTags := make([]tag.Mutator, len(tags.t)+1)
+		allTags[0] = tag.Upsert(StatusCode, strconv.Itoa(t.statusCode))
+		copy(allTags[1:], tags.t)
+		stats.RecordWithTags(t.ctx, allTags, m...)
+	})
+}
+
+func (t *trackingResponseWriter) Header() http.Header {
+	return t.writer.Header()
+}
+
+func (t *trackingResponseWriter) Write(data []byte) (int, error) {
+	n, err := t.writer.Write(data)
+	t.respSize += int64(n)
+	return n, err
+}
+
+func (t *trackingResponseWriter) WriteHeader(statusCode int) {
+	t.writer.WriteHeader(statusCode)
+	t.statusCode = statusCode
+	t.statusLine = http.StatusText(t.statusCode)
+}
+
+// wrappedResponseWriter returns a wrapped version of the original
+//  ResponseWriter and only implements the same combination of additional
+// interfaces as the original.
+// This implementation is based on https://github.com/felixge/httpsnoop.
+func (t *trackingResponseWriter) wrappedResponseWriter() http.ResponseWriter {
+	var (
+		hj, i0 = t.writer.(http.Hijacker)
+		cn, i1 = t.writer.(http.CloseNotifier)
+		pu, i2 = t.writer.(http.Pusher)
+		fl, i3 = t.writer.(http.Flusher)
+		rf, i4 = t.writer.(io.ReaderFrom)
+	)
+
+	switch {
+	case !i0 && !i1 && !i2 && !i3 && !i4:
+		return struct {
+			http.ResponseWriter
+		}{t}
+	case !i0 && !i1 && !i2 && !i3 && i4:
+		return struct {
+			http.ResponseWriter
+			io.ReaderFrom
+		}{t, rf}
+	case !i0 && !i1 && !i2 && i3 && !i4:
+		return struct {
+			http.ResponseWriter
+			http.Flusher
+		}{t, fl}
+	case !i0 && !i1 && !i2 && i3 && i4:
+		return struct {
+			http.ResponseWriter
+			http.Flusher
+			io.ReaderFrom
+		}{t, fl, rf}
+	case !i0 && !i1 && i2 && !i3 && !i4:
+		return struct {
+			http.ResponseWriter
+			http.Pusher
+		}{t, pu}
+	case !i0 && !i1 && i2 && !i3 && i4:
+		return struct {
+			http.ResponseWriter
+			http.Pusher
+			io.ReaderFrom
+		}{t, pu, rf}
+	case !i0 && !i1 && i2 && i3 && !i4:
+		return struct {
+			http.ResponseWriter
+			http.Pusher
+			http.Flusher
+		}{t, pu, fl}
+	case !i0 && !i1 && i2 && i3 && i4:
+		return struct {
+			http.ResponseWriter
+			http.Pusher
+			http.Flusher
+			io.ReaderFrom
+		}{t, pu, fl, rf}
+	case !i0 && i1 && !i2 && !i3 && !i4:
+		return struct {
+			http.ResponseWriter
+			http.CloseNotifier
+		}{t, cn}
+	case !i0 && i1 && !i2 && !i3 && i4:
+		return struct {
+			http.ResponseWriter
+			http.CloseNotifier
+			io.ReaderFrom
+		}{t, cn, rf}
+	case !i0 && i1 && !i2 && i3 && !i4:
+		return struct {
+			http.ResponseWriter
+			http.CloseNotifier
+			http.Flusher
+		}{t, cn, fl}
+	case !i0 && i1 && !i2 && i3 && i4:
+		return struct {
+			http.ResponseWriter
+			http.CloseNotifier
+			http.Flusher
+			io.ReaderFrom
+		}{t, cn, fl, rf}
+	case !i0 && i1 && i2 && !i3 && !i4:
+		return struct {
+			http.ResponseWriter
+			http.CloseNotifier
+			http.Pusher
+		}{t, cn, pu}
+	case !i0 && i1 && i2 && !i3 && i4:
+		return struct {
+			http.ResponseWriter
+			http.CloseNotifier
+			http.Pusher
+			io.ReaderFrom
+		}{t, cn, pu, rf}
+	case !i0 && i1 && i2 && i3 && !i4:
+		return struct {
+			http.ResponseWriter
+			http.CloseNotifier
+			http.Pusher
+			http.Flusher
+		}{t, cn, pu, fl}
+	case !i0 && i1 && i2 && i3 && i4:
+		return struct {
+			http.ResponseWriter
+			http.CloseNotifier
+			http.Pusher
+			http.Flusher
+			io.ReaderFrom
+		}{t, cn, pu, fl, rf}
+	case i0 && !i1 && !i2 && !i3 && !i4:
+		return struct {
+			http.ResponseWriter
+			http.Hijacker
+		}{t, hj}
+	case i0 && !i1 && !i2 && !i3 && i4:
+		return struct {
+			http.ResponseWriter
+			http.Hijacker
+			io.ReaderFrom
+		}{t, hj, rf}
+	case i0 && !i1 && !i2 && i3 && !i4:
+		return struct {
+			http.ResponseWriter
+			http.Hijacker
+			http.Flusher
+		}{t, hj, fl}
+	case i0 && !i1 && !i2 && i3 && i4:
+		return struct {
+			http.ResponseWriter
+			http.Hijacker
+			http.Flusher
+			io.ReaderFrom
+		}{t, hj, fl, rf}
+	case i0 && !i1 && i2 && !i3 && !i4:
+		return struct {
+			http.ResponseWriter
+			http.Hijacker
+			http.Pusher
+		}{t, hj, pu}
+	case i0 && !i1 && i2 && !i3 && i4:
+		return struct {
+			http.ResponseWriter
+			http.Hijacker
+			http.Pusher
+			io.ReaderFrom
+		}{t, hj, pu, rf}
+	case i0 && !i1 && i2 && i3 && !i4:
+		return struct {
+			http.ResponseWriter
+			http.Hijacker
+			http.Pusher
+			http.Flusher
+		}{t, hj, pu, fl}
+	case i0 && !i1 && i2 && i3 && i4:
+		return struct {
+			http.ResponseWriter
+			http.Hijacker
+			http.Pusher
+			http.Flusher
+			io.ReaderFrom
+		}{t, hj, pu, fl, rf}
+	case i0 && i1 && !i2 && !i3 && !i4:
+		return struct {
+			http.ResponseWriter
+			http.Hijacker
+			http.CloseNotifier
+		}{t, hj, cn}
+	case i0 && i1 && !i2 && !i3 && i4:
+		return struct {
+			http.ResponseWriter
+			http.Hijacker
+			http.CloseNotifier
+			io.ReaderFrom
+		}{t, hj, cn, rf}
+	case i0 && i1 && !i2 && i3 && !i4:
+		return struct {
+			http.ResponseWriter
+			http.Hijacker
+			http.CloseNotifier
+			http.Flusher
+		}{t, hj, cn, fl}
+	case i0 && i1 && !i2 && i3 && i4:
+		return struct {
+			http.ResponseWriter
+			http.Hijacker
+			http.CloseNotifier
+			http.Flusher
+			io.ReaderFrom
+		}{t, hj, cn, fl, rf}
+	case i0 && i1 && i2 && !i3 && !i4:
+		return struct {
+			http.ResponseWriter
+			http.Hijacker
+			http.CloseNotifier
+			http.Pusher
+		}{t, hj, cn, pu}
+	case i0 && i1 && i2 && !i3 && i4:
+		return struct {
+			http.ResponseWriter
+			http.Hijacker
+			http.CloseNotifier
+			http.Pusher
+			io.ReaderFrom
+		}{t, hj, cn, pu, rf}
+	case i0 && i1 && i2 && i3 && !i4:
+		return struct {
+			http.ResponseWriter
+			http.Hijacker
+			http.CloseNotifier
+			http.Pusher
+			http.Flusher
+		}{t, hj, cn, pu, fl}
+	case i0 && i1 && i2 && i3 && i4:
+		return struct {
+			http.ResponseWriter
+			http.Hijacker
+			http.CloseNotifier
+			http.Pusher
+			http.Flusher
+			io.ReaderFrom
+		}{t, hj, cn, pu, fl, rf}
+	default:
+		return struct {
+			http.ResponseWriter
+		}{t}
+	}
+}
diff --git a/vendor/go.opencensus.io/plugin/ochttp/span_annotating_client_trace.go b/vendor/go.opencensus.io/plugin/ochttp/span_annotating_client_trace.go
new file mode 100644
index 0000000..05c6c56
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/span_annotating_client_trace.go
@@ -0,0 +1,169 @@
+// Copyright 2018, 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 ochttp
+
+import (
+	"crypto/tls"
+	"net/http"
+	"net/http/httptrace"
+	"strings"
+
+	"go.opencensus.io/trace"
+)
+
+type spanAnnotator struct {
+	sp *trace.Span
+}
+
+// TODO: Remove NewSpanAnnotator at the next release.
+
+// NewSpanAnnotator returns a httptrace.ClientTrace which annotates
+// all emitted httptrace events on the provided Span.
+// Deprecated: Use NewSpanAnnotatingClientTrace instead
+func NewSpanAnnotator(r *http.Request, s *trace.Span) *httptrace.ClientTrace {
+	return NewSpanAnnotatingClientTrace(r, s)
+}
+
+// NewSpanAnnotatingClientTrace returns a httptrace.ClientTrace which annotates
+// all emitted httptrace events on the provided Span.
+func NewSpanAnnotatingClientTrace(_ *http.Request, s *trace.Span) *httptrace.ClientTrace {
+	sa := spanAnnotator{sp: s}
+
+	return &httptrace.ClientTrace{
+		GetConn:              sa.getConn,
+		GotConn:              sa.gotConn,
+		PutIdleConn:          sa.putIdleConn,
+		GotFirstResponseByte: sa.gotFirstResponseByte,
+		Got100Continue:       sa.got100Continue,
+		DNSStart:             sa.dnsStart,
+		DNSDone:              sa.dnsDone,
+		ConnectStart:         sa.connectStart,
+		ConnectDone:          sa.connectDone,
+		TLSHandshakeStart:    sa.tlsHandshakeStart,
+		TLSHandshakeDone:     sa.tlsHandshakeDone,
+		WroteHeaders:         sa.wroteHeaders,
+		Wait100Continue:      sa.wait100Continue,
+		WroteRequest:         sa.wroteRequest,
+	}
+}
+
+func (s spanAnnotator) getConn(hostPort string) {
+	attrs := []trace.Attribute{
+		trace.StringAttribute("httptrace.get_connection.host_port", hostPort),
+	}
+	s.sp.Annotate(attrs, "GetConn")
+}
+
+func (s spanAnnotator) gotConn(info httptrace.GotConnInfo) {
+	attrs := []trace.Attribute{
+		trace.BoolAttribute("httptrace.got_connection.reused", info.Reused),
+		trace.BoolAttribute("httptrace.got_connection.was_idle", info.WasIdle),
+	}
+	if info.WasIdle {
+		attrs = append(attrs,
+			trace.StringAttribute("httptrace.got_connection.idle_time", info.IdleTime.String()))
+	}
+	s.sp.Annotate(attrs, "GotConn")
+}
+
+// PutIdleConn implements a httptrace.ClientTrace hook
+func (s spanAnnotator) putIdleConn(err error) {
+	var attrs []trace.Attribute
+	if err != nil {
+		attrs = append(attrs,
+			trace.StringAttribute("httptrace.put_idle_connection.error", err.Error()))
+	}
+	s.sp.Annotate(attrs, "PutIdleConn")
+}
+
+func (s spanAnnotator) gotFirstResponseByte() {
+	s.sp.Annotate(nil, "GotFirstResponseByte")
+}
+
+func (s spanAnnotator) got100Continue() {
+	s.sp.Annotate(nil, "Got100Continue")
+}
+
+func (s spanAnnotator) dnsStart(info httptrace.DNSStartInfo) {
+	attrs := []trace.Attribute{
+		trace.StringAttribute("httptrace.dns_start.host", info.Host),
+	}
+	s.sp.Annotate(attrs, "DNSStart")
+}
+
+func (s spanAnnotator) dnsDone(info httptrace.DNSDoneInfo) {
+	var addrs []string
+	for _, addr := range info.Addrs {
+		addrs = append(addrs, addr.String())
+	}
+	attrs := []trace.Attribute{
+		trace.StringAttribute("httptrace.dns_done.addrs", strings.Join(addrs, " , ")),
+	}
+	if info.Err != nil {
+		attrs = append(attrs,
+			trace.StringAttribute("httptrace.dns_done.error", info.Err.Error()))
+	}
+	s.sp.Annotate(attrs, "DNSDone")
+}
+
+func (s spanAnnotator) connectStart(network, addr string) {
+	attrs := []trace.Attribute{
+		trace.StringAttribute("httptrace.connect_start.network", network),
+		trace.StringAttribute("httptrace.connect_start.addr", addr),
+	}
+	s.sp.Annotate(attrs, "ConnectStart")
+}
+
+func (s spanAnnotator) connectDone(network, addr string, err error) {
+	attrs := []trace.Attribute{
+		trace.StringAttribute("httptrace.connect_done.network", network),
+		trace.StringAttribute("httptrace.connect_done.addr", addr),
+	}
+	if err != nil {
+		attrs = append(attrs,
+			trace.StringAttribute("httptrace.connect_done.error", err.Error()))
+	}
+	s.sp.Annotate(attrs, "ConnectDone")
+}
+
+func (s spanAnnotator) tlsHandshakeStart() {
+	s.sp.Annotate(nil, "TLSHandshakeStart")
+}
+
+func (s spanAnnotator) tlsHandshakeDone(_ tls.ConnectionState, err error) {
+	var attrs []trace.Attribute
+	if err != nil {
+		attrs = append(attrs,
+			trace.StringAttribute("httptrace.tls_handshake_done.error", err.Error()))
+	}
+	s.sp.Annotate(attrs, "TLSHandshakeDone")
+}
+
+func (s spanAnnotator) wroteHeaders() {
+	s.sp.Annotate(nil, "WroteHeaders")
+}
+
+func (s spanAnnotator) wait100Continue() {
+	s.sp.Annotate(nil, "Wait100Continue")
+}
+
+func (s spanAnnotator) wroteRequest(info httptrace.WroteRequestInfo) {
+	var attrs []trace.Attribute
+	if info.Err != nil {
+		attrs = append(attrs,
+			trace.StringAttribute("httptrace.wrote_request.error", info.Err.Error()))
+	}
+	s.sp.Annotate(attrs, "WroteRequest")
+}
diff --git a/vendor/go.opencensus.io/plugin/ochttp/stats.go b/vendor/go.opencensus.io/plugin/ochttp/stats.go
new file mode 100644
index 0000000..46dcc8e
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/stats.go
@@ -0,0 +1,265 @@
+// Copyright 2018, 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 ochttp
+
+import (
+	"go.opencensus.io/stats"
+	"go.opencensus.io/stats/view"
+	"go.opencensus.io/tag"
+)
+
+// The following client HTTP measures are supported for use in custom views.
+var (
+	// Deprecated: Use a Count aggregation over one of the other client measures to achieve the same effect.
+	ClientRequestCount = stats.Int64("opencensus.io/http/client/request_count", "Number of HTTP requests started", stats.UnitDimensionless)
+	// Deprecated: Use ClientSentBytes.
+	ClientRequestBytes = stats.Int64("opencensus.io/http/client/request_bytes", "HTTP request body size if set as ContentLength (uncompressed)", stats.UnitBytes)
+	// Deprecated: Use ClientReceivedBytes.
+	ClientResponseBytes = stats.Int64("opencensus.io/http/client/response_bytes", "HTTP response body size (uncompressed)", stats.UnitBytes)
+	// Deprecated: Use ClientRoundtripLatency.
+	ClientLatency = stats.Float64("opencensus.io/http/client/latency", "End-to-end latency", stats.UnitMilliseconds)
+)
+
+// Client measures supported for use in custom views.
+var (
+	ClientSentBytes = stats.Int64(
+		"opencensus.io/http/client/sent_bytes",
+		"Total bytes sent in request body (not including headers)",
+		stats.UnitBytes,
+	)
+	ClientReceivedBytes = stats.Int64(
+		"opencensus.io/http/client/received_bytes",
+		"Total bytes received in response bodies (not including headers but including error responses with bodies)",
+		stats.UnitBytes,
+	)
+	ClientRoundtripLatency = stats.Float64(
+		"opencensus.io/http/client/roundtrip_latency",
+		"Time between first byte of request headers sent to last byte of response received, or terminal error",
+		stats.UnitMilliseconds,
+	)
+)
+
+// The following server HTTP measures are supported for use in custom views:
+var (
+	ServerRequestCount  = stats.Int64("opencensus.io/http/server/request_count", "Number of HTTP requests started", stats.UnitDimensionless)
+	ServerRequestBytes  = stats.Int64("opencensus.io/http/server/request_bytes", "HTTP request body size if set as ContentLength (uncompressed)", stats.UnitBytes)
+	ServerResponseBytes = stats.Int64("opencensus.io/http/server/response_bytes", "HTTP response body size (uncompressed)", stats.UnitBytes)
+	ServerLatency       = stats.Float64("opencensus.io/http/server/latency", "End-to-end latency", stats.UnitMilliseconds)
+)
+
+// The following tags are applied to stats recorded by this package. Host, Path
+// and Method are applied to all measures. StatusCode is not applied to
+// ClientRequestCount or ServerRequestCount, since it is recorded before the status is known.
+var (
+	// Host is the value of the HTTP Host header.
+	//
+	// The value of this tag can be controlled by the HTTP client, so you need
+	// to watch out for potentially generating high-cardinality labels in your
+	// metrics backend if you use this tag in views.
+	Host, _ = tag.NewKey("http.host")
+
+	// StatusCode is the numeric HTTP response status code,
+	// or "error" if a transport error occurred and no status code was read.
+	StatusCode, _ = tag.NewKey("http.status")
+
+	// Path is the URL path (not including query string) in the request.
+	//
+	// The value of this tag can be controlled by the HTTP client, so you need
+	// to watch out for potentially generating high-cardinality labels in your
+	// metrics backend if you use this tag in views.
+	Path, _ = tag.NewKey("http.path")
+
+	// Method is the HTTP method of the request, capitalized (GET, POST, etc.).
+	Method, _ = tag.NewKey("http.method")
+
+	// KeyServerRoute is a low cardinality string representing the logical
+	// handler of the request. This is usually the pattern registered on the a
+	// ServeMux (or similar string).
+	KeyServerRoute, _ = tag.NewKey("http_server_route")
+)
+
+// Client tag keys.
+var (
+	// KeyClientMethod is the HTTP method, capitalized (i.e. GET, POST, PUT, DELETE, etc.).
+	KeyClientMethod, _ = tag.NewKey("http_client_method")
+	// KeyClientPath is the URL path (not including query string).
+	KeyClientPath, _ = tag.NewKey("http_client_path")
+	// KeyClientStatus is the HTTP status code as an integer (e.g. 200, 404, 500.), or "error" if no response status line was received.
+	KeyClientStatus, _ = tag.NewKey("http_client_status")
+	// KeyClientHost is the value of the request Host header.
+	KeyClientHost, _ = tag.NewKey("http_client_host")
+)
+
+// Default distributions used by views in this package.
+var (
+	DefaultSizeDistribution    = view.Distribution(0, 1024, 2048, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216, 67108864, 268435456, 1073741824, 4294967296)
+	DefaultLatencyDistribution = view.Distribution(0, 1, 2, 3, 4, 5, 6, 8, 10, 13, 16, 20, 25, 30, 40, 50, 65, 80, 100, 130, 160, 200, 250, 300, 400, 500, 650, 800, 1000, 2000, 5000, 10000, 20000, 50000, 100000)
+)
+
+// Package ochttp provides some convenience views.
+// You still need to register these views for data to actually be collected.
+var (
+	ClientSentBytesDistribution = &view.View{
+		Name:        "opencensus.io/http/client/sent_bytes",
+		Measure:     ClientSentBytes,
+		Aggregation: DefaultSizeDistribution,
+		Description: "Total bytes sent in request body (not including headers), by HTTP method and response status",
+		TagKeys:     []tag.Key{KeyClientMethod, KeyClientStatus},
+	}
+
+	ClientReceivedBytesDistribution = &view.View{
+		Name:        "opencensus.io/http/client/received_bytes",
+		Measure:     ClientReceivedBytes,
+		Aggregation: DefaultSizeDistribution,
+		Description: "Total bytes received in response bodies (not including headers but including error responses with bodies), by HTTP method and response status",
+		TagKeys:     []tag.Key{KeyClientMethod, KeyClientStatus},
+	}
+
+	ClientRoundtripLatencyDistribution = &view.View{
+		Name:        "opencensus.io/http/client/roundtrip_latency",
+		Measure:     ClientRoundtripLatency,
+		Aggregation: DefaultLatencyDistribution,
+		Description: "End-to-end latency, by HTTP method and response status",
+		TagKeys:     []tag.Key{KeyClientMethod, KeyClientStatus},
+	}
+
+	ClientCompletedCount = &view.View{
+		Name:        "opencensus.io/http/client/completed_count",
+		Measure:     ClientRoundtripLatency,
+		Aggregation: view.Count(),
+		Description: "Count of completed requests, by HTTP method and response status",
+		TagKeys:     []tag.Key{KeyClientMethod, KeyClientStatus},
+	}
+)
+
+var (
+	// Deprecated: No direct replacement, but see ClientCompletedCount.
+	ClientRequestCountView = &view.View{
+		Name:        "opencensus.io/http/client/request_count",
+		Description: "Count of HTTP requests started",
+		Measure:     ClientRequestCount,
+		Aggregation: view.Count(),
+	}
+
+	// Deprecated: Use ClientSentBytesDistribution.
+	ClientRequestBytesView = &view.View{
+		Name:        "opencensus.io/http/client/request_bytes",
+		Description: "Size distribution of HTTP request body",
+		Measure:     ClientSentBytes,
+		Aggregation: DefaultSizeDistribution,
+	}
+
+	// Deprecated: Use ClientReceivedBytesDistribution.
+	ClientResponseBytesView = &view.View{
+		Name:        "opencensus.io/http/client/response_bytes",
+		Description: "Size distribution of HTTP response body",
+		Measure:     ClientReceivedBytes,
+		Aggregation: DefaultSizeDistribution,
+	}
+
+	// Deprecated: Use ClientRoundtripLatencyDistribution.
+	ClientLatencyView = &view.View{
+		Name:        "opencensus.io/http/client/latency",
+		Description: "Latency distribution of HTTP requests",
+		Measure:     ClientRoundtripLatency,
+		Aggregation: DefaultLatencyDistribution,
+	}
+
+	// Deprecated: Use ClientCompletedCount.
+	ClientRequestCountByMethod = &view.View{
+		Name:        "opencensus.io/http/client/request_count_by_method",
+		Description: "Client request count by HTTP method",
+		TagKeys:     []tag.Key{Method},
+		Measure:     ClientSentBytes,
+		Aggregation: view.Count(),
+	}
+
+	// Deprecated: Use ClientCompletedCount.
+	ClientResponseCountByStatusCode = &view.View{
+		Name:        "opencensus.io/http/client/response_count_by_status_code",
+		Description: "Client response count by status code",
+		TagKeys:     []tag.Key{StatusCode},
+		Measure:     ClientRoundtripLatency,
+		Aggregation: view.Count(),
+	}
+)
+
+var (
+	ServerRequestCountView = &view.View{
+		Name:        "opencensus.io/http/server/request_count",
+		Description: "Count of HTTP requests started",
+		Measure:     ServerRequestCount,
+		Aggregation: view.Count(),
+	}
+
+	ServerRequestBytesView = &view.View{
+		Name:        "opencensus.io/http/server/request_bytes",
+		Description: "Size distribution of HTTP request body",
+		Measure:     ServerRequestBytes,
+		Aggregation: DefaultSizeDistribution,
+	}
+
+	ServerResponseBytesView = &view.View{
+		Name:        "opencensus.io/http/server/response_bytes",
+		Description: "Size distribution of HTTP response body",
+		Measure:     ServerResponseBytes,
+		Aggregation: DefaultSizeDistribution,
+	}
+
+	ServerLatencyView = &view.View{
+		Name:        "opencensus.io/http/server/latency",
+		Description: "Latency distribution of HTTP requests",
+		Measure:     ServerLatency,
+		Aggregation: DefaultLatencyDistribution,
+	}
+
+	ServerRequestCountByMethod = &view.View{
+		Name:        "opencensus.io/http/server/request_count_by_method",
+		Description: "Server request count by HTTP method",
+		TagKeys:     []tag.Key{Method},
+		Measure:     ServerRequestCount,
+		Aggregation: view.Count(),
+	}
+
+	ServerResponseCountByStatusCode = &view.View{
+		Name:        "opencensus.io/http/server/response_count_by_status_code",
+		Description: "Server response count by status code",
+		TagKeys:     []tag.Key{StatusCode},
+		Measure:     ServerLatency,
+		Aggregation: view.Count(),
+	}
+)
+
+// DefaultClientViews are the default client views provided by this package.
+// Deprecated: No replacement. Register the views you would like individually.
+var DefaultClientViews = []*view.View{
+	ClientRequestCountView,
+	ClientRequestBytesView,
+	ClientResponseBytesView,
+	ClientLatencyView,
+	ClientRequestCountByMethod,
+	ClientResponseCountByStatusCode,
+}
+
+// DefaultServerViews are the default server views provided by this package.
+// Deprecated: No replacement. Register the views you would like individually.
+var DefaultServerViews = []*view.View{
+	ServerRequestCountView,
+	ServerRequestBytesView,
+	ServerResponseBytesView,
+	ServerLatencyView,
+	ServerRequestCountByMethod,
+	ServerResponseCountByStatusCode,
+}
diff --git a/vendor/go.opencensus.io/plugin/ochttp/trace.go b/vendor/go.opencensus.io/plugin/ochttp/trace.go
new file mode 100644
index 0000000..819a2d5
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/trace.go
@@ -0,0 +1,228 @@
+// Copyright 2018, 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 ochttp
+
+import (
+	"io"
+	"net/http"
+	"net/http/httptrace"
+
+	"go.opencensus.io/plugin/ochttp/propagation/b3"
+	"go.opencensus.io/trace"
+	"go.opencensus.io/trace/propagation"
+)
+
+// TODO(jbd): Add godoc examples.
+
+var defaultFormat propagation.HTTPFormat = &b3.HTTPFormat{}
+
+// Attributes recorded on the span for the requests.
+// Only trace exporters will need them.
+const (
+	HostAttribute       = "http.host"
+	MethodAttribute     = "http.method"
+	PathAttribute       = "http.path"
+	UserAgentAttribute  = "http.user_agent"
+	StatusCodeAttribute = "http.status_code"
+)
+
+type traceTransport struct {
+	base           http.RoundTripper
+	startOptions   trace.StartOptions
+	format         propagation.HTTPFormat
+	formatSpanName func(*http.Request) string
+	newClientTrace func(*http.Request, *trace.Span) *httptrace.ClientTrace
+}
+
+// TODO(jbd): Add message events for request and response size.
+
+// RoundTrip creates a trace.Span and inserts it into the outgoing request's headers.
+// The created span can follow a parent span, if a parent is presented in
+// the request's context.
+func (t *traceTransport) RoundTrip(req *http.Request) (*http.Response, error) {
+	name := t.formatSpanName(req)
+	// TODO(jbd): Discuss whether we want to prefix
+	// outgoing requests with Sent.
+	ctx, span := trace.StartSpan(req.Context(), name,
+		trace.WithSampler(t.startOptions.Sampler),
+		trace.WithSpanKind(trace.SpanKindClient))
+
+	if t.newClientTrace != nil {
+		req = req.WithContext(httptrace.WithClientTrace(ctx, t.newClientTrace(req, span)))
+	} else {
+		req = req.WithContext(ctx)
+	}
+
+	if t.format != nil {
+		// SpanContextToRequest will modify its Request argument, which is
+		// contrary to the contract for http.RoundTripper, so we need to
+		// pass it a copy of the Request.
+		// However, the Request struct itself was already copied by
+		// the WithContext calls above and so we just need to copy the header.
+		header := make(http.Header)
+		for k, v := range req.Header {
+			header[k] = v
+		}
+		req.Header = header
+		t.format.SpanContextToRequest(span.SpanContext(), req)
+	}
+
+	span.AddAttributes(requestAttrs(req)...)
+	resp, err := t.base.RoundTrip(req)
+	if err != nil {
+		span.SetStatus(trace.Status{Code: trace.StatusCodeUnknown, Message: err.Error()})
+		span.End()
+		return resp, err
+	}
+
+	span.AddAttributes(responseAttrs(resp)...)
+	span.SetStatus(TraceStatus(resp.StatusCode, resp.Status))
+
+	// span.End() will be invoked after
+	// a read from resp.Body returns io.EOF or when
+	// resp.Body.Close() is invoked.
+	resp.Body = &bodyTracker{rc: resp.Body, span: span}
+	return resp, err
+}
+
+// bodyTracker wraps a response.Body and invokes
+// trace.EndSpan on encountering io.EOF on reading
+// the body of the original response.
+type bodyTracker struct {
+	rc   io.ReadCloser
+	span *trace.Span
+}
+
+var _ io.ReadCloser = (*bodyTracker)(nil)
+
+func (bt *bodyTracker) Read(b []byte) (int, error) {
+	n, err := bt.rc.Read(b)
+
+	switch err {
+	case nil:
+		return n, nil
+	case io.EOF:
+		bt.span.End()
+	default:
+		// For all other errors, set the span status
+		bt.span.SetStatus(trace.Status{
+			// Code 2 is the error code for Internal server error.
+			Code:    2,
+			Message: err.Error(),
+		})
+	}
+	return n, err
+}
+
+func (bt *bodyTracker) Close() error {
+	// Invoking endSpan on Close will help catch the cases
+	// in which a read returned a non-nil error, we set the
+	// span status but didn't end the span.
+	bt.span.End()
+	return bt.rc.Close()
+}
+
+// CancelRequest cancels an in-flight request by closing its connection.
+func (t *traceTransport) CancelRequest(req *http.Request) {
+	type canceler interface {
+		CancelRequest(*http.Request)
+	}
+	if cr, ok := t.base.(canceler); ok {
+		cr.CancelRequest(req)
+	}
+}
+
+func spanNameFromURL(req *http.Request) string {
+	return req.URL.Path
+}
+
+func requestAttrs(r *http.Request) []trace.Attribute {
+	return []trace.Attribute{
+		trace.StringAttribute(PathAttribute, r.URL.Path),
+		trace.StringAttribute(HostAttribute, r.URL.Host),
+		trace.StringAttribute(MethodAttribute, r.Method),
+		trace.StringAttribute(UserAgentAttribute, r.UserAgent()),
+	}
+}
+
+func responseAttrs(resp *http.Response) []trace.Attribute {
+	return []trace.Attribute{
+		trace.Int64Attribute(StatusCodeAttribute, int64(resp.StatusCode)),
+	}
+}
+
+// TraceStatus is a utility to convert the HTTP status code to a trace.Status that
+// represents the outcome as closely as possible.
+func TraceStatus(httpStatusCode int, statusLine string) trace.Status {
+	var code int32
+	if httpStatusCode < 200 || httpStatusCode >= 400 {
+		code = trace.StatusCodeUnknown
+	}
+	switch httpStatusCode {
+	case 499:
+		code = trace.StatusCodeCancelled
+	case http.StatusBadRequest:
+		code = trace.StatusCodeInvalidArgument
+	case http.StatusGatewayTimeout:
+		code = trace.StatusCodeDeadlineExceeded
+	case http.StatusNotFound:
+		code = trace.StatusCodeNotFound
+	case http.StatusForbidden:
+		code = trace.StatusCodePermissionDenied
+	case http.StatusUnauthorized: // 401 is actually unauthenticated.
+		code = trace.StatusCodeUnauthenticated
+	case http.StatusTooManyRequests:
+		code = trace.StatusCodeResourceExhausted
+	case http.StatusNotImplemented:
+		code = trace.StatusCodeUnimplemented
+	case http.StatusServiceUnavailable:
+		code = trace.StatusCodeUnavailable
+	case http.StatusOK:
+		code = trace.StatusCodeOK
+	}
+	return trace.Status{Code: code, Message: codeToStr[code]}
+}
+
+var codeToStr = map[int32]string{
+	trace.StatusCodeOK:                 `OK`,
+	trace.StatusCodeCancelled:          `CANCELLED`,
+	trace.StatusCodeUnknown:            `UNKNOWN`,
+	trace.StatusCodeInvalidArgument:    `INVALID_ARGUMENT`,
+	trace.StatusCodeDeadlineExceeded:   `DEADLINE_EXCEEDED`,
+	trace.StatusCodeNotFound:           `NOT_FOUND`,
+	trace.StatusCodeAlreadyExists:      `ALREADY_EXISTS`,
+	trace.StatusCodePermissionDenied:   `PERMISSION_DENIED`,
+	trace.StatusCodeResourceExhausted:  `RESOURCE_EXHAUSTED`,
+	trace.StatusCodeFailedPrecondition: `FAILED_PRECONDITION`,
+	trace.StatusCodeAborted:            `ABORTED`,
+	trace.StatusCodeOutOfRange:         `OUT_OF_RANGE`,
+	trace.StatusCodeUnimplemented:      `UNIMPLEMENTED`,
+	trace.StatusCodeInternal:           `INTERNAL`,
+	trace.StatusCodeUnavailable:        `UNAVAILABLE`,
+	trace.StatusCodeDataLoss:           `DATA_LOSS`,
+	trace.StatusCodeUnauthenticated:    `UNAUTHENTICATED`,
+}
+
+func isHealthEndpoint(path string) bool {
+	// Health checking is pretty frequent and
+	// traces collected for health endpoints
+	// can be extremely noisy and expensive.
+	// Disable canonical health checking endpoints
+	// like /healthz and /_ah/health for now.
+	if path == "/healthz" || path == "/_ah/health" {
+		return true
+	}
+	return false
+}
diff --git a/vendor/go.opencensus.io/stats/doc.go b/vendor/go.opencensus.io/stats/doc.go
new file mode 100644
index 0000000..00d473e
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/doc.go
@@ -0,0 +1,69 @@
+// 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 stats contains support for OpenCensus stats recording.
+
+OpenCensus allows users to create typed measures, record measurements,
+aggregate the collected data, and export the aggregated data.
+
+Measures
+
+A measure represents a type of data point to be tracked and recorded.
+For example, latency, request Mb/s, and response Mb/s are measures
+to collect from a server.
+
+Measure constructors such as Int64 and Float64 automatically
+register the measure by the given name. Each registered measure needs
+to be unique by name. Measures also have a description and a unit.
+
+Libraries can define and export measures. Application authors can then
+create views and collect and break down measures by the tags they are
+interested in.
+
+Recording measurements
+
+Measurement is a data point to be collected for a measure. For example,
+for a latency (ms) measure, 100 is a measurement that represents a 100ms
+latency event. Measurements are created from measures with
+the current context. Tags from the current context are recorded with the
+measurements if they are any.
+
+Recorded measurements are dropped immediately if no views are registered for them.
+There is usually no need to conditionally enable and disable
+recording to reduce cost. Recording of measurements is cheap.
+
+Libraries can always record measurements, and applications can later decide
+on which measurements they want to collect by registering views. This allows
+libraries to turn on the instrumentation by default.
+
+Exemplars
+
+For a given recorded measurement, the associated exemplar is a diagnostic map
+that gives more information about the measurement.
+
+When aggregated using a Distribution aggregation, an exemplar is kept for each
+bucket in the Distribution. This allows you to easily find an example of a
+measurement that fell into each bucket.
+
+For example, if you also use the OpenCensus trace package and you
+record a measurement with a context that contains a sampled trace span,
+then the trace span will be added to the exemplar associated with the measurement.
+
+When exported to a supporting back end, you should be able to easily navigate
+to example traces that fell into each bucket in the Distribution.
+
+*/
+package stats // import "go.opencensus.io/stats"
diff --git a/vendor/go.opencensus.io/stats/internal/record.go b/vendor/go.opencensus.io/stats/internal/record.go
new file mode 100644
index 0000000..ed54552
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/internal/record.go
@@ -0,0 +1,25 @@
+// Copyright 2018, 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 internal
+
+import (
+	"go.opencensus.io/tag"
+)
+
+// DefaultRecorder will be called for each Record call.
+var DefaultRecorder func(tags *tag.Map, measurement interface{}, attachments map[string]string)
+
+// SubscriptionReporter reports when a view subscribed with a measure.
+var SubscriptionReporter func(measure string)
diff --git a/vendor/go.opencensus.io/stats/internal/validation.go b/vendor/go.opencensus.io/stats/internal/validation.go
new file mode 100644
index 0000000..b946667
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/internal/validation.go
@@ -0,0 +1,28 @@
+// Copyright 2018, 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 internal // import "go.opencensus.io/stats/internal"
+
+const (
+	MaxNameLength = 255
+)
+
+func IsPrintable(str string) bool {
+	for _, r := range str {
+		if !(r >= ' ' && r <= '~') {
+			return false
+		}
+	}
+	return true
+}
diff --git a/vendor/go.opencensus.io/stats/measure.go b/vendor/go.opencensus.io/stats/measure.go
new file mode 100644
index 0000000..64d02b1
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/measure.go
@@ -0,0 +1,123 @@
+// 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 stats
+
+import (
+	"sync"
+	"sync/atomic"
+)
+
+// Measure represents a single numeric value to be tracked and recorded.
+// For example, latency, request bytes, and response bytes could be measures
+// to collect from a server.
+//
+// Measures by themselves have no outside effects. In order to be exported,
+// the measure needs to be used in a View. If no Views are defined over a
+// measure, there is very little cost in recording it.
+type Measure interface {
+	// Name returns the name of this measure.
+	//
+	// Measure names are globally unique (among all libraries linked into your program).
+	// We recommend prefixing the measure name with a domain name relevant to your
+	// project or application.
+	//
+	// Measure names are never sent over the wire or exported to backends.
+	// They are only used to create Views.
+	Name() string
+
+	// Description returns the human-readable description of this measure.
+	Description() string
+
+	// Unit returns the units for the values this measure takes on.
+	//
+	// Units are encoded according to the case-sensitive abbreviations from the
+	// Unified Code for Units of Measure: http://unitsofmeasure.org/ucum.html
+	Unit() string
+}
+
+// measureDescriptor is the untyped descriptor associated with each measure.
+// Int64Measure and Float64Measure wrap measureDescriptor to provide typed
+// recording APIs.
+// Two Measures with the same name will have the same measureDescriptor.
+type measureDescriptor struct {
+	subs int32 // access atomically
+
+	name        string
+	description string
+	unit        string
+}
+
+func (m *measureDescriptor) subscribe() {
+	atomic.StoreInt32(&m.subs, 1)
+}
+
+func (m *measureDescriptor) subscribed() bool {
+	return atomic.LoadInt32(&m.subs) == 1
+}
+
+// Name returns the name of the measure.
+func (m *measureDescriptor) Name() string {
+	return m.name
+}
+
+// Description returns the description of the measure.
+func (m *measureDescriptor) Description() string {
+	return m.description
+}
+
+// Unit returns the unit of the measure.
+func (m *measureDescriptor) Unit() string {
+	return m.unit
+}
+
+var (
+	mu       sync.RWMutex
+	measures = make(map[string]*measureDescriptor)
+)
+
+func registerMeasureHandle(name, desc, unit string) *measureDescriptor {
+	mu.Lock()
+	defer mu.Unlock()
+
+	if stored, ok := measures[name]; ok {
+		return stored
+	}
+	m := &measureDescriptor{
+		name:        name,
+		description: desc,
+		unit:        unit,
+	}
+	measures[name] = m
+	return m
+}
+
+// Measurement is the numeric value measured when recording stats. Each measure
+// provides methods to create measurements of their kind. For example, Int64Measure
+// provides M to convert an int64 into a measurement.
+type Measurement struct {
+	v float64
+	m *measureDescriptor
+}
+
+// Value returns the value of the Measurement as a float64.
+func (m Measurement) Value() float64 {
+	return m.v
+}
+
+// Measure returns the Measure from which this Measurement was created.
+func (m Measurement) Measure() Measure {
+	return m.m
+}
diff --git a/vendor/go.opencensus.io/stats/measure_float64.go b/vendor/go.opencensus.io/stats/measure_float64.go
new file mode 100644
index 0000000..acedb21
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/measure_float64.go
@@ -0,0 +1,36 @@
+// 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 stats
+
+// Float64Measure is a measure for float64 values.
+type Float64Measure struct {
+	*measureDescriptor
+}
+
+// M creates a new float64 measurement.
+// Use Record to record measurements.
+func (m *Float64Measure) M(v float64) Measurement {
+	return Measurement{m: m.measureDescriptor, v: v}
+}
+
+// Float64 creates a new measure for float64 values.
+//
+// See the documentation for interface Measure for more guidance on the
+// parameters of this function.
+func Float64(name, description, unit string) *Float64Measure {
+	mi := registerMeasureHandle(name, description, unit)
+	return &Float64Measure{mi}
+}
diff --git a/vendor/go.opencensus.io/stats/measure_int64.go b/vendor/go.opencensus.io/stats/measure_int64.go
new file mode 100644
index 0000000..c4243ba
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/measure_int64.go
@@ -0,0 +1,36 @@
+// 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 stats
+
+// Int64Measure is a measure for int64 values.
+type Int64Measure struct {
+	*measureDescriptor
+}
+
+// M creates a new int64 measurement.
+// Use Record to record measurements.
+func (m *Int64Measure) M(v int64) Measurement {
+	return Measurement{m: m.measureDescriptor, v: float64(v)}
+}
+
+// Int64 creates a new measure for int64 values.
+//
+// See the documentation for interface Measure for more guidance on the
+// parameters of this function.
+func Int64(name, description, unit string) *Int64Measure {
+	mi := registerMeasureHandle(name, description, unit)
+	return &Int64Measure{mi}
+}
diff --git a/vendor/go.opencensus.io/stats/record.go b/vendor/go.opencensus.io/stats/record.go
new file mode 100644
index 0000000..0aced02
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/record.go
@@ -0,0 +1,69 @@
+// Copyright 2018, 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 stats
+
+import (
+	"context"
+
+	"go.opencensus.io/exemplar"
+	"go.opencensus.io/stats/internal"
+	"go.opencensus.io/tag"
+)
+
+func init() {
+	internal.SubscriptionReporter = func(measure string) {
+		mu.Lock()
+		measures[measure].subscribe()
+		mu.Unlock()
+	}
+}
+
+// Record records one or multiple measurements with the same context at once.
+// If there are any tags in the context, measurements will be tagged with them.
+func Record(ctx context.Context, ms ...Measurement) {
+	recorder := internal.DefaultRecorder
+	if recorder == nil {
+		return
+	}
+	if len(ms) == 0 {
+		return
+	}
+	record := false
+	for _, m := range ms {
+		if m.m.subscribed() {
+			record = true
+			break
+		}
+	}
+	if !record {
+		return
+	}
+	recorder(tag.FromContext(ctx), ms, exemplar.AttachmentsFromContext(ctx))
+}
+
+// RecordWithTags records one or multiple measurements at once.
+//
+// Measurements will be tagged with the tags in the context mutated by the mutators.
+// RecordWithTags is useful if you want to record with tag mutations but don't want
+// to propagate the mutations in the context.
+func RecordWithTags(ctx context.Context, mutators []tag.Mutator, ms ...Measurement) error {
+	ctx, err := tag.New(ctx, mutators...)
+	if err != nil {
+		return err
+	}
+	Record(ctx, ms...)
+	return nil
+}
diff --git a/vendor/go.opencensus.io/stats/units.go b/vendor/go.opencensus.io/stats/units.go
new file mode 100644
index 0000000..6931a5f
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/units.go
@@ -0,0 +1,25 @@
+// Copyright 2018, 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 stats
+
+// Units are encoded according to the case-sensitive abbreviations from the
+// Unified Code for Units of Measure: http://unitsofmeasure.org/ucum.html
+const (
+	UnitNone          = "1" // Deprecated: Use UnitDimensionless.
+	UnitDimensionless = "1"
+	UnitBytes         = "By"
+	UnitMilliseconds  = "ms"
+)
diff --git a/vendor/go.opencensus.io/stats/view/aggregation.go b/vendor/go.opencensus.io/stats/view/aggregation.go
new file mode 100644
index 0000000..b7f169b
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/aggregation.go
@@ -0,0 +1,120 @@
+// 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 view
+
+// AggType represents the type of aggregation function used on a View.
+type AggType int
+
+// All available aggregation types.
+const (
+	AggTypeNone         AggType = iota // no aggregation; reserved for future use.
+	AggTypeCount                       // the count aggregation, see Count.
+	AggTypeSum                         // the sum aggregation, see Sum.
+	AggTypeDistribution                // the distribution aggregation, see Distribution.
+	AggTypeLastValue                   // the last value aggregation, see LastValue.
+)
+
+func (t AggType) String() string {
+	return aggTypeName[t]
+}
+
+var aggTypeName = map[AggType]string{
+	AggTypeNone:         "None",
+	AggTypeCount:        "Count",
+	AggTypeSum:          "Sum",
+	AggTypeDistribution: "Distribution",
+	AggTypeLastValue:    "LastValue",
+}
+
+// Aggregation represents a data aggregation method. Use one of the functions:
+// Count, Sum, or Distribution to construct an Aggregation.
+type Aggregation struct {
+	Type    AggType   // Type is the AggType of this Aggregation.
+	Buckets []float64 // Buckets are the bucket endpoints if this Aggregation represents a distribution, see Distribution.
+
+	newData func() AggregationData
+}
+
+var (
+	aggCount = &Aggregation{
+		Type: AggTypeCount,
+		newData: func() AggregationData {
+			return &CountData{}
+		},
+	}
+	aggSum = &Aggregation{
+		Type: AggTypeSum,
+		newData: func() AggregationData {
+			return &SumData{}
+		},
+	}
+)
+
+// Count indicates that data collected and aggregated
+// with this method will be turned into a count value.
+// For example, total number of accepted requests can be
+// aggregated by using Count.
+func Count() *Aggregation {
+	return aggCount
+}
+
+// Sum indicates that data collected and aggregated
+// with this method will be summed up.
+// For example, accumulated request bytes can be aggregated by using
+// Sum.
+func Sum() *Aggregation {
+	return aggSum
+}
+
+// Distribution indicates that the desired aggregation is
+// a histogram distribution.
+//
+// An distribution aggregation may contain a histogram of the values in the
+// population. The bucket boundaries for that histogram are described
+// by the bounds. This defines len(bounds)+1 buckets.
+//
+// If len(bounds) >= 2 then the boundaries for bucket index i are:
+//
+//     [-infinity, bounds[i]) for i = 0
+//     [bounds[i-1], bounds[i]) for 0 < i < length
+//     [bounds[i-1], +infinity) for i = length
+//
+// If len(bounds) is 0 then there is no histogram associated with the
+// distribution. There will be a single bucket with boundaries
+// (-infinity, +infinity).
+//
+// If len(bounds) is 1 then there is no finite buckets, and that single
+// element is the common boundary of the overflow and underflow buckets.
+func Distribution(bounds ...float64) *Aggregation {
+	return &Aggregation{
+		Type:    AggTypeDistribution,
+		Buckets: bounds,
+		newData: func() AggregationData {
+			return newDistributionData(bounds)
+		},
+	}
+}
+
+// LastValue only reports the last value recorded using this
+// aggregation. All other measurements will be dropped.
+func LastValue() *Aggregation {
+	return &Aggregation{
+		Type: AggTypeLastValue,
+		newData: func() AggregationData {
+			return &LastValueData{}
+		},
+	}
+}
diff --git a/vendor/go.opencensus.io/stats/view/aggregation_data.go b/vendor/go.opencensus.io/stats/view/aggregation_data.go
new file mode 100644
index 0000000..960b946
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/aggregation_data.go
@@ -0,0 +1,235 @@
+// 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 view
+
+import (
+	"math"
+
+	"go.opencensus.io/exemplar"
+)
+
+// AggregationData represents an aggregated value from a collection.
+// They are reported on the view data during exporting.
+// Mosts users won't directly access aggregration data.
+type AggregationData interface {
+	isAggregationData() bool
+	addSample(e *exemplar.Exemplar)
+	clone() AggregationData
+	equal(other AggregationData) bool
+}
+
+const epsilon = 1e-9
+
+// CountData is the aggregated data for the Count aggregation.
+// A count aggregation processes data and counts the recordings.
+//
+// Most users won't directly access count data.
+type CountData struct {
+	Value int64
+}
+
+func (a *CountData) isAggregationData() bool { return true }
+
+func (a *CountData) addSample(_ *exemplar.Exemplar) {
+	a.Value = a.Value + 1
+}
+
+func (a *CountData) clone() AggregationData {
+	return &CountData{Value: a.Value}
+}
+
+func (a *CountData) equal(other AggregationData) bool {
+	a2, ok := other.(*CountData)
+	if !ok {
+		return false
+	}
+
+	return a.Value == a2.Value
+}
+
+// SumData is the aggregated data for the Sum aggregation.
+// A sum aggregation processes data and sums up the recordings.
+//
+// Most users won't directly access sum data.
+type SumData struct {
+	Value float64
+}
+
+func (a *SumData) isAggregationData() bool { return true }
+
+func (a *SumData) addSample(e *exemplar.Exemplar) {
+	a.Value += e.Value
+}
+
+func (a *SumData) clone() AggregationData {
+	return &SumData{Value: a.Value}
+}
+
+func (a *SumData) equal(other AggregationData) bool {
+	a2, ok := other.(*SumData)
+	if !ok {
+		return false
+	}
+	return math.Pow(a.Value-a2.Value, 2) < epsilon
+}
+
+// DistributionData is the aggregated data for the
+// Distribution aggregation.
+//
+// Most users won't directly access distribution data.
+//
+// For a distribution with N bounds, the associated DistributionData will have
+// N+1 buckets.
+type DistributionData struct {
+	Count           int64   // number of data points aggregated
+	Min             float64 // minimum value in the distribution
+	Max             float64 // max value in the distribution
+	Mean            float64 // mean of the distribution
+	SumOfSquaredDev float64 // sum of the squared deviation from the mean
+	CountPerBucket  []int64 // number of occurrences per bucket
+	// ExemplarsPerBucket is slice the same length as CountPerBucket containing
+	// an exemplar for the associated bucket, or nil.
+	ExemplarsPerBucket []*exemplar.Exemplar
+	bounds             []float64 // histogram distribution of the values
+}
+
+func newDistributionData(bounds []float64) *DistributionData {
+	bucketCount := len(bounds) + 1
+	return &DistributionData{
+		CountPerBucket:     make([]int64, bucketCount),
+		ExemplarsPerBucket: make([]*exemplar.Exemplar, bucketCount),
+		bounds:             bounds,
+		Min:                math.MaxFloat64,
+		Max:                math.SmallestNonzeroFloat64,
+	}
+}
+
+// Sum returns the sum of all samples collected.
+func (a *DistributionData) Sum() float64 { return a.Mean * float64(a.Count) }
+
+func (a *DistributionData) variance() float64 {
+	if a.Count <= 1 {
+		return 0
+	}
+	return a.SumOfSquaredDev / float64(a.Count-1)
+}
+
+func (a *DistributionData) isAggregationData() bool { return true }
+
+func (a *DistributionData) addSample(e *exemplar.Exemplar) {
+	f := e.Value
+	if f < a.Min {
+		a.Min = f
+	}
+	if f > a.Max {
+		a.Max = f
+	}
+	a.Count++
+	a.addToBucket(e)
+
+	if a.Count == 1 {
+		a.Mean = f
+		return
+	}
+
+	oldMean := a.Mean
+	a.Mean = a.Mean + (f-a.Mean)/float64(a.Count)
+	a.SumOfSquaredDev = a.SumOfSquaredDev + (f-oldMean)*(f-a.Mean)
+}
+
+func (a *DistributionData) addToBucket(e *exemplar.Exemplar) {
+	var count *int64
+	var ex **exemplar.Exemplar
+	for i, b := range a.bounds {
+		if e.Value < b {
+			count = &a.CountPerBucket[i]
+			ex = &a.ExemplarsPerBucket[i]
+			break
+		}
+	}
+	if count == nil {
+		count = &a.CountPerBucket[len(a.bounds)]
+		ex = &a.ExemplarsPerBucket[len(a.bounds)]
+	}
+	*count++
+	*ex = maybeRetainExemplar(*ex, e)
+}
+
+func maybeRetainExemplar(old, cur *exemplar.Exemplar) *exemplar.Exemplar {
+	if old == nil {
+		return cur
+	}
+
+	// Heuristic to pick the "better" exemplar: first keep the one with a
+	// sampled trace attachment, if neither have a trace attachment, pick the
+	// one with more attachments.
+	_, haveTraceID := cur.Attachments[exemplar.KeyTraceID]
+	if haveTraceID || len(cur.Attachments) >= len(old.Attachments) {
+		return cur
+	}
+	return old
+}
+
+func (a *DistributionData) clone() AggregationData {
+	c := *a
+	c.CountPerBucket = append([]int64(nil), a.CountPerBucket...)
+	c.ExemplarsPerBucket = append([]*exemplar.Exemplar(nil), a.ExemplarsPerBucket...)
+	return &c
+}
+
+func (a *DistributionData) equal(other AggregationData) bool {
+	a2, ok := other.(*DistributionData)
+	if !ok {
+		return false
+	}
+	if a2 == nil {
+		return false
+	}
+	if len(a.CountPerBucket) != len(a2.CountPerBucket) {
+		return false
+	}
+	for i := range a.CountPerBucket {
+		if a.CountPerBucket[i] != a2.CountPerBucket[i] {
+			return false
+		}
+	}
+	return a.Count == a2.Count && a.Min == a2.Min && a.Max == a2.Max && math.Pow(a.Mean-a2.Mean, 2) < epsilon && math.Pow(a.variance()-a2.variance(), 2) < epsilon
+}
+
+// LastValueData returns the last value recorded for LastValue aggregation.
+type LastValueData struct {
+	Value float64
+}
+
+func (l *LastValueData) isAggregationData() bool {
+	return true
+}
+
+func (l *LastValueData) addSample(e *exemplar.Exemplar) {
+	l.Value = e.Value
+}
+
+func (l *LastValueData) clone() AggregationData {
+	return &LastValueData{l.Value}
+}
+
+func (l *LastValueData) equal(other AggregationData) bool {
+	a2, ok := other.(*LastValueData)
+	if !ok {
+		return false
+	}
+	return l.Value == a2.Value
+}
diff --git a/vendor/go.opencensus.io/stats/view/collector.go b/vendor/go.opencensus.io/stats/view/collector.go
new file mode 100644
index 0000000..32415d4
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/collector.go
@@ -0,0 +1,87 @@
+// 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 view
+
+import (
+	"sort"
+
+	"go.opencensus.io/exemplar"
+
+	"go.opencensus.io/internal/tagencoding"
+	"go.opencensus.io/tag"
+)
+
+type collector struct {
+	// signatures holds the aggregations values for each unique tag signature
+	// (values for all keys) to its aggregator.
+	signatures map[string]AggregationData
+	// Aggregation is the description of the aggregation to perform for this
+	// view.
+	a *Aggregation
+}
+
+func (c *collector) addSample(s string, e *exemplar.Exemplar) {
+	aggregator, ok := c.signatures[s]
+	if !ok {
+		aggregator = c.a.newData()
+		c.signatures[s] = aggregator
+	}
+	aggregator.addSample(e)
+}
+
+// collectRows returns a snapshot of the collected Row values.
+func (c *collector) collectedRows(keys []tag.Key) []*Row {
+	rows := make([]*Row, 0, len(c.signatures))
+	for sig, aggregator := range c.signatures {
+		tags := decodeTags([]byte(sig), keys)
+		row := &Row{Tags: tags, Data: aggregator.clone()}
+		rows = append(rows, row)
+	}
+	return rows
+}
+
+func (c *collector) clearRows() {
+	c.signatures = make(map[string]AggregationData)
+}
+
+// encodeWithKeys encodes the map by using values
+// only associated with the keys provided.
+func encodeWithKeys(m *tag.Map, keys []tag.Key) []byte {
+	vb := &tagencoding.Values{
+		Buffer: make([]byte, len(keys)),
+	}
+	for _, k := range keys {
+		v, _ := m.Value(k)
+		vb.WriteValue([]byte(v))
+	}
+	return vb.Bytes()
+}
+
+// decodeTags decodes tags from the buffer and
+// orders them by the keys.
+func decodeTags(buf []byte, keys []tag.Key) []tag.Tag {
+	vb := &tagencoding.Values{Buffer: buf}
+	var tags []tag.Tag
+	for _, k := range keys {
+		v := vb.ReadValue()
+		if v != nil {
+			tags = append(tags, tag.Tag{Key: k, Value: string(v)})
+		}
+	}
+	vb.ReadIndex = 0
+	sort.Slice(tags, func(i, j int) bool { return tags[i].Key.Name() < tags[j].Key.Name() })
+	return tags
+}
diff --git a/vendor/go.opencensus.io/stats/view/doc.go b/vendor/go.opencensus.io/stats/view/doc.go
new file mode 100644
index 0000000..dced225
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/doc.go
@@ -0,0 +1,47 @@
+// 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 view contains support for collecting and exposing aggregates over stats.
+//
+// In order to collect measurements, views need to be defined and registered.
+// A view allows recorded measurements to be filtered and aggregated.
+//
+// All recorded measurements can be grouped by a list of tags.
+//
+// OpenCensus provides several aggregation methods: Count, Distribution and Sum.
+//
+// Count only counts the number of measurement points recorded.
+// Distribution provides statistical summary of the aggregated data by counting
+// how many recorded measurements fall into each bucket.
+// Sum adds up the measurement values.
+// LastValue just keeps track of the most recently recorded measurement value.
+// All aggregations are cumulative.
+//
+// Views can be registerd and unregistered at any time during program execution.
+//
+// Libraries can define views but it is recommended that in most cases registering
+// views be left up to applications.
+//
+// Exporting
+//
+// Collected and aggregated data can be exported to a metric collection
+// backend by registering its exporter.
+//
+// Multiple exporters can be registered to upload the data to various
+// different back ends.
+package view // import "go.opencensus.io/stats/view"
+
+// TODO(acetechnologist): Add a link to the language independent OpenCensus
+// spec when it is available.
diff --git a/vendor/go.opencensus.io/stats/view/export.go b/vendor/go.opencensus.io/stats/view/export.go
new file mode 100644
index 0000000..7cb5971
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/export.go
@@ -0,0 +1,58 @@
+// 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 view
+
+import "sync"
+
+var (
+	exportersMu sync.RWMutex // guards exporters
+	exporters   = make(map[Exporter]struct{})
+)
+
+// Exporter exports the collected records as view data.
+//
+// The ExportView method should return quickly; if an
+// Exporter takes a significant amount of time to
+// process a Data, that work should be done on another goroutine.
+//
+// It is safe to assume that ExportView will not be called concurrently from
+// multiple goroutines.
+//
+// The Data should not be modified.
+type Exporter interface {
+	ExportView(viewData *Data)
+}
+
+// RegisterExporter registers an exporter.
+// Collected data will be reported via all the
+// registered exporters. Once you no longer
+// want data to be exported, invoke UnregisterExporter
+// with the previously registered exporter.
+//
+// Binaries can register exporters, libraries shouldn't register exporters.
+func RegisterExporter(e Exporter) {
+	exportersMu.Lock()
+	defer exportersMu.Unlock()
+
+	exporters[e] = struct{}{}
+}
+
+// UnregisterExporter unregisters an exporter.
+func UnregisterExporter(e Exporter) {
+	exportersMu.Lock()
+	defer exportersMu.Unlock()
+
+	delete(exporters, e)
+}
diff --git a/vendor/go.opencensus.io/stats/view/view.go b/vendor/go.opencensus.io/stats/view/view.go
new file mode 100644
index 0000000..c2a08af
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/view.go
@@ -0,0 +1,185 @@
+// 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 view
+
+import (
+	"bytes"
+	"fmt"
+	"reflect"
+	"sort"
+	"sync/atomic"
+	"time"
+
+	"go.opencensus.io/exemplar"
+
+	"go.opencensus.io/stats"
+	"go.opencensus.io/stats/internal"
+	"go.opencensus.io/tag"
+)
+
+// View allows users to aggregate the recorded stats.Measurements.
+// Views need to be passed to the Register function to be before data will be
+// collected and sent to Exporters.
+type View struct {
+	Name        string // Name of View. Must be unique. If unset, will default to the name of the Measure.
+	Description string // Description is a human-readable description for this view.
+
+	// TagKeys are the tag keys describing the grouping of this view.
+	// A single Row will be produced for each combination of associated tag values.
+	TagKeys []tag.Key
+
+	// Measure is a stats.Measure to aggregate in this view.
+	Measure stats.Measure
+
+	// Aggregation is the aggregation function tp apply to the set of Measurements.
+	Aggregation *Aggregation
+}
+
+// WithName returns a copy of the View with a new name. This is useful for
+// renaming views to cope with limitations placed on metric names by various
+// backends.
+func (v *View) WithName(name string) *View {
+	vNew := *v
+	vNew.Name = name
+	return &vNew
+}
+
+// same compares two views and returns true if they represent the same aggregation.
+func (v *View) same(other *View) bool {
+	if v == other {
+		return true
+	}
+	if v == nil {
+		return false
+	}
+	return reflect.DeepEqual(v.Aggregation, other.Aggregation) &&
+		v.Measure.Name() == other.Measure.Name()
+}
+
+// canonicalize canonicalizes v by setting explicit
+// defaults for Name and Description and sorting the TagKeys
+func (v *View) canonicalize() error {
+	if v.Measure == nil {
+		return fmt.Errorf("cannot register view %q: measure not set", v.Name)
+	}
+	if v.Aggregation == nil {
+		return fmt.Errorf("cannot register view %q: aggregation not set", v.Name)
+	}
+	if v.Name == "" {
+		v.Name = v.Measure.Name()
+	}
+	if v.Description == "" {
+		v.Description = v.Measure.Description()
+	}
+	if err := checkViewName(v.Name); err != nil {
+		return err
+	}
+	sort.Slice(v.TagKeys, func(i, j int) bool {
+		return v.TagKeys[i].Name() < v.TagKeys[j].Name()
+	})
+	return nil
+}
+
+// viewInternal is the internal representation of a View.
+type viewInternal struct {
+	view       *View  // view is the canonicalized View definition associated with this view.
+	subscribed uint32 // 1 if someone is subscribed and data need to be exported, use atomic to access
+	collector  *collector
+}
+
+func newViewInternal(v *View) (*viewInternal, error) {
+	return &viewInternal{
+		view:      v,
+		collector: &collector{make(map[string]AggregationData), v.Aggregation},
+	}, nil
+}
+
+func (v *viewInternal) subscribe() {
+	atomic.StoreUint32(&v.subscribed, 1)
+}
+
+func (v *viewInternal) unsubscribe() {
+	atomic.StoreUint32(&v.subscribed, 0)
+}
+
+// isSubscribed returns true if the view is exporting
+// data by subscription.
+func (v *viewInternal) isSubscribed() bool {
+	return atomic.LoadUint32(&v.subscribed) == 1
+}
+
+func (v *viewInternal) clearRows() {
+	v.collector.clearRows()
+}
+
+func (v *viewInternal) collectedRows() []*Row {
+	return v.collector.collectedRows(v.view.TagKeys)
+}
+
+func (v *viewInternal) addSample(m *tag.Map, e *exemplar.Exemplar) {
+	if !v.isSubscribed() {
+		return
+	}
+	sig := string(encodeWithKeys(m, v.view.TagKeys))
+	v.collector.addSample(sig, e)
+}
+
+// A Data is a set of rows about usage of the single measure associated
+// with the given view. Each row is specific to a unique set of tags.
+type Data struct {
+	View       *View
+	Start, End time.Time
+	Rows       []*Row
+}
+
+// Row is the collected value for a specific set of key value pairs a.k.a tags.
+type Row struct {
+	Tags []tag.Tag
+	Data AggregationData
+}
+
+func (r *Row) String() string {
+	var buffer bytes.Buffer
+	buffer.WriteString("{ ")
+	buffer.WriteString("{ ")
+	for _, t := range r.Tags {
+		buffer.WriteString(fmt.Sprintf("{%v %v}", t.Key.Name(), t.Value))
+	}
+	buffer.WriteString(" }")
+	buffer.WriteString(fmt.Sprintf("%v", r.Data))
+	buffer.WriteString(" }")
+	return buffer.String()
+}
+
+// Equal returns true if both rows are equal. Tags are expected to be ordered
+// by the key name. Even both rows have the same tags but the tags appear in
+// different orders it will return false.
+func (r *Row) Equal(other *Row) bool {
+	if r == other {
+		return true
+	}
+	return reflect.DeepEqual(r.Tags, other.Tags) && r.Data.equal(other.Data)
+}
+
+func checkViewName(name string) error {
+	if len(name) > internal.MaxNameLength {
+		return fmt.Errorf("view name cannot be larger than %v", internal.MaxNameLength)
+	}
+	if !internal.IsPrintable(name) {
+		return fmt.Errorf("view name needs to be an ASCII string")
+	}
+	return nil
+}
diff --git a/vendor/go.opencensus.io/stats/view/worker.go b/vendor/go.opencensus.io/stats/view/worker.go
new file mode 100644
index 0000000..63b0ee3
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/worker.go
@@ -0,0 +1,229 @@
+// 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 view
+
+import (
+	"fmt"
+	"time"
+
+	"go.opencensus.io/stats"
+	"go.opencensus.io/stats/internal"
+	"go.opencensus.io/tag"
+)
+
+func init() {
+	defaultWorker = newWorker()
+	go defaultWorker.start()
+	internal.DefaultRecorder = record
+}
+
+type measureRef struct {
+	measure string
+	views   map[*viewInternal]struct{}
+}
+
+type worker struct {
+	measures   map[string]*measureRef
+	views      map[string]*viewInternal
+	startTimes map[*viewInternal]time.Time
+
+	timer      *time.Ticker
+	c          chan command
+	quit, done chan bool
+}
+
+var defaultWorker *worker
+
+var defaultReportingDuration = 10 * time.Second
+
+// Find returns a registered view associated with this name.
+// If no registered view is found, nil is returned.
+func Find(name string) (v *View) {
+	req := &getViewByNameReq{
+		name: name,
+		c:    make(chan *getViewByNameResp),
+	}
+	defaultWorker.c <- req
+	resp := <-req.c
+	return resp.v
+}
+
+// Register begins collecting data for the given views.
+// Once a view is registered, it reports data to the registered exporters.
+func Register(views ...*View) error {
+	for _, v := range views {
+		if err := v.canonicalize(); err != nil {
+			return err
+		}
+	}
+	req := &registerViewReq{
+		views: views,
+		err:   make(chan error),
+	}
+	defaultWorker.c <- req
+	return <-req.err
+}
+
+// Unregister the given views. Data will not longer be exported for these views
+// after Unregister returns.
+// It is not necessary to unregister from views you expect to collect for the
+// duration of your program execution.
+func Unregister(views ...*View) {
+	names := make([]string, len(views))
+	for i := range views {
+		names[i] = views[i].Name
+	}
+	req := &unregisterFromViewReq{
+		views: names,
+		done:  make(chan struct{}),
+	}
+	defaultWorker.c <- req
+	<-req.done
+}
+
+// RetrieveData gets a snapshot of the data collected for the the view registered
+// with the given name. It is intended for testing only.
+func RetrieveData(viewName string) ([]*Row, error) {
+	req := &retrieveDataReq{
+		now: time.Now(),
+		v:   viewName,
+		c:   make(chan *retrieveDataResp),
+	}
+	defaultWorker.c <- req
+	resp := <-req.c
+	return resp.rows, resp.err
+}
+
+func record(tags *tag.Map, ms interface{}, attachments map[string]string) {
+	req := &recordReq{
+		tm:          tags,
+		ms:          ms.([]stats.Measurement),
+		attachments: attachments,
+		t:           time.Now(),
+	}
+	defaultWorker.c <- req
+}
+
+// SetReportingPeriod sets the interval between reporting aggregated views in
+// the program. If duration is less than or equal to zero, it enables the
+// default behavior.
+//
+// Note: each exporter makes different promises about what the lowest supported
+// duration is. For example, the Stackdriver exporter recommends a value no
+// lower than 1 minute. Consult each exporter per your needs.
+func SetReportingPeriod(d time.Duration) {
+	// TODO(acetechnologist): ensure that the duration d is more than a certain
+	// value. e.g. 1s
+	req := &setReportingPeriodReq{
+		d: d,
+		c: make(chan bool),
+	}
+	defaultWorker.c <- req
+	<-req.c // don't return until the timer is set to the new duration.
+}
+
+func newWorker() *worker {
+	return &worker{
+		measures:   make(map[string]*measureRef),
+		views:      make(map[string]*viewInternal),
+		startTimes: make(map[*viewInternal]time.Time),
+		timer:      time.NewTicker(defaultReportingDuration),
+		c:          make(chan command, 1024),
+		quit:       make(chan bool),
+		done:       make(chan bool),
+	}
+}
+
+func (w *worker) start() {
+	for {
+		select {
+		case cmd := <-w.c:
+			cmd.handleCommand(w)
+		case <-w.timer.C:
+			w.reportUsage(time.Now())
+		case <-w.quit:
+			w.timer.Stop()
+			close(w.c)
+			w.done <- true
+			return
+		}
+	}
+}
+
+func (w *worker) stop() {
+	w.quit <- true
+	<-w.done
+}
+
+func (w *worker) getMeasureRef(name string) *measureRef {
+	if mr, ok := w.measures[name]; ok {
+		return mr
+	}
+	mr := &measureRef{
+		measure: name,
+		views:   make(map[*viewInternal]struct{}),
+	}
+	w.measures[name] = mr
+	return mr
+}
+
+func (w *worker) tryRegisterView(v *View) (*viewInternal, error) {
+	vi, err := newViewInternal(v)
+	if err != nil {
+		return nil, err
+	}
+	if x, ok := w.views[vi.view.Name]; ok {
+		if !x.view.same(vi.view) {
+			return nil, fmt.Errorf("cannot register view %q; a different view with the same name is already registered", v.Name)
+		}
+
+		// the view is already registered so there is nothing to do and the
+		// command is considered successful.
+		return x, nil
+	}
+	w.views[vi.view.Name] = vi
+	ref := w.getMeasureRef(vi.view.Measure.Name())
+	ref.views[vi] = struct{}{}
+	return vi, nil
+}
+
+func (w *worker) reportView(v *viewInternal, now time.Time) {
+	if !v.isSubscribed() {
+		return
+	}
+	rows := v.collectedRows()
+	_, ok := w.startTimes[v]
+	if !ok {
+		w.startTimes[v] = now
+	}
+	viewData := &Data{
+		View:  v.view,
+		Start: w.startTimes[v],
+		End:   time.Now(),
+		Rows:  rows,
+	}
+	exportersMu.Lock()
+	for e := range exporters {
+		e.ExportView(viewData)
+	}
+	exportersMu.Unlock()
+}
+
+func (w *worker) reportUsage(now time.Time) {
+	for _, v := range w.views {
+		w.reportView(v, now)
+	}
+}
diff --git a/vendor/go.opencensus.io/stats/view/worker_commands.go b/vendor/go.opencensus.io/stats/view/worker_commands.go
new file mode 100644
index 0000000..b38f26f
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/worker_commands.go
@@ -0,0 +1,183 @@
+// 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 view
+
+import (
+	"errors"
+	"fmt"
+	"strings"
+	"time"
+
+	"go.opencensus.io/exemplar"
+
+	"go.opencensus.io/stats"
+	"go.opencensus.io/stats/internal"
+	"go.opencensus.io/tag"
+)
+
+type command interface {
+	handleCommand(w *worker)
+}
+
+// getViewByNameReq is the command to get a view given its name.
+type getViewByNameReq struct {
+	name string
+	c    chan *getViewByNameResp
+}
+
+type getViewByNameResp struct {
+	v *View
+}
+
+func (cmd *getViewByNameReq) handleCommand(w *worker) {
+	v := w.views[cmd.name]
+	if v == nil {
+		cmd.c <- &getViewByNameResp{nil}
+		return
+	}
+	cmd.c <- &getViewByNameResp{v.view}
+}
+
+// registerViewReq is the command to register a view.
+type registerViewReq struct {
+	views []*View
+	err   chan error
+}
+
+func (cmd *registerViewReq) handleCommand(w *worker) {
+	var errstr []string
+	for _, view := range cmd.views {
+		vi, err := w.tryRegisterView(view)
+		if err != nil {
+			errstr = append(errstr, fmt.Sprintf("%s: %v", view.Name, err))
+			continue
+		}
+		internal.SubscriptionReporter(view.Measure.Name())
+		vi.subscribe()
+	}
+	if len(errstr) > 0 {
+		cmd.err <- errors.New(strings.Join(errstr, "\n"))
+	} else {
+		cmd.err <- nil
+	}
+}
+
+// unregisterFromViewReq is the command to unregister to a view. Has no
+// impact on the data collection for client that are pulling data from the
+// library.
+type unregisterFromViewReq struct {
+	views []string
+	done  chan struct{}
+}
+
+func (cmd *unregisterFromViewReq) handleCommand(w *worker) {
+	for _, name := range cmd.views {
+		vi, ok := w.views[name]
+		if !ok {
+			continue
+		}
+
+		// Report pending data for this view before removing it.
+		w.reportView(vi, time.Now())
+
+		vi.unsubscribe()
+		if !vi.isSubscribed() {
+			// this was the last subscription and view is not collecting anymore.
+			// The collected data can be cleared.
+			vi.clearRows()
+		}
+		delete(w.views, name)
+	}
+	cmd.done <- struct{}{}
+}
+
+// retrieveDataReq is the command to retrieve data for a view.
+type retrieveDataReq struct {
+	now time.Time
+	v   string
+	c   chan *retrieveDataResp
+}
+
+type retrieveDataResp struct {
+	rows []*Row
+	err  error
+}
+
+func (cmd *retrieveDataReq) handleCommand(w *worker) {
+	vi, ok := w.views[cmd.v]
+	if !ok {
+		cmd.c <- &retrieveDataResp{
+			nil,
+			fmt.Errorf("cannot retrieve data; view %q is not registered", cmd.v),
+		}
+		return
+	}
+
+	if !vi.isSubscribed() {
+		cmd.c <- &retrieveDataResp{
+			nil,
+			fmt.Errorf("cannot retrieve data; view %q has no subscriptions or collection is not forcibly started", cmd.v),
+		}
+		return
+	}
+	cmd.c <- &retrieveDataResp{
+		vi.collectedRows(),
+		nil,
+	}
+}
+
+// recordReq is the command to record data related to multiple measures
+// at once.
+type recordReq struct {
+	tm          *tag.Map
+	ms          []stats.Measurement
+	attachments map[string]string
+	t           time.Time
+}
+
+func (cmd *recordReq) handleCommand(w *worker) {
+	for _, m := range cmd.ms {
+		if (m == stats.Measurement{}) { // not registered
+			continue
+		}
+		ref := w.getMeasureRef(m.Measure().Name())
+		for v := range ref.views {
+			e := &exemplar.Exemplar{
+				Value:       m.Value(),
+				Timestamp:   cmd.t,
+				Attachments: cmd.attachments,
+			}
+			v.addSample(cmd.tm, e)
+		}
+	}
+}
+
+// setReportingPeriodReq is the command to modify the duration between
+// reporting the collected data to the registered clients.
+type setReportingPeriodReq struct {
+	d time.Duration
+	c chan bool
+}
+
+func (cmd *setReportingPeriodReq) handleCommand(w *worker) {
+	w.timer.Stop()
+	if cmd.d <= 0 {
+		w.timer = time.NewTicker(defaultReportingDuration)
+	} else {
+		w.timer = time.NewTicker(cmd.d)
+	}
+	cmd.c <- true
+}
diff --git a/vendor/go.opencensus.io/tag/context.go b/vendor/go.opencensus.io/tag/context.go
new file mode 100644
index 0000000..dcc13f4
--- /dev/null
+++ b/vendor/go.opencensus.io/tag/context.go
@@ -0,0 +1,67 @@
+// 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 tag
+
+import (
+	"context"
+
+	"go.opencensus.io/exemplar"
+)
+
+// FromContext returns the tag map stored in the context.
+func FromContext(ctx context.Context) *Map {
+	// The returned tag map shouldn't be mutated.
+	ts := ctx.Value(mapCtxKey)
+	if ts == nil {
+		return nil
+	}
+	return ts.(*Map)
+}
+
+// NewContext creates a new context with the given tag map.
+// To propagate a tag map to downstream methods and downstream RPCs, add a tag map
+// to the current context. NewContext will return a copy of the current context,
+// and put the tag map into the returned one.
+// If there is already a tag map in the current context, it will be replaced with m.
+func NewContext(ctx context.Context, m *Map) context.Context {
+	return context.WithValue(ctx, mapCtxKey, m)
+}
+
+type ctxKey struct{}
+
+var mapCtxKey = ctxKey{}
+
+func init() {
+	exemplar.RegisterAttachmentExtractor(extractTagsAttachments)
+}
+
+func extractTagsAttachments(ctx context.Context, a exemplar.Attachments) exemplar.Attachments {
+	m := FromContext(ctx)
+	if m == nil {
+		return a
+	}
+	if len(m.m) == 0 {
+		return a
+	}
+	if a == nil {
+		a = make(map[string]string)
+	}
+
+	for k, v := range m.m {
+		a[exemplar.KeyPrefixTag+k.Name()] = v
+	}
+	return a
+}
diff --git a/vendor/go.opencensus.io/tag/doc.go b/vendor/go.opencensus.io/tag/doc.go
new file mode 100644
index 0000000..da16b74
--- /dev/null
+++ b/vendor/go.opencensus.io/tag/doc.go
@@ -0,0 +1,26 @@
+// 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 tag contains OpenCensus tags.
+
+Tags are key-value pairs. Tags provide additional cardinality to
+the OpenCensus instrumentation data.
+
+Tags can be propagated on the wire and in the same
+process via context.Context. Encode and Decode should be
+used to represent tags into their binary propagation form.
+*/
+package tag // import "go.opencensus.io/tag"
diff --git a/vendor/go.opencensus.io/tag/key.go b/vendor/go.opencensus.io/tag/key.go
new file mode 100644
index 0000000..ebbed95
--- /dev/null
+++ b/vendor/go.opencensus.io/tag/key.go
@@ -0,0 +1,35 @@
+// 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 tag
+
+// Key represents a tag key.
+type Key struct {
+	name string
+}
+
+// NewKey creates or retrieves a string key identified by name.
+// Calling NewKey consequently with the same name returns the same key.
+func NewKey(name string) (Key, error) {
+	if !checkKeyName(name) {
+		return Key{}, errInvalidKeyName
+	}
+	return Key{name: name}, nil
+}
+
+// Name returns the name of the key.
+func (k Key) Name() string {
+	return k.name
+}
diff --git a/vendor/go.opencensus.io/tag/map.go b/vendor/go.opencensus.io/tag/map.go
new file mode 100644
index 0000000..5b72ba6
--- /dev/null
+++ b/vendor/go.opencensus.io/tag/map.go
@@ -0,0 +1,197 @@
+// 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 tag
+
+import (
+	"bytes"
+	"context"
+	"fmt"
+	"sort"
+)
+
+// Tag is a key value pair that can be propagated on wire.
+type Tag struct {
+	Key   Key
+	Value string
+}
+
+// Map is a map of tags. Use New to create a context containing
+// a new Map.
+type Map struct {
+	m map[Key]string
+}
+
+// Value returns the value for the key if a value for the key exists.
+func (m *Map) Value(k Key) (string, bool) {
+	if m == nil {
+		return "", false
+	}
+	v, ok := m.m[k]
+	return v, ok
+}
+
+func (m *Map) String() string {
+	if m == nil {
+		return "nil"
+	}
+	keys := make([]Key, 0, len(m.m))
+	for k := range m.m {
+		keys = append(keys, k)
+	}
+	sort.Slice(keys, func(i, j int) bool { return keys[i].Name() < keys[j].Name() })
+
+	var buffer bytes.Buffer
+	buffer.WriteString("{ ")
+	for _, k := range keys {
+		buffer.WriteString(fmt.Sprintf("{%v %v}", k.name, m.m[k]))
+	}
+	buffer.WriteString(" }")
+	return buffer.String()
+}
+
+func (m *Map) insert(k Key, v string) {
+	if _, ok := m.m[k]; ok {
+		return
+	}
+	m.m[k] = v
+}
+
+func (m *Map) update(k Key, v string) {
+	if _, ok := m.m[k]; ok {
+		m.m[k] = v
+	}
+}
+
+func (m *Map) upsert(k Key, v string) {
+	m.m[k] = v
+}
+
+func (m *Map) delete(k Key) {
+	delete(m.m, k)
+}
+
+func newMap() *Map {
+	return &Map{m: make(map[Key]string)}
+}
+
+// Mutator modifies a tag map.
+type Mutator interface {
+	Mutate(t *Map) (*Map, error)
+}
+
+// Insert returns a mutator that inserts a
+// value associated with k. If k already exists in the tag map,
+// mutator doesn't update the value.
+func Insert(k Key, v string) Mutator {
+	return &mutator{
+		fn: func(m *Map) (*Map, error) {
+			if !checkValue(v) {
+				return nil, errInvalidValue
+			}
+			m.insert(k, v)
+			return m, nil
+		},
+	}
+}
+
+// Update returns a mutator that updates the
+// value of the tag associated with k with v. If k doesn't
+// exists in the tag map, the mutator doesn't insert the value.
+func Update(k Key, v string) Mutator {
+	return &mutator{
+		fn: func(m *Map) (*Map, error) {
+			if !checkValue(v) {
+				return nil, errInvalidValue
+			}
+			m.update(k, v)
+			return m, nil
+		},
+	}
+}
+
+// Upsert returns a mutator that upserts the
+// value of the tag associated with k with v. It inserts the
+// value if k doesn't exist already. It mutates the value
+// if k already exists.
+func Upsert(k Key, v string) Mutator {
+	return &mutator{
+		fn: func(m *Map) (*Map, error) {
+			if !checkValue(v) {
+				return nil, errInvalidValue
+			}
+			m.upsert(k, v)
+			return m, nil
+		},
+	}
+}
+
+// Delete returns a mutator that deletes
+// the value associated with k.
+func Delete(k Key) Mutator {
+	return &mutator{
+		fn: func(m *Map) (*Map, error) {
+			m.delete(k)
+			return m, nil
+		},
+	}
+}
+
+// New returns a new context that contains a tag map
+// originated from the incoming context and modified
+// with the provided mutators.
+func New(ctx context.Context, mutator ...Mutator) (context.Context, error) {
+	m := newMap()
+	orig := FromContext(ctx)
+	if orig != nil {
+		for k, v := range orig.m {
+			if !checkKeyName(k.Name()) {
+				return ctx, fmt.Errorf("key:%q: %v", k, errInvalidKeyName)
+			}
+			if !checkValue(v) {
+				return ctx, fmt.Errorf("key:%q value:%q: %v", k.Name(), v, errInvalidValue)
+			}
+			m.insert(k, v)
+		}
+	}
+	var err error
+	for _, mod := range mutator {
+		m, err = mod.Mutate(m)
+		if err != nil {
+			return ctx, err
+		}
+	}
+	return NewContext(ctx, m), nil
+}
+
+// Do is similar to pprof.Do: a convenience for installing the tags
+// from the context as Go profiler labels. This allows you to
+// correlated runtime profiling with stats.
+//
+// It converts the key/values from the given map to Go profiler labels
+// and calls pprof.Do.
+//
+// Do is going to do nothing if your Go version is below 1.9.
+func Do(ctx context.Context, f func(ctx context.Context)) {
+	do(ctx, f)
+}
+
+type mutator struct {
+	fn func(t *Map) (*Map, error)
+}
+
+func (m *mutator) Mutate(t *Map) (*Map, error) {
+	return m.fn(t)
+}
diff --git a/vendor/go.opencensus.io/tag/map_codec.go b/vendor/go.opencensus.io/tag/map_codec.go
new file mode 100644
index 0000000..3e99895
--- /dev/null
+++ b/vendor/go.opencensus.io/tag/map_codec.go
@@ -0,0 +1,234 @@
+// 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 tag
+
+import (
+	"encoding/binary"
+	"fmt"
+)
+
+// KeyType defines the types of keys allowed. Currently only keyTypeString is
+// supported.
+type keyType byte
+
+const (
+	keyTypeString keyType = iota
+	keyTypeInt64
+	keyTypeTrue
+	keyTypeFalse
+
+	tagsVersionID = byte(0)
+)
+
+type encoderGRPC struct {
+	buf               []byte
+	writeIdx, readIdx int
+}
+
+// writeKeyString writes the fieldID '0' followed by the key string and value
+// string.
+func (eg *encoderGRPC) writeTagString(k, v string) {
+	eg.writeByte(byte(keyTypeString))
+	eg.writeStringWithVarintLen(k)
+	eg.writeStringWithVarintLen(v)
+}
+
+func (eg *encoderGRPC) writeTagUint64(k string, i uint64) {
+	eg.writeByte(byte(keyTypeInt64))
+	eg.writeStringWithVarintLen(k)
+	eg.writeUint64(i)
+}
+
+func (eg *encoderGRPC) writeTagTrue(k string) {
+	eg.writeByte(byte(keyTypeTrue))
+	eg.writeStringWithVarintLen(k)
+}
+
+func (eg *encoderGRPC) writeTagFalse(k string) {
+	eg.writeByte(byte(keyTypeFalse))
+	eg.writeStringWithVarintLen(k)
+}
+
+func (eg *encoderGRPC) writeBytesWithVarintLen(bytes []byte) {
+	length := len(bytes)
+
+	eg.growIfRequired(binary.MaxVarintLen64 + length)
+	eg.writeIdx += binary.PutUvarint(eg.buf[eg.writeIdx:], uint64(length))
+	copy(eg.buf[eg.writeIdx:], bytes)
+	eg.writeIdx += length
+}
+
+func (eg *encoderGRPC) writeStringWithVarintLen(s string) {
+	length := len(s)
+
+	eg.growIfRequired(binary.MaxVarintLen64 + length)
+	eg.writeIdx += binary.PutUvarint(eg.buf[eg.writeIdx:], uint64(length))
+	copy(eg.buf[eg.writeIdx:], s)
+	eg.writeIdx += length
+}
+
+func (eg *encoderGRPC) writeByte(v byte) {
+	eg.growIfRequired(1)
+	eg.buf[eg.writeIdx] = v
+	eg.writeIdx++
+}
+
+func (eg *encoderGRPC) writeUint32(i uint32) {
+	eg.growIfRequired(4)
+	binary.LittleEndian.PutUint32(eg.buf[eg.writeIdx:], i)
+	eg.writeIdx += 4
+}
+
+func (eg *encoderGRPC) writeUint64(i uint64) {
+	eg.growIfRequired(8)
+	binary.LittleEndian.PutUint64(eg.buf[eg.writeIdx:], i)
+	eg.writeIdx += 8
+}
+
+func (eg *encoderGRPC) readByte() byte {
+	b := eg.buf[eg.readIdx]
+	eg.readIdx++
+	return b
+}
+
+func (eg *encoderGRPC) readUint32() uint32 {
+	i := binary.LittleEndian.Uint32(eg.buf[eg.readIdx:])
+	eg.readIdx += 4
+	return i
+}
+
+func (eg *encoderGRPC) readUint64() uint64 {
+	i := binary.LittleEndian.Uint64(eg.buf[eg.readIdx:])
+	eg.readIdx += 8
+	return i
+}
+
+func (eg *encoderGRPC) readBytesWithVarintLen() ([]byte, error) {
+	if eg.readEnded() {
+		return nil, fmt.Errorf("unexpected end while readBytesWithVarintLen '%x' starting at idx '%v'", eg.buf, eg.readIdx)
+	}
+	length, valueStart := binary.Uvarint(eg.buf[eg.readIdx:])
+	if valueStart <= 0 {
+		return nil, fmt.Errorf("unexpected end while readBytesWithVarintLen '%x' starting at idx '%v'", eg.buf, eg.readIdx)
+	}
+
+	valueStart += eg.readIdx
+	valueEnd := valueStart + int(length)
+	if valueEnd > len(eg.buf) {
+		return nil, fmt.Errorf("malformed encoding: length:%v, upper:%v, maxLength:%v", length, valueEnd, len(eg.buf))
+	}
+
+	eg.readIdx = valueEnd
+	return eg.buf[valueStart:valueEnd], nil
+}
+
+func (eg *encoderGRPC) readStringWithVarintLen() (string, error) {
+	bytes, err := eg.readBytesWithVarintLen()
+	if err != nil {
+		return "", err
+	}
+	return string(bytes), nil
+}
+
+func (eg *encoderGRPC) growIfRequired(expected int) {
+	if len(eg.buf)-eg.writeIdx < expected {
+		tmp := make([]byte, 2*(len(eg.buf)+1)+expected)
+		copy(tmp, eg.buf)
+		eg.buf = tmp
+	}
+}
+
+func (eg *encoderGRPC) readEnded() bool {
+	return eg.readIdx >= len(eg.buf)
+}
+
+func (eg *encoderGRPC) bytes() []byte {
+	return eg.buf[:eg.writeIdx]
+}
+
+// Encode encodes the tag map into a []byte. It is useful to propagate
+// the tag maps on wire in binary format.
+func Encode(m *Map) []byte {
+	eg := &encoderGRPC{
+		buf: make([]byte, len(m.m)),
+	}
+	eg.writeByte(byte(tagsVersionID))
+	for k, v := range m.m {
+		eg.writeByte(byte(keyTypeString))
+		eg.writeStringWithVarintLen(k.name)
+		eg.writeBytesWithVarintLen([]byte(v))
+	}
+	return eg.bytes()
+}
+
+// Decode decodes the given []byte into a tag map.
+func Decode(bytes []byte) (*Map, error) {
+	ts := newMap()
+	err := DecodeEach(bytes, ts.upsert)
+	if err != nil {
+		// no partial failures
+		return nil, err
+	}
+	return ts, nil
+}
+
+// DecodeEach decodes the given serialized tag map, calling handler for each
+// tag key and value decoded.
+func DecodeEach(bytes []byte, fn func(key Key, val string)) error {
+	eg := &encoderGRPC{
+		buf: bytes,
+	}
+	if len(eg.buf) == 0 {
+		return nil
+	}
+
+	version := eg.readByte()
+	if version > tagsVersionID {
+		return fmt.Errorf("cannot decode: unsupported version: %q; supports only up to: %q", version, tagsVersionID)
+	}
+
+	for !eg.readEnded() {
+		typ := keyType(eg.readByte())
+
+		if typ != keyTypeString {
+			return fmt.Errorf("cannot decode: invalid key type: %q", typ)
+		}
+
+		k, err := eg.readBytesWithVarintLen()
+		if err != nil {
+			return err
+		}
+
+		v, err := eg.readBytesWithVarintLen()
+		if err != nil {
+			return err
+		}
+
+		key, err := NewKey(string(k))
+		if err != nil {
+			return err
+		}
+		val := string(v)
+		if !checkValue(val) {
+			return errInvalidValue
+		}
+		fn(key, val)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
diff --git a/vendor/go.opencensus.io/tag/profile_19.go b/vendor/go.opencensus.io/tag/profile_19.go
new file mode 100644
index 0000000..f81cd0b
--- /dev/null
+++ b/vendor/go.opencensus.io/tag/profile_19.go
@@ -0,0 +1,31 @@
+// Copyright 2018, 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.
+
+// +build go1.9
+
+package tag
+
+import (
+	"context"
+	"runtime/pprof"
+)
+
+func do(ctx context.Context, f func(ctx context.Context)) {
+	m := FromContext(ctx)
+	keyvals := make([]string, 0, 2*len(m.m))
+	for k, v := range m.m {
+		keyvals = append(keyvals, k.Name(), v)
+	}
+	pprof.Do(ctx, pprof.Labels(keyvals...), f)
+}
diff --git a/vendor/go.opencensus.io/tag/profile_not19.go b/vendor/go.opencensus.io/tag/profile_not19.go
new file mode 100644
index 0000000..83adbce
--- /dev/null
+++ b/vendor/go.opencensus.io/tag/profile_not19.go
@@ -0,0 +1,23 @@
+// Copyright 2018, 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.
+
+// +build !go1.9
+
+package tag
+
+import "context"
+
+func do(ctx context.Context, f func(ctx context.Context)) {
+	f(ctx)
+}
diff --git a/vendor/go.opencensus.io/tag/validate.go b/vendor/go.opencensus.io/tag/validate.go
new file mode 100644
index 0000000..0939fc6
--- /dev/null
+++ b/vendor/go.opencensus.io/tag/validate.go
@@ -0,0 +1,56 @@
+// 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 tag
+
+import "errors"
+
+const (
+	maxKeyLength = 255
+
+	// valid are restricted to US-ASCII subset (range 0x20 (' ') to 0x7e ('~')).
+	validKeyValueMin = 32
+	validKeyValueMax = 126
+)
+
+var (
+	errInvalidKeyName = errors.New("invalid key name: only ASCII characters accepted; max length must be 255 characters")
+	errInvalidValue   = errors.New("invalid value: only ASCII characters accepted; max length must be 255 characters")
+)
+
+func checkKeyName(name string) bool {
+	if len(name) == 0 {
+		return false
+	}
+	if len(name) > maxKeyLength {
+		return false
+	}
+	return isASCII(name)
+}
+
+func isASCII(s string) bool {
+	for _, c := range s {
+		if (c < validKeyValueMin) || (c > validKeyValueMax) {
+			return false
+		}
+	}
+	return true
+}
+
+func checkValue(v string) bool {
+	if len(v) > maxKeyLength {
+		return false
+	}
+	return isASCII(v)
+}
diff --git a/vendor/go.opencensus.io/trace/basetypes.go b/vendor/go.opencensus.io/trace/basetypes.go
new file mode 100644
index 0000000..01f0f90
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/basetypes.go
@@ -0,0 +1,114 @@
+// 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 trace
+
+import (
+	"fmt"
+	"time"
+)
+
+type (
+	// TraceID is a 16-byte identifier for a set of spans.
+	TraceID [16]byte
+
+	// SpanID is an 8-byte identifier for a single span.
+	SpanID [8]byte
+)
+
+func (t TraceID) String() string {
+	return fmt.Sprintf("%02x", t[:])
+}
+
+func (s SpanID) String() string {
+	return fmt.Sprintf("%02x", s[:])
+}
+
+// Annotation represents a text annotation with a set of attributes and a timestamp.
+type Annotation struct {
+	Time       time.Time
+	Message    string
+	Attributes map[string]interface{}
+}
+
+// Attribute represents a key-value pair on a span, link or annotation.
+// Construct with one of: BoolAttribute, Int64Attribute, or StringAttribute.
+type Attribute struct {
+	key   string
+	value interface{}
+}
+
+// BoolAttribute returns a bool-valued attribute.
+func BoolAttribute(key string, value bool) Attribute {
+	return Attribute{key: key, value: value}
+}
+
+// Int64Attribute returns an int64-valued attribute.
+func Int64Attribute(key string, value int64) Attribute {
+	return Attribute{key: key, value: value}
+}
+
+// StringAttribute returns a string-valued attribute.
+func StringAttribute(key string, value string) Attribute {
+	return Attribute{key: key, value: value}
+}
+
+// LinkType specifies the relationship between the span that had the link
+// added, and the linked span.
+type LinkType int32
+
+// LinkType values.
+const (
+	LinkTypeUnspecified LinkType = iota // The relationship of the two spans is unknown.
+	LinkTypeChild                       // The current span is a child of the linked span.
+	LinkTypeParent                      // The current span is the parent of the linked span.
+)
+
+// Link represents a reference from one span to another span.
+type Link struct {
+	TraceID TraceID
+	SpanID  SpanID
+	Type    LinkType
+	// Attributes is a set of attributes on the link.
+	Attributes map[string]interface{}
+}
+
+// MessageEventType specifies the type of message event.
+type MessageEventType int32
+
+// MessageEventType values.
+const (
+	MessageEventTypeUnspecified MessageEventType = iota // Unknown event type.
+	MessageEventTypeSent                                // Indicates a sent RPC message.
+	MessageEventTypeRecv                                // Indicates a received RPC message.
+)
+
+// MessageEvent represents an event describing a message sent or received on the network.
+type MessageEvent struct {
+	Time                 time.Time
+	EventType            MessageEventType
+	MessageID            int64
+	UncompressedByteSize int64
+	CompressedByteSize   int64
+}
+
+// Status is the status of a Span.
+type Status struct {
+	// Code is a status code.  Zero indicates success.
+	//
+	// If Code will be propagated to Google APIs, it ideally should be a value from
+	// https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto .
+	Code    int32
+	Message string
+}
diff --git a/vendor/go.opencensus.io/trace/config.go b/vendor/go.opencensus.io/trace/config.go
new file mode 100644
index 0000000..0816892
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/config.go
@@ -0,0 +1,48 @@
+// Copyright 2018, 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 trace
+
+import (
+	"sync"
+
+	"go.opencensus.io/trace/internal"
+)
+
+// Config represents the global tracing configuration.
+type Config struct {
+	// DefaultSampler is the default sampler used when creating new spans.
+	DefaultSampler Sampler
+
+	// IDGenerator is for internal use only.
+	IDGenerator internal.IDGenerator
+}
+
+var configWriteMu sync.Mutex
+
+// ApplyConfig applies changes to the global tracing configuration.
+//
+// Fields not provided in the given config are going to be preserved.
+func ApplyConfig(cfg Config) {
+	configWriteMu.Lock()
+	defer configWriteMu.Unlock()
+	c := *config.Load().(*Config)
+	if cfg.DefaultSampler != nil {
+		c.DefaultSampler = cfg.DefaultSampler
+	}
+	if cfg.IDGenerator != nil {
+		c.IDGenerator = cfg.IDGenerator
+	}
+	config.Store(&c)
+}
diff --git a/vendor/go.opencensus.io/trace/doc.go b/vendor/go.opencensus.io/trace/doc.go
new file mode 100644
index 0000000..04b1ee4
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/doc.go
@@ -0,0 +1,53 @@
+// 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 trace contains support for OpenCensus distributed tracing.
+
+The following assumes a basic familiarity with OpenCensus concepts.
+See http://opencensus.io
+
+
+Exporting Traces
+
+To export collected tracing data, register at least one exporter. You can use
+one of the provided exporters or write your own.
+
+    trace.RegisterExporter(exporter)
+
+By default, traces will be sampled relatively rarely. To change the sampling
+frequency for your entire program, call ApplyConfig. Use a ProbabilitySampler
+to sample a subset of traces, or use AlwaysSample to collect a trace on every run:
+
+    trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
+
+Be careful about using trace.AlwaysSample in a production application with
+significant traffic: a new trace will be started and exported for every request.
+
+Adding Spans to a Trace
+
+A trace consists of a tree of spans. In Go, the current span is carried in a
+context.Context.
+
+It is common to want to capture all the activity of a function call in a span. For
+this to work, the function must take a context.Context as a parameter. Add these two
+lines to the top of the function:
+
+    ctx, span := trace.StartSpan(ctx, "example.com/Run")
+    defer span.End()
+
+StartSpan will create a new top-level span if the context
+doesn't contain another span, otherwise it will create a child span.
+*/
+package trace // import "go.opencensus.io/trace"
diff --git a/vendor/go.opencensus.io/trace/exemplar.go b/vendor/go.opencensus.io/trace/exemplar.go
new file mode 100644
index 0000000..416d805
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/exemplar.go
@@ -0,0 +1,43 @@
+// Copyright 2018, 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 trace
+
+import (
+	"context"
+	"encoding/hex"
+
+	"go.opencensus.io/exemplar"
+)
+
+func init() {
+	exemplar.RegisterAttachmentExtractor(attachSpanContext)
+}
+
+func attachSpanContext(ctx context.Context, a exemplar.Attachments) exemplar.Attachments {
+	span := FromContext(ctx)
+	if span == nil {
+		return a
+	}
+	sc := span.SpanContext()
+	if !sc.IsSampled() {
+		return a
+	}
+	if a == nil {
+		a = make(exemplar.Attachments)
+	}
+	a[exemplar.KeyTraceID] = hex.EncodeToString(sc.TraceID[:])
+	a[exemplar.KeySpanID] = hex.EncodeToString(sc.SpanID[:])
+	return a
+}
diff --git a/vendor/go.opencensus.io/trace/export.go b/vendor/go.opencensus.io/trace/export.go
new file mode 100644
index 0000000..77a8c73
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/export.go
@@ -0,0 +1,90 @@
+// 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 trace
+
+import (
+	"sync"
+	"sync/atomic"
+	"time"
+)
+
+// Exporter is a type for functions that receive sampled trace spans.
+//
+// The ExportSpan method should be safe for concurrent use and should return
+// quickly; if an Exporter takes a significant amount of time to process a
+// SpanData, that work should be done on another goroutine.
+//
+// The SpanData should not be modified, but a pointer to it can be kept.
+type Exporter interface {
+	ExportSpan(s *SpanData)
+}
+
+type exportersMap map[Exporter]struct{}
+
+var (
+	exporterMu sync.Mutex
+	exporters  atomic.Value
+)
+
+// RegisterExporter adds to the list of Exporters that will receive sampled
+// trace spans.
+//
+// Binaries can register exporters, libraries shouldn't register exporters.
+func RegisterExporter(e Exporter) {
+	exporterMu.Lock()
+	new := make(exportersMap)
+	if old, ok := exporters.Load().(exportersMap); ok {
+		for k, v := range old {
+			new[k] = v
+		}
+	}
+	new[e] = struct{}{}
+	exporters.Store(new)
+	exporterMu.Unlock()
+}
+
+// UnregisterExporter removes from the list of Exporters the Exporter that was
+// registered with the given name.
+func UnregisterExporter(e Exporter) {
+	exporterMu.Lock()
+	new := make(exportersMap)
+	if old, ok := exporters.Load().(exportersMap); ok {
+		for k, v := range old {
+			new[k] = v
+		}
+	}
+	delete(new, e)
+	exporters.Store(new)
+	exporterMu.Unlock()
+}
+
+// SpanData contains all the information collected by a Span.
+type SpanData struct {
+	SpanContext
+	ParentSpanID SpanID
+	SpanKind     int
+	Name         string
+	StartTime    time.Time
+	// The wall clock time of EndTime will be adjusted to always be offset
+	// from StartTime by the duration of the span.
+	EndTime time.Time
+	// The values of Attributes each have type string, bool, or int64.
+	Attributes    map[string]interface{}
+	Annotations   []Annotation
+	MessageEvents []MessageEvent
+	Status
+	Links           []Link
+	HasRemoteParent bool
+}
diff --git a/vendor/go.opencensus.io/trace/internal/internal.go b/vendor/go.opencensus.io/trace/internal/internal.go
new file mode 100644
index 0000000..1c8b9b3
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/internal/internal.go
@@ -0,0 +1,21 @@
+// Copyright 2018, 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 internal provides trace internals.
+package internal
+
+type IDGenerator interface {
+	NewTraceID() [16]byte
+	NewSpanID() [8]byte
+}
diff --git a/vendor/go.opencensus.io/trace/propagation/propagation.go b/vendor/go.opencensus.io/trace/propagation/propagation.go
new file mode 100644
index 0000000..1eb190a
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/propagation/propagation.go
@@ -0,0 +1,108 @@
+// 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 propagation implements the binary trace context format.
+package propagation // import "go.opencensus.io/trace/propagation"
+
+// TODO: link to external spec document.
+
+// BinaryFormat format:
+//
+// Binary value: <version_id><version_format>
+// version_id: 1 byte representing the version id.
+//
+// For version_id = 0:
+//
+// version_format: <field><field>
+// field_format: <field_id><field_format>
+//
+// Fields:
+//
+// TraceId: (field_id = 0, len = 16, default = "0000000000000000") - 16-byte array representing the trace_id.
+// SpanId: (field_id = 1, len = 8, default = "00000000") - 8-byte array representing the span_id.
+// TraceOptions: (field_id = 2, len = 1, default = "0") - 1-byte array representing the trace_options.
+//
+// Fields MUST be encoded using the field id order (smaller to higher).
+//
+// Valid value example:
+//
+// {0, 0, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 1, 97,
+// 98, 99, 100, 101, 102, 103, 104, 2, 1}
+//
+// version_id = 0;
+// trace_id = {64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79}
+// span_id = {97, 98, 99, 100, 101, 102, 103, 104};
+// trace_options = {1};
+
+import (
+	"net/http"
+
+	"go.opencensus.io/trace"
+)
+
+// Binary returns the binary format representation of a SpanContext.
+//
+// If sc is the zero value, Binary returns nil.
+func Binary(sc trace.SpanContext) []byte {
+	if sc == (trace.SpanContext{}) {
+		return nil
+	}
+	var b [29]byte
+	copy(b[2:18], sc.TraceID[:])
+	b[18] = 1
+	copy(b[19:27], sc.SpanID[:])
+	b[27] = 2
+	b[28] = uint8(sc.TraceOptions)
+	return b[:]
+}
+
+// FromBinary returns the SpanContext represented by b.
+//
+// If b has an unsupported version ID or contains no TraceID, FromBinary
+// returns with ok==false.
+func FromBinary(b []byte) (sc trace.SpanContext, ok bool) {
+	if len(b) == 0 || b[0] != 0 {
+		return trace.SpanContext{}, false
+	}
+	b = b[1:]
+	if len(b) >= 17 && b[0] == 0 {
+		copy(sc.TraceID[:], b[1:17])
+		b = b[17:]
+	} else {
+		return trace.SpanContext{}, false
+	}
+	if len(b) >= 9 && b[0] == 1 {
+		copy(sc.SpanID[:], b[1:9])
+		b = b[9:]
+	}
+	if len(b) >= 2 && b[0] == 2 {
+		sc.TraceOptions = trace.TraceOptions(b[1])
+	}
+	return sc, true
+}
+
+// HTTPFormat implementations propagate span contexts
+// in HTTP requests.
+//
+// SpanContextFromRequest extracts a span context from incoming
+// requests.
+//
+// SpanContextToRequest modifies the given request to include the given
+// span context.
+type HTTPFormat interface {
+	SpanContextFromRequest(req *http.Request) (sc trace.SpanContext, ok bool)
+	SpanContextToRequest(sc trace.SpanContext, req *http.Request)
+}
+
+// TODO(jbd): Find a more representative but short name for HTTPFormat.
diff --git a/vendor/go.opencensus.io/trace/sampling.go b/vendor/go.opencensus.io/trace/sampling.go
new file mode 100644
index 0000000..71c10f9
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/sampling.go
@@ -0,0 +1,75 @@
+// 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 trace
+
+import (
+	"encoding/binary"
+)
+
+const defaultSamplingProbability = 1e-4
+
+// Sampler decides whether a trace should be sampled and exported.
+type Sampler func(SamplingParameters) SamplingDecision
+
+// SamplingParameters contains the values passed to a Sampler.
+type SamplingParameters struct {
+	ParentContext   SpanContext
+	TraceID         TraceID
+	SpanID          SpanID
+	Name            string
+	HasRemoteParent bool
+}
+
+// SamplingDecision is the value returned by a Sampler.
+type SamplingDecision struct {
+	Sample bool
+}
+
+// ProbabilitySampler returns a Sampler that samples a given fraction of traces.
+//
+// It also samples spans whose parents are sampled.
+func ProbabilitySampler(fraction float64) Sampler {
+	if !(fraction >= 0) {
+		fraction = 0
+	} else if fraction >= 1 {
+		return AlwaysSample()
+	}
+
+	traceIDUpperBound := uint64(fraction * (1 << 63))
+	return Sampler(func(p SamplingParameters) SamplingDecision {
+		if p.ParentContext.IsSampled() {
+			return SamplingDecision{Sample: true}
+		}
+		x := binary.BigEndian.Uint64(p.TraceID[0:8]) >> 1
+		return SamplingDecision{Sample: x < traceIDUpperBound}
+	})
+}
+
+// AlwaysSample returns a Sampler that samples every trace.
+// Be careful about using this sampler in a production application with
+// significant traffic: a new trace will be started and exported for every
+// request.
+func AlwaysSample() Sampler {
+	return func(p SamplingParameters) SamplingDecision {
+		return SamplingDecision{Sample: true}
+	}
+}
+
+// NeverSample returns a Sampler that samples no traces.
+func NeverSample() Sampler {
+	return func(p SamplingParameters) SamplingDecision {
+		return SamplingDecision{Sample: false}
+	}
+}
diff --git a/vendor/go.opencensus.io/trace/spanbucket.go b/vendor/go.opencensus.io/trace/spanbucket.go
new file mode 100644
index 0000000..fbabad3
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/spanbucket.go
@@ -0,0 +1,130 @@
+// 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 trace
+
+import (
+	"time"
+)
+
+// samplePeriod is the minimum time between accepting spans in a single bucket.
+const samplePeriod = time.Second
+
+// defaultLatencies contains the default latency bucket bounds.
+// TODO: consider defaults, make configurable
+var defaultLatencies = [...]time.Duration{
+	10 * time.Microsecond,
+	100 * time.Microsecond,
+	time.Millisecond,
+	10 * time.Millisecond,
+	100 * time.Millisecond,
+	time.Second,
+	10 * time.Second,
+	time.Minute,
+}
+
+// bucket is a container for a set of spans for a particular error code or latency range.
+type bucket struct {
+	nextTime  time.Time   // next time we can accept a span
+	buffer    []*SpanData // circular buffer of spans
+	nextIndex int         // location next SpanData should be placed in buffer
+	overflow  bool        // whether the circular buffer has wrapped around
+}
+
+func makeBucket(bufferSize int) bucket {
+	return bucket{
+		buffer: make([]*SpanData, bufferSize),
+	}
+}
+
+// add adds a span to the bucket, if nextTime has been reached.
+func (b *bucket) add(s *SpanData) {
+	if s.EndTime.Before(b.nextTime) {
+		return
+	}
+	if len(b.buffer) == 0 {
+		return
+	}
+	b.nextTime = s.EndTime.Add(samplePeriod)
+	b.buffer[b.nextIndex] = s
+	b.nextIndex++
+	if b.nextIndex == len(b.buffer) {
+		b.nextIndex = 0
+		b.overflow = true
+	}
+}
+
+// size returns the number of spans in the bucket.
+func (b *bucket) size() int {
+	if b.overflow {
+		return len(b.buffer)
+	}
+	return b.nextIndex
+}
+
+// span returns the ith span in the bucket.
+func (b *bucket) span(i int) *SpanData {
+	if !b.overflow {
+		return b.buffer[i]
+	}
+	if i < len(b.buffer)-b.nextIndex {
+		return b.buffer[b.nextIndex+i]
+	}
+	return b.buffer[b.nextIndex+i-len(b.buffer)]
+}
+
+// resize changes the size of the bucket to n, keeping up to n existing spans.
+func (b *bucket) resize(n int) {
+	cur := b.size()
+	newBuffer := make([]*SpanData, n)
+	if cur < n {
+		for i := 0; i < cur; i++ {
+			newBuffer[i] = b.span(i)
+		}
+		b.buffer = newBuffer
+		b.nextIndex = cur
+		b.overflow = false
+		return
+	}
+	for i := 0; i < n; i++ {
+		newBuffer[i] = b.span(i + cur - n)
+	}
+	b.buffer = newBuffer
+	b.nextIndex = 0
+	b.overflow = true
+}
+
+// latencyBucket returns the appropriate bucket number for a given latency.
+func latencyBucket(latency time.Duration) int {
+	i := 0
+	for i < len(defaultLatencies) && latency >= defaultLatencies[i] {
+		i++
+	}
+	return i
+}
+
+// latencyBucketBounds returns the lower and upper bounds for a latency bucket
+// number.
+//
+// The lower bound is inclusive, the upper bound is exclusive (except for the
+// last bucket.)
+func latencyBucketBounds(index int) (lower time.Duration, upper time.Duration) {
+	if index == 0 {
+		return 0, defaultLatencies[index]
+	}
+	if index == len(defaultLatencies) {
+		return defaultLatencies[index-1], 1<<63 - 1
+	}
+	return defaultLatencies[index-1], defaultLatencies[index]
+}
diff --git a/vendor/go.opencensus.io/trace/spanstore.go b/vendor/go.opencensus.io/trace/spanstore.go
new file mode 100644
index 0000000..c442d99
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/spanstore.go
@@ -0,0 +1,306 @@
+// 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 trace
+
+import (
+	"sync"
+	"time"
+
+	"go.opencensus.io/internal"
+)
+
+const (
+	maxBucketSize     = 100000
+	defaultBucketSize = 10
+)
+
+var (
+	ssmu       sync.RWMutex // protects spanStores
+	spanStores = make(map[string]*spanStore)
+)
+
+// This exists purely to avoid exposing internal methods used by z-Pages externally.
+type internalOnly struct{}
+
+func init() {
+	//TODO(#412): remove
+	internal.Trace = &internalOnly{}
+}
+
+// ReportActiveSpans returns the active spans for the given name.
+func (i internalOnly) ReportActiveSpans(name string) []*SpanData {
+	s := spanStoreForName(name)
+	if s == nil {
+		return nil
+	}
+	var out []*SpanData
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	for span := range s.active {
+		out = append(out, span.makeSpanData())
+	}
+	return out
+}
+
+// ReportSpansByError returns a sample of error spans.
+//
+// If code is nonzero, only spans with that status code are returned.
+func (i internalOnly) ReportSpansByError(name string, code int32) []*SpanData {
+	s := spanStoreForName(name)
+	if s == nil {
+		return nil
+	}
+	var out []*SpanData
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	if code != 0 {
+		if b, ok := s.errors[code]; ok {
+			for _, sd := range b.buffer {
+				if sd == nil {
+					break
+				}
+				out = append(out, sd)
+			}
+		}
+	} else {
+		for _, b := range s.errors {
+			for _, sd := range b.buffer {
+				if sd == nil {
+					break
+				}
+				out = append(out, sd)
+			}
+		}
+	}
+	return out
+}
+
+// ConfigureBucketSizes sets the number of spans to keep per latency and error
+// bucket for different span names.
+func (i internalOnly) ConfigureBucketSizes(bcs []internal.BucketConfiguration) {
+	for _, bc := range bcs {
+		latencyBucketSize := bc.MaxRequestsSucceeded
+		if latencyBucketSize < 0 {
+			latencyBucketSize = 0
+		}
+		if latencyBucketSize > maxBucketSize {
+			latencyBucketSize = maxBucketSize
+		}
+		errorBucketSize := bc.MaxRequestsErrors
+		if errorBucketSize < 0 {
+			errorBucketSize = 0
+		}
+		if errorBucketSize > maxBucketSize {
+			errorBucketSize = maxBucketSize
+		}
+		spanStoreSetSize(bc.Name, latencyBucketSize, errorBucketSize)
+	}
+}
+
+// ReportSpansPerMethod returns a summary of what spans are being stored for each span name.
+func (i internalOnly) ReportSpansPerMethod() map[string]internal.PerMethodSummary {
+	out := make(map[string]internal.PerMethodSummary)
+	ssmu.RLock()
+	defer ssmu.RUnlock()
+	for name, s := range spanStores {
+		s.mu.Lock()
+		p := internal.PerMethodSummary{
+			Active: len(s.active),
+		}
+		for code, b := range s.errors {
+			p.ErrorBuckets = append(p.ErrorBuckets, internal.ErrorBucketSummary{
+				ErrorCode: code,
+				Size:      b.size(),
+			})
+		}
+		for i, b := range s.latency {
+			min, max := latencyBucketBounds(i)
+			p.LatencyBuckets = append(p.LatencyBuckets, internal.LatencyBucketSummary{
+				MinLatency: min,
+				MaxLatency: max,
+				Size:       b.size(),
+			})
+		}
+		s.mu.Unlock()
+		out[name] = p
+	}
+	return out
+}
+
+// ReportSpansByLatency returns a sample of successful spans.
+//
+// minLatency is the minimum latency of spans to be returned.
+// maxLatency, if nonzero, is the maximum latency of spans to be returned.
+func (i internalOnly) ReportSpansByLatency(name string, minLatency, maxLatency time.Duration) []*SpanData {
+	s := spanStoreForName(name)
+	if s == nil {
+		return nil
+	}
+	var out []*SpanData
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	for i, b := range s.latency {
+		min, max := latencyBucketBounds(i)
+		if i+1 != len(s.latency) && max <= minLatency {
+			continue
+		}
+		if maxLatency != 0 && maxLatency < min {
+			continue
+		}
+		for _, sd := range b.buffer {
+			if sd == nil {
+				break
+			}
+			if minLatency != 0 || maxLatency != 0 {
+				d := sd.EndTime.Sub(sd.StartTime)
+				if d < minLatency {
+					continue
+				}
+				if maxLatency != 0 && d > maxLatency {
+					continue
+				}
+			}
+			out = append(out, sd)
+		}
+	}
+	return out
+}
+
+// spanStore keeps track of spans stored for a particular span name.
+//
+// It contains all active spans; a sample of spans for failed requests,
+// categorized by error code; and a sample of spans for successful requests,
+// bucketed by latency.
+type spanStore struct {
+	mu                     sync.Mutex // protects everything below.
+	active                 map[*Span]struct{}
+	errors                 map[int32]*bucket
+	latency                []bucket
+	maxSpansPerErrorBucket int
+}
+
+// newSpanStore creates a span store.
+func newSpanStore(name string, latencyBucketSize int, errorBucketSize int) *spanStore {
+	s := &spanStore{
+		active:                 make(map[*Span]struct{}),
+		latency:                make([]bucket, len(defaultLatencies)+1),
+		maxSpansPerErrorBucket: errorBucketSize,
+	}
+	for i := range s.latency {
+		s.latency[i] = makeBucket(latencyBucketSize)
+	}
+	return s
+}
+
+// spanStoreForName returns the spanStore for the given name.
+//
+// It returns nil if it doesn't exist.
+func spanStoreForName(name string) *spanStore {
+	var s *spanStore
+	ssmu.RLock()
+	s, _ = spanStores[name]
+	ssmu.RUnlock()
+	return s
+}
+
+// spanStoreForNameCreateIfNew returns the spanStore for the given name.
+//
+// It creates it if it didn't exist.
+func spanStoreForNameCreateIfNew(name string) *spanStore {
+	ssmu.RLock()
+	s, ok := spanStores[name]
+	ssmu.RUnlock()
+	if ok {
+		return s
+	}
+	ssmu.Lock()
+	defer ssmu.Unlock()
+	s, ok = spanStores[name]
+	if ok {
+		return s
+	}
+	s = newSpanStore(name, defaultBucketSize, defaultBucketSize)
+	spanStores[name] = s
+	return s
+}
+
+// spanStoreSetSize resizes the spanStore for the given name.
+//
+// It creates it if it didn't exist.
+func spanStoreSetSize(name string, latencyBucketSize int, errorBucketSize int) {
+	ssmu.RLock()
+	s, ok := spanStores[name]
+	ssmu.RUnlock()
+	if ok {
+		s.resize(latencyBucketSize, errorBucketSize)
+		return
+	}
+	ssmu.Lock()
+	defer ssmu.Unlock()
+	s, ok = spanStores[name]
+	if ok {
+		s.resize(latencyBucketSize, errorBucketSize)
+		return
+	}
+	s = newSpanStore(name, latencyBucketSize, errorBucketSize)
+	spanStores[name] = s
+}
+
+func (s *spanStore) resize(latencyBucketSize int, errorBucketSize int) {
+	s.mu.Lock()
+	for i := range s.latency {
+		s.latency[i].resize(latencyBucketSize)
+	}
+	for _, b := range s.errors {
+		b.resize(errorBucketSize)
+	}
+	s.maxSpansPerErrorBucket = errorBucketSize
+	s.mu.Unlock()
+}
+
+// add adds a span to the active bucket of the spanStore.
+func (s *spanStore) add(span *Span) {
+	s.mu.Lock()
+	s.active[span] = struct{}{}
+	s.mu.Unlock()
+}
+
+// finished removes a span from the active set, and adds a corresponding
+// SpanData to a latency or error bucket.
+func (s *spanStore) finished(span *Span, sd *SpanData) {
+	latency := sd.EndTime.Sub(sd.StartTime)
+	if latency < 0 {
+		latency = 0
+	}
+	code := sd.Status.Code
+
+	s.mu.Lock()
+	delete(s.active, span)
+	if code == 0 {
+		s.latency[latencyBucket(latency)].add(sd)
+	} else {
+		if s.errors == nil {
+			s.errors = make(map[int32]*bucket)
+		}
+		if b := s.errors[code]; b != nil {
+			b.add(sd)
+		} else {
+			b := makeBucket(s.maxSpansPerErrorBucket)
+			s.errors[code] = &b
+			b.add(sd)
+		}
+	}
+	s.mu.Unlock()
+}
diff --git a/vendor/go.opencensus.io/trace/status_codes.go b/vendor/go.opencensus.io/trace/status_codes.go
new file mode 100644
index 0000000..ec60eff
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/status_codes.go
@@ -0,0 +1,37 @@
+// Copyright 2018, 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 trace
+
+// Status codes for use with Span.SetStatus. These correspond to the status
+// codes used by gRPC defined here: https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto
+const (
+	StatusCodeOK                 = 0
+	StatusCodeCancelled          = 1
+	StatusCodeUnknown            = 2
+	StatusCodeInvalidArgument    = 3
+	StatusCodeDeadlineExceeded   = 4
+	StatusCodeNotFound           = 5
+	StatusCodeAlreadyExists      = 6
+	StatusCodePermissionDenied   = 7
+	StatusCodeResourceExhausted  = 8
+	StatusCodeFailedPrecondition = 9
+	StatusCodeAborted            = 10
+	StatusCodeOutOfRange         = 11
+	StatusCodeUnimplemented      = 12
+	StatusCodeInternal           = 13
+	StatusCodeUnavailable        = 14
+	StatusCodeDataLoss           = 15
+	StatusCodeUnauthenticated    = 16
+)
diff --git a/vendor/go.opencensus.io/trace/trace.go b/vendor/go.opencensus.io/trace/trace.go
new file mode 100644
index 0000000..9e5e5f0
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/trace.go
@@ -0,0 +1,516 @@
+// 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 trace
+
+import (
+	"context"
+	crand "crypto/rand"
+	"encoding/binary"
+	"fmt"
+	"math/rand"
+	"sync"
+	"sync/atomic"
+	"time"
+
+	"go.opencensus.io/internal"
+	"go.opencensus.io/trace/tracestate"
+)
+
+// Span represents a span of a trace.  It has an associated SpanContext, and
+// stores data accumulated while the span is active.
+//
+// Ideally users should interact with Spans by calling the functions in this
+// package that take a Context parameter.
+type Span struct {
+	// data contains information recorded about the span.
+	//
+	// It will be non-nil if we are exporting the span or recording events for it.
+	// Otherwise, data is nil, and the Span is simply a carrier for the
+	// SpanContext, so that the trace ID is propagated.
+	data        *SpanData
+	mu          sync.Mutex // protects the contents of *data (but not the pointer value.)
+	spanContext SpanContext
+	// spanStore is the spanStore this span belongs to, if any, otherwise it is nil.
+	*spanStore
+	endOnce sync.Once
+
+	executionTracerTaskEnd func() // ends the execution tracer span
+}
+
+// IsRecordingEvents returns true if events are being recorded for this span.
+// Use this check to avoid computing expensive annotations when they will never
+// be used.
+func (s *Span) IsRecordingEvents() bool {
+	if s == nil {
+		return false
+	}
+	return s.data != nil
+}
+
+// TraceOptions contains options associated with a trace span.
+type TraceOptions uint32
+
+// IsSampled returns true if the span will be exported.
+func (sc SpanContext) IsSampled() bool {
+	return sc.TraceOptions.IsSampled()
+}
+
+// setIsSampled sets the TraceOptions bit that determines whether the span will be exported.
+func (sc *SpanContext) setIsSampled(sampled bool) {
+	if sampled {
+		sc.TraceOptions |= 1
+	} else {
+		sc.TraceOptions &= ^TraceOptions(1)
+	}
+}
+
+// IsSampled returns true if the span will be exported.
+func (t TraceOptions) IsSampled() bool {
+	return t&1 == 1
+}
+
+// SpanContext contains the state that must propagate across process boundaries.
+//
+// SpanContext is not an implementation of context.Context.
+// TODO: add reference to external Census docs for SpanContext.
+type SpanContext struct {
+	TraceID      TraceID
+	SpanID       SpanID
+	TraceOptions TraceOptions
+	Tracestate   *tracestate.Tracestate
+}
+
+type contextKey struct{}
+
+// FromContext returns the Span stored in a context, or nil if there isn't one.
+func FromContext(ctx context.Context) *Span {
+	s, _ := ctx.Value(contextKey{}).(*Span)
+	return s
+}
+
+// NewContext returns a new context with the given Span attached.
+func NewContext(parent context.Context, s *Span) context.Context {
+	return context.WithValue(parent, contextKey{}, s)
+}
+
+// All available span kinds. Span kind must be either one of these values.
+const (
+	SpanKindUnspecified = iota
+	SpanKindServer
+	SpanKindClient
+)
+
+// StartOptions contains options concerning how a span is started.
+type StartOptions struct {
+	// Sampler to consult for this Span. If provided, it is always consulted.
+	//
+	// If not provided, then the behavior differs based on whether
+	// the parent of this Span is remote, local, or there is no parent.
+	// In the case of a remote parent or no parent, the
+	// default sampler (see Config) will be consulted. Otherwise,
+	// when there is a non-remote parent, no new sampling decision will be made:
+	// we will preserve the sampling of the parent.
+	Sampler Sampler
+
+	// SpanKind represents the kind of a span. If none is set,
+	// SpanKindUnspecified is used.
+	SpanKind int
+}
+
+// StartOption apply changes to StartOptions.
+type StartOption func(*StartOptions)
+
+// WithSpanKind makes new spans to be created with the given kind.
+func WithSpanKind(spanKind int) StartOption {
+	return func(o *StartOptions) {
+		o.SpanKind = spanKind
+	}
+}
+
+// WithSampler makes new spans to be be created with a custom sampler.
+// Otherwise, the global sampler is used.
+func WithSampler(sampler Sampler) StartOption {
+	return func(o *StartOptions) {
+		o.Sampler = sampler
+	}
+}
+
+// StartSpan starts a new child span of the current span in the context. If
+// there is no span in the context, creates a new trace and span.
+//
+// Returned context contains the newly created span. You can use it to
+// propagate the returned span in process.
+func StartSpan(ctx context.Context, name string, o ...StartOption) (context.Context, *Span) {
+	var opts StartOptions
+	var parent SpanContext
+	if p := FromContext(ctx); p != nil {
+		parent = p.spanContext
+	}
+	for _, op := range o {
+		op(&opts)
+	}
+	span := startSpanInternal(name, parent != SpanContext{}, parent, false, opts)
+
+	ctx, end := startExecutionTracerTask(ctx, name)
+	span.executionTracerTaskEnd = end
+	return NewContext(ctx, span), span
+}
+
+// StartSpanWithRemoteParent starts a new child span of the span from the given parent.
+//
+// If the incoming context contains a parent, it ignores. StartSpanWithRemoteParent is
+// preferred for cases where the parent is propagated via an incoming request.
+//
+// Returned context contains the newly created span. You can use it to
+// propagate the returned span in process.
+func StartSpanWithRemoteParent(ctx context.Context, name string, parent SpanContext, o ...StartOption) (context.Context, *Span) {
+	var opts StartOptions
+	for _, op := range o {
+		op(&opts)
+	}
+	span := startSpanInternal(name, parent != SpanContext{}, parent, true, opts)
+	ctx, end := startExecutionTracerTask(ctx, name)
+	span.executionTracerTaskEnd = end
+	return NewContext(ctx, span), span
+}
+
+func startSpanInternal(name string, hasParent bool, parent SpanContext, remoteParent bool, o StartOptions) *Span {
+	span := &Span{}
+	span.spanContext = parent
+
+	cfg := config.Load().(*Config)
+
+	if !hasParent {
+		span.spanContext.TraceID = cfg.IDGenerator.NewTraceID()
+	}
+	span.spanContext.SpanID = cfg.IDGenerator.NewSpanID()
+	sampler := cfg.DefaultSampler
+
+	if !hasParent || remoteParent || o.Sampler != nil {
+		// If this span is the child of a local span and no Sampler is set in the
+		// options, keep the parent's TraceOptions.
+		//
+		// Otherwise, consult the Sampler in the options if it is non-nil, otherwise
+		// the default sampler.
+		if o.Sampler != nil {
+			sampler = o.Sampler
+		}
+		span.spanContext.setIsSampled(sampler(SamplingParameters{
+			ParentContext:   parent,
+			TraceID:         span.spanContext.TraceID,
+			SpanID:          span.spanContext.SpanID,
+			Name:            name,
+			HasRemoteParent: remoteParent}).Sample)
+	}
+
+	if !internal.LocalSpanStoreEnabled && !span.spanContext.IsSampled() {
+		return span
+	}
+
+	span.data = &SpanData{
+		SpanContext:     span.spanContext,
+		StartTime:       time.Now(),
+		SpanKind:        o.SpanKind,
+		Name:            name,
+		HasRemoteParent: remoteParent,
+	}
+	if hasParent {
+		span.data.ParentSpanID = parent.SpanID
+	}
+	if internal.LocalSpanStoreEnabled {
+		var ss *spanStore
+		ss = spanStoreForNameCreateIfNew(name)
+		if ss != nil {
+			span.spanStore = ss
+			ss.add(span)
+		}
+	}
+
+	return span
+}
+
+// End ends the span.
+func (s *Span) End() {
+	if s == nil {
+		return
+	}
+	if s.executionTracerTaskEnd != nil {
+		s.executionTracerTaskEnd()
+	}
+	if !s.IsRecordingEvents() {
+		return
+	}
+	s.endOnce.Do(func() {
+		exp, _ := exporters.Load().(exportersMap)
+		mustExport := s.spanContext.IsSampled() && len(exp) > 0
+		if s.spanStore != nil || mustExport {
+			sd := s.makeSpanData()
+			sd.EndTime = internal.MonotonicEndTime(sd.StartTime)
+			if s.spanStore != nil {
+				s.spanStore.finished(s, sd)
+			}
+			if mustExport {
+				for e := range exp {
+					e.ExportSpan(sd)
+				}
+			}
+		}
+	})
+}
+
+// makeSpanData produces a SpanData representing the current state of the Span.
+// It requires that s.data is non-nil.
+func (s *Span) makeSpanData() *SpanData {
+	var sd SpanData
+	s.mu.Lock()
+	sd = *s.data
+	if s.data.Attributes != nil {
+		sd.Attributes = make(map[string]interface{})
+		for k, v := range s.data.Attributes {
+			sd.Attributes[k] = v
+		}
+	}
+	s.mu.Unlock()
+	return &sd
+}
+
+// SpanContext returns the SpanContext of the span.
+func (s *Span) SpanContext() SpanContext {
+	if s == nil {
+		return SpanContext{}
+	}
+	return s.spanContext
+}
+
+// SetName sets the name of the span, if it is recording events.
+func (s *Span) SetName(name string) {
+	if !s.IsRecordingEvents() {
+		return
+	}
+	s.mu.Lock()
+	s.data.Name = name
+	s.mu.Unlock()
+}
+
+// SetStatus sets the status of the span, if it is recording events.
+func (s *Span) SetStatus(status Status) {
+	if !s.IsRecordingEvents() {
+		return
+	}
+	s.mu.Lock()
+	s.data.Status = status
+	s.mu.Unlock()
+}
+
+// AddAttributes sets attributes in the span.
+//
+// Existing attributes whose keys appear in the attributes parameter are overwritten.
+func (s *Span) AddAttributes(attributes ...Attribute) {
+	if !s.IsRecordingEvents() {
+		return
+	}
+	s.mu.Lock()
+	if s.data.Attributes == nil {
+		s.data.Attributes = make(map[string]interface{})
+	}
+	copyAttributes(s.data.Attributes, attributes)
+	s.mu.Unlock()
+}
+
+// copyAttributes copies a slice of Attributes into a map.
+func copyAttributes(m map[string]interface{}, attributes []Attribute) {
+	for _, a := range attributes {
+		m[a.key] = a.value
+	}
+}
+
+func (s *Span) lazyPrintfInternal(attributes []Attribute, format string, a ...interface{}) {
+	now := time.Now()
+	msg := fmt.Sprintf(format, a...)
+	var m map[string]interface{}
+	s.mu.Lock()
+	if len(attributes) != 0 {
+		m = make(map[string]interface{})
+		copyAttributes(m, attributes)
+	}
+	s.data.Annotations = append(s.data.Annotations, Annotation{
+		Time:       now,
+		Message:    msg,
+		Attributes: m,
+	})
+	s.mu.Unlock()
+}
+
+func (s *Span) printStringInternal(attributes []Attribute, str string) {
+	now := time.Now()
+	var a map[string]interface{}
+	s.mu.Lock()
+	if len(attributes) != 0 {
+		a = make(map[string]interface{})
+		copyAttributes(a, attributes)
+	}
+	s.data.Annotations = append(s.data.Annotations, Annotation{
+		Time:       now,
+		Message:    str,
+		Attributes: a,
+	})
+	s.mu.Unlock()
+}
+
+// Annotate adds an annotation with attributes.
+// Attributes can be nil.
+func (s *Span) Annotate(attributes []Attribute, str string) {
+	if !s.IsRecordingEvents() {
+		return
+	}
+	s.printStringInternal(attributes, str)
+}
+
+// Annotatef adds an annotation with attributes.
+func (s *Span) Annotatef(attributes []Attribute, format string, a ...interface{}) {
+	if !s.IsRecordingEvents() {
+		return
+	}
+	s.lazyPrintfInternal(attributes, format, a...)
+}
+
+// AddMessageSendEvent adds a message send event to the span.
+//
+// messageID is an identifier for the message, which is recommended to be
+// unique in this span and the same between the send event and the receive
+// event (this allows to identify a message between the sender and receiver).
+// For example, this could be a sequence id.
+func (s *Span) AddMessageSendEvent(messageID, uncompressedByteSize, compressedByteSize int64) {
+	if !s.IsRecordingEvents() {
+		return
+	}
+	now := time.Now()
+	s.mu.Lock()
+	s.data.MessageEvents = append(s.data.MessageEvents, MessageEvent{
+		Time:                 now,
+		EventType:            MessageEventTypeSent,
+		MessageID:            messageID,
+		UncompressedByteSize: uncompressedByteSize,
+		CompressedByteSize:   compressedByteSize,
+	})
+	s.mu.Unlock()
+}
+
+// AddMessageReceiveEvent adds a message receive event to the span.
+//
+// messageID is an identifier for the message, which is recommended to be
+// unique in this span and the same between the send event and the receive
+// event (this allows to identify a message between the sender and receiver).
+// For example, this could be a sequence id.
+func (s *Span) AddMessageReceiveEvent(messageID, uncompressedByteSize, compressedByteSize int64) {
+	if !s.IsRecordingEvents() {
+		return
+	}
+	now := time.Now()
+	s.mu.Lock()
+	s.data.MessageEvents = append(s.data.MessageEvents, MessageEvent{
+		Time:                 now,
+		EventType:            MessageEventTypeRecv,
+		MessageID:            messageID,
+		UncompressedByteSize: uncompressedByteSize,
+		CompressedByteSize:   compressedByteSize,
+	})
+	s.mu.Unlock()
+}
+
+// AddLink adds a link to the span.
+func (s *Span) AddLink(l Link) {
+	if !s.IsRecordingEvents() {
+		return
+	}
+	s.mu.Lock()
+	s.data.Links = append(s.data.Links, l)
+	s.mu.Unlock()
+}
+
+func (s *Span) String() string {
+	if s == nil {
+		return "<nil>"
+	}
+	if s.data == nil {
+		return fmt.Sprintf("span %s", s.spanContext.SpanID)
+	}
+	s.mu.Lock()
+	str := fmt.Sprintf("span %s %q", s.spanContext.SpanID, s.data.Name)
+	s.mu.Unlock()
+	return str
+}
+
+var config atomic.Value // access atomically
+
+func init() {
+	gen := &defaultIDGenerator{}
+	// initialize traceID and spanID generators.
+	var rngSeed int64
+	for _, p := range []interface{}{
+		&rngSeed, &gen.traceIDAdd, &gen.nextSpanID, &gen.spanIDInc,
+	} {
+		binary.Read(crand.Reader, binary.LittleEndian, p)
+	}
+	gen.traceIDRand = rand.New(rand.NewSource(rngSeed))
+	gen.spanIDInc |= 1
+
+	config.Store(&Config{
+		DefaultSampler: ProbabilitySampler(defaultSamplingProbability),
+		IDGenerator:    gen,
+	})
+}
+
+type defaultIDGenerator struct {
+	sync.Mutex
+
+	// Please keep these as the first fields
+	// so that these 8 byte fields will be aligned on addresses
+	// divisible by 8, on both 32-bit and 64-bit machines when
+	// performing atomic increments and accesses.
+	// See:
+	// * https://github.com/census-instrumentation/opencensus-go/issues/587
+	// * https://github.com/census-instrumentation/opencensus-go/issues/865
+	// * https://golang.org/pkg/sync/atomic/#pkg-note-BUG
+	nextSpanID uint64
+	spanIDInc  uint64
+
+	traceIDAdd  [2]uint64
+	traceIDRand *rand.Rand
+}
+
+// NewSpanID returns a non-zero span ID from a randomly-chosen sequence.
+func (gen *defaultIDGenerator) NewSpanID() [8]byte {
+	var id uint64
+	for id == 0 {
+		id = atomic.AddUint64(&gen.nextSpanID, gen.spanIDInc)
+	}
+	var sid [8]byte
+	binary.LittleEndian.PutUint64(sid[:], id)
+	return sid
+}
+
+// NewTraceID returns a non-zero trace ID from a randomly-chosen sequence.
+// mu should be held while this function is called.
+func (gen *defaultIDGenerator) NewTraceID() [16]byte {
+	var tid [16]byte
+	// Construct the trace ID from two outputs of traceIDRand, with a constant
+	// added to each half for additional entropy.
+	gen.Lock()
+	binary.LittleEndian.PutUint64(tid[0:8], gen.traceIDRand.Uint64()+gen.traceIDAdd[0])
+	binary.LittleEndian.PutUint64(tid[8:16], gen.traceIDRand.Uint64()+gen.traceIDAdd[1])
+	gen.Unlock()
+	return tid
+}
diff --git a/vendor/go.opencensus.io/trace/trace_go11.go b/vendor/go.opencensus.io/trace/trace_go11.go
new file mode 100644
index 0000000..b7d8aaf
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/trace_go11.go
@@ -0,0 +1,32 @@
+// Copyright 2018, 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.
+
+// +build go1.11
+
+package trace
+
+import (
+	"context"
+	t "runtime/trace"
+)
+
+func startExecutionTracerTask(ctx context.Context, name string) (context.Context, func()) {
+	if !t.IsEnabled() {
+		// Avoid additional overhead if
+		// runtime/trace is not enabled.
+		return ctx, func() {}
+	}
+	nctx, task := t.NewTask(ctx, name)
+	return nctx, task.End
+}
diff --git a/vendor/go.opencensus.io/trace/trace_nongo11.go b/vendor/go.opencensus.io/trace/trace_nongo11.go
new file mode 100644
index 0000000..e254198
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/trace_nongo11.go
@@ -0,0 +1,25 @@
+// Copyright 2018, 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.
+
+// +build !go1.11
+
+package trace
+
+import (
+	"context"
+)
+
+func startExecutionTracerTask(ctx context.Context, name string) (context.Context, func()) {
+	return ctx, func() {}
+}
diff --git a/vendor/go.opencensus.io/trace/tracestate/tracestate.go b/vendor/go.opencensus.io/trace/tracestate/tracestate.go
new file mode 100644
index 0000000..2d6c713
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/tracestate/tracestate.go
@@ -0,0 +1,147 @@
+// Copyright 2018, 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 tracestate implements support for the Tracestate header of the
+// W3C TraceContext propagation format.
+package tracestate
+
+import (
+	"fmt"
+	"regexp"
+)
+
+const (
+	keyMaxSize       = 256
+	valueMaxSize     = 256
+	maxKeyValuePairs = 32
+)
+
+const (
+	keyWithoutVendorFormat = `[a-z][_0-9a-z\-\*\/]{0,255}`
+	keyWithVendorFormat    = `[a-z][_0-9a-z\-\*\/]{0,240}@[a-z][_0-9a-z\-\*\/]{0,13}`
+	keyFormat              = `(` + keyWithoutVendorFormat + `)|(` + keyWithVendorFormat + `)`
+	valueFormat            = `[\x20-\x2b\x2d-\x3c\x3e-\x7e]{0,255}[\x21-\x2b\x2d-\x3c\x3e-\x7e]`
+)
+
+var keyValidationRegExp = regexp.MustCompile(`^(` + keyFormat + `)$`)
+var valueValidationRegExp = regexp.MustCompile(`^(` + valueFormat + `)$`)
+
+// Tracestate represents tracing-system specific context in a list of key-value pairs. Tracestate allows different
+// vendors propagate additional information and inter-operate with their legacy Id formats.
+type Tracestate struct {
+	entries []Entry
+}
+
+// Entry represents one key-value pair in a list of key-value pair of Tracestate.
+type Entry struct {
+	// Key is an opaque string up to 256 characters printable. It MUST begin with a lowercase letter,
+	// and can only contain lowercase letters a-z, digits 0-9, underscores _, dashes -, asterisks *, and
+	// forward slashes /.
+	Key string
+
+	// Value is an opaque string up to 256 characters printable ASCII RFC0020 characters (i.e., the
+	// range 0x20 to 0x7E) except comma , and =.
+	Value string
+}
+
+// Entries returns a slice of Entry.
+func (ts *Tracestate) Entries() []Entry {
+	if ts == nil {
+		return nil
+	}
+	return ts.entries
+}
+
+func (ts *Tracestate) remove(key string) *Entry {
+	for index, entry := range ts.entries {
+		if entry.Key == key {
+			ts.entries = append(ts.entries[:index], ts.entries[index+1:]...)
+			return &entry
+		}
+	}
+	return nil
+}
+
+func (ts *Tracestate) add(entries []Entry) error {
+	for _, entry := range entries {
+		ts.remove(entry.Key)
+	}
+	if len(ts.entries)+len(entries) > maxKeyValuePairs {
+		return fmt.Errorf("adding %d key-value pairs to current %d pairs exceeds the limit of %d",
+			len(entries), len(ts.entries), maxKeyValuePairs)
+	}
+	ts.entries = append(entries, ts.entries...)
+	return nil
+}
+
+func isValid(entry Entry) bool {
+	return keyValidationRegExp.MatchString(entry.Key) &&
+		valueValidationRegExp.MatchString(entry.Value)
+}
+
+func containsDuplicateKey(entries ...Entry) (string, bool) {
+	keyMap := make(map[string]int)
+	for _, entry := range entries {
+		if _, ok := keyMap[entry.Key]; ok {
+			return entry.Key, true
+		}
+		keyMap[entry.Key] = 1
+	}
+	return "", false
+}
+
+func areEntriesValid(entries ...Entry) (*Entry, bool) {
+	for _, entry := range entries {
+		if !isValid(entry) {
+			return &entry, false
+		}
+	}
+	return nil, true
+}
+
+// New creates a Tracestate object from a parent and/or entries (key-value pair).
+// Entries from the parent are copied if present. The entries passed to this function
+// are inserted in front of those copied from the parent. If an entry copied from the
+// parent contains the same key as one of the entry in entries then the entry copied
+// from the parent is removed. See add func.
+//
+// An error is returned with nil Tracestate if
+//  1. one or more entry in entries is invalid.
+//  2. two or more entries in the input entries have the same key.
+//  3. the number of entries combined from the parent and the input entries exceeds maxKeyValuePairs.
+//     (duplicate entry is counted only once).
+func New(parent *Tracestate, entries ...Entry) (*Tracestate, error) {
+	if parent == nil && len(entries) == 0 {
+		return nil, nil
+	}
+	if entry, ok := areEntriesValid(entries...); !ok {
+		return nil, fmt.Errorf("key-value pair {%s, %s} is invalid", entry.Key, entry.Value)
+	}
+
+	if key, duplicate := containsDuplicateKey(entries...); duplicate {
+		return nil, fmt.Errorf("contains duplicate keys (%s)", key)
+	}
+
+	tracestate := Tracestate{}
+
+	if parent != nil && len(parent.entries) > 0 {
+		tracestate.entries = append([]Entry{}, parent.entries...)
+	}
+
+	err := tracestate.add(entries)
+	if err != nil {
+		return nil, err
+	}
+	return &tracestate, nil
+}
diff --git a/vendor/vendor.json b/vendor/vendor.json
index cb04a61..ab65970 100644
--- a/vendor/vendor.json
+++ b/vendor/vendor.json
@@ -5,20 +5,26 @@
 		{
 			"checksumSHA1": "pLvPnUablirQucyALgrso9hLG4E=",
 			"path": "git.autistici.org/ai3/go-common",
-			"revision": "2fd6e256a27812c8dab4cce19b756213ce8c69bf",
-			"revisionTime": "2018-11-16T09:25:50Z"
+			"revision": "1f95fcdd58ebf63d338f05ceae29d2de811a2d2f",
+			"revisionTime": "2018-11-18T16:11:30Z"
 		},
 		{
-			"checksumSHA1": "HtRAXnw4/i/jVoa5d3arp34Uerw=",
+			"checksumSHA1": "1ChQcW9Biu/AgiKjsbJFg/+WhjQ=",
 			"path": "git.autistici.org/ai3/go-common/clientutil",
-			"revision": "2fd6e256a27812c8dab4cce19b756213ce8c69bf",
-			"revisionTime": "2018-11-16T09:25:50Z"
+			"revision": "1f95fcdd58ebf63d338f05ceae29d2de811a2d2f",
+			"revisionTime": "2018-11-18T16:11:30Z"
 		},
 		{
-			"checksumSHA1": "RyFydcBJvLBevfsriijLqHtZ0hs=",
+			"checksumSHA1": "TKGUNmKxj7KH3qhwiCh/6quUnwc=",
 			"path": "git.autistici.org/ai3/go-common/serverutil",
-			"revision": "2fd6e256a27812c8dab4cce19b756213ce8c69bf",
-			"revisionTime": "2018-11-16T09:25:50Z"
+			"revision": "1f95fcdd58ebf63d338f05ceae29d2de811a2d2f",
+			"revisionTime": "2018-11-18T16:11:30Z"
+		},
+		{
+			"checksumSHA1": "WvuSF0pz3rk7bu+5g9lqTqq97Ow=",
+			"path": "git.autistici.org/ai3/go-common/tracing",
+			"revision": "1f95fcdd58ebf63d338f05ceae29d2de811a2d2f",
+			"revisionTime": "2018-11-18T16:11:30Z"
 		},
 		{
 			"checksumSHA1": "rcWTaHvwTmKqbl8NqUF/nDsHzk8=",
@@ -152,6 +158,42 @@
 			"revision": "a2f39d5a9b15ecc1fa1005b6aae73cd83da240ef",
 			"revisionTime": "2017-09-06T15:25:53Z"
 		},
+		{
+			"checksumSHA1": "LnyXWrTqeu9HH+yNzKYn2tg+S2g=",
+			"path": "github.com/openzipkin/zipkin-go",
+			"revision": "3793c981d4f621c0e3eb1457acffa2c1cc591384",
+			"revisionTime": "2018-11-07T13:50:50Z"
+		},
+		{
+			"checksumSHA1": "1n86VLjqoF28QnbVkZm48BXMjjM=",
+			"path": "github.com/openzipkin/zipkin-go/idgenerator",
+			"revision": "3793c981d4f621c0e3eb1457acffa2c1cc591384",
+			"revisionTime": "2018-11-07T13:50:50Z"
+		},
+		{
+			"checksumSHA1": "Pcem82MuBFP2dauH1emyRaXhYIM=",
+			"path": "github.com/openzipkin/zipkin-go/model",
+			"revision": "3793c981d4f621c0e3eb1457acffa2c1cc591384",
+			"revisionTime": "2018-11-07T13:50:50Z"
+		},
+		{
+			"checksumSHA1": "dkd7Sltl3omwaIt2nMA3rNr10GM=",
+			"path": "github.com/openzipkin/zipkin-go/propagation",
+			"revision": "3793c981d4f621c0e3eb1457acffa2c1cc591384",
+			"revisionTime": "2018-11-07T13:50:50Z"
+		},
+		{
+			"checksumSHA1": "/vKln074gYI1JVb20zv0Kfwm+68=",
+			"path": "github.com/openzipkin/zipkin-go/reporter",
+			"revision": "3793c981d4f621c0e3eb1457acffa2c1cc591384",
+			"revisionTime": "2018-11-07T13:50:50Z"
+		},
+		{
+			"checksumSHA1": "aNAxfa1W/33dQP+iO+hyFmyhRkE=",
+			"path": "github.com/openzipkin/zipkin-go/reporter/http",
+			"revision": "3793c981d4f621c0e3eb1457acffa2c1cc591384",
+			"revisionTime": "2018-11-07T13:50:50Z"
+		},
 		{
 			"checksumSHA1": "N6I3i0LIjQckurgTeH3b2A5YTec=",
 			"path": "github.com/oschwald/maxminddb-golang",
@@ -254,6 +296,96 @@
 			"revision": "c46b9c6b15141e1c75d096258e560996b68ef8cb",
 			"revisionTime": "2016-12-26T07:54:37Z"
 		},
+		{
+			"checksumSHA1": "C9EIZQEMR5q5zVZCo1OtPWSV39I=",
+			"path": "go.opencensus.io",
+			"revision": "91a0276ece6ad4cbdc4b46116f88d2b47a5f58e5",
+			"revisionTime": "2018-11-12T17:26:09Z"
+		},
+		{
+			"checksumSHA1": "TA3C6+5PM7V2zbsnLMp13Efy/BA=",
+			"path": "go.opencensus.io/exemplar",
+			"revision": "91a0276ece6ad4cbdc4b46116f88d2b47a5f58e5",
+			"revisionTime": "2018-11-12T17:26:09Z"
+		},
+		{
+			"checksumSHA1": "9TNs1Fhq3e9Xw4XdvxaKjZk0W48=",
+			"path": "go.opencensus.io/exporter/zipkin",
+			"revision": "91a0276ece6ad4cbdc4b46116f88d2b47a5f58e5",
+			"revisionTime": "2018-11-12T17:26:09Z"
+		},
+		{
+			"checksumSHA1": "BhwWPIG9k2gelU3zEOkhKdedctk=",
+			"path": "go.opencensus.io/internal",
+			"revision": "91a0276ece6ad4cbdc4b46116f88d2b47a5f58e5",
+			"revisionTime": "2018-11-12T17:26:09Z"
+		},
+		{
+			"checksumSHA1": "Vcwr4P/uIN4haoJPglU7liURepM=",
+			"path": "go.opencensus.io/internal/tagencoding",
+			"revision": "91a0276ece6ad4cbdc4b46116f88d2b47a5f58e5",
+			"revisionTime": "2018-11-12T17:26:09Z"
+		},
+		{
+			"checksumSHA1": "kxVcsHl3DWhTdSZkterTpRFQRIs=",
+			"path": "go.opencensus.io/plugin/ochttp",
+			"revision": "91a0276ece6ad4cbdc4b46116f88d2b47a5f58e5",
+			"revisionTime": "2018-11-12T17:26:09Z"
+		},
+		{
+			"checksumSHA1": "0OVZlXVUMGzf8ddlnjg2yMZI4ao=",
+			"path": "go.opencensus.io/plugin/ochttp/propagation/b3",
+			"revision": "91a0276ece6ad4cbdc4b46116f88d2b47a5f58e5",
+			"revisionTime": "2018-11-12T17:26:09Z"
+		},
+		{
+			"checksumSHA1": "9Qm9NNFLaZ8KM3pv4lIBSsD4q3A=",
+			"path": "go.opencensus.io/stats",
+			"revision": "91a0276ece6ad4cbdc4b46116f88d2b47a5f58e5",
+			"revisionTime": "2018-11-12T17:26:09Z"
+		},
+		{
+			"checksumSHA1": "SEHKoV2p561oIgFTqzQ67a/XU7I=",
+			"path": "go.opencensus.io/stats/internal",
+			"revision": "91a0276ece6ad4cbdc4b46116f88d2b47a5f58e5",
+			"revisionTime": "2018-11-12T17:26:09Z"
+		},
+		{
+			"checksumSHA1": "KVJAD8BjQ045mOPz/mAWbPXMlIU=",
+			"path": "go.opencensus.io/stats/view",
+			"revision": "91a0276ece6ad4cbdc4b46116f88d2b47a5f58e5",
+			"revisionTime": "2018-11-12T17:26:09Z"
+		},
+		{
+			"checksumSHA1": "/xIgvCFhYpV43FT16tNBTbm7MeY=",
+			"path": "go.opencensus.io/tag",
+			"revision": "91a0276ece6ad4cbdc4b46116f88d2b47a5f58e5",
+			"revisionTime": "2018-11-12T17:26:09Z"
+		},
+		{
+			"checksumSHA1": "LFehOdQ0p2mKk0rpV1FaQTq4UwU=",
+			"path": "go.opencensus.io/trace",
+			"revision": "91a0276ece6ad4cbdc4b46116f88d2b47a5f58e5",
+			"revisionTime": "2018-11-12T17:26:09Z"
+		},
+		{
+			"checksumSHA1": "0P3BycP6CFnFNRCnF4dTlMEJgEI=",
+			"path": "go.opencensus.io/trace/internal",
+			"revision": "91a0276ece6ad4cbdc4b46116f88d2b47a5f58e5",
+			"revisionTime": "2018-11-12T17:26:09Z"
+		},
+		{
+			"checksumSHA1": "FHJParRi8f1GHO7Cx+lk3bMWBq0=",
+			"path": "go.opencensus.io/trace/propagation",
+			"revision": "91a0276ece6ad4cbdc4b46116f88d2b47a5f58e5",
+			"revisionTime": "2018-11-12T17:26:09Z"
+		},
+		{
+			"checksumSHA1": "UHbxxaMqpEPsubh8kPwzSlyEwqI=",
+			"path": "go.opencensus.io/trace/tracestate",
+			"revision": "91a0276ece6ad4cbdc4b46116f88d2b47a5f58e5",
+			"revisionTime": "2018-11-12T17:26:09Z"
+		},
 		{
 			"checksumSHA1": "2LpxYGSf068307b7bhAuVjvzLLc=",
 			"path": "golang.org/x/crypto/ed25519",
-- 
GitLab