From f8e3dea19012ccf05965d10255789eec33c2ebcf Mon Sep 17 00:00:00 2001 From: Niall Sheridan Date: Thu, 23 Aug 2018 22:51:21 +0100 Subject: Update deps --- vendor/go.opencensus.io/CONTRIBUTING.md | 34 ++- vendor/go.opencensus.io/Gopkg.lock | 185 ++++++------- vendor/go.opencensus.io/Gopkg.toml | 12 - vendor/go.opencensus.io/README.md | 99 +++++-- vendor/go.opencensus.io/go.mod | 20 ++ vendor/go.opencensus.io/opencensus.go | 2 +- vendor/go.opencensus.io/plugin/ochttp/client.go | 27 +- vendor/go.opencensus.io/plugin/ochttp/server.go | 291 ++++++++++++++++++--- .../plugin/ochttp/span_annotator.go | 160 +++++++++++ vendor/go.opencensus.io/plugin/ochttp/stats.go | 10 +- vendor/go.opencensus.io/plugin/ochttp/trace.go | 39 ++- vendor/go.opencensus.io/stats/measure.go | 28 +- vendor/go.opencensus.io/stats/measure_float64.go | 8 +- vendor/go.opencensus.io/stats/measure_int64.go | 8 +- vendor/go.opencensus.io/stats/view/collector.go | 5 +- vendor/go.opencensus.io/stats/view/export.go | 3 + vendor/go.opencensus.io/stats/view/view.go | 6 +- vendor/go.opencensus.io/stats/view/worker.go | 62 ++--- .../go.opencensus.io/stats/view/worker_commands.go | 9 +- vendor/go.opencensus.io/tag/map_codec.go | 31 ++- vendor/go.opencensus.io/trace/config.go | 9 +- vendor/go.opencensus.io/trace/doc.go | 2 +- vendor/go.opencensus.io/trace/export.go | 34 ++- vendor/go.opencensus.io/trace/trace.go | 93 ++++--- 24 files changed, 865 insertions(+), 312 deletions(-) create mode 100644 vendor/go.opencensus.io/go.mod create mode 100644 vendor/go.opencensus.io/plugin/ochttp/span_annotator.go (limited to 'vendor/go.opencensus.io') diff --git a/vendor/go.opencensus.io/CONTRIBUTING.md b/vendor/go.opencensus.io/CONTRIBUTING.md index 6ec97c9..3f3aed3 100644 --- a/vendor/go.opencensus.io/CONTRIBUTING.md +++ b/vendor/go.opencensus.io/CONTRIBUTING.md @@ -21,4 +21,36 @@ 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/ \ No newline at end of file +[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 index 026f013..3be12ac 100644 --- a/vendor/go.opencensus.io/Gopkg.lock +++ b/vendor/go.opencensus.io/Gopkg.lock @@ -1,58 +1,47 @@ # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. -[[projects]] - name = "cloud.google.com/go" - packages = [ - "compute/metadata", - "internal/version", - "monitoring/apiv3", - "trace/apiv2" - ] - revision = "0fd7230b2a7505833d5f69b75cbd6c9582401479" - version = "v0.23.0" - [[projects]] branch = "master" + digest = "1:eee9386329f4fcdf8d6c0def0c9771b634bdd5ba460d888aa98c17d59b37a76c" name = "git.apache.org/thrift.git" packages = ["lib/go/thrift"] - revision = "88591e32e710a0524327153c8b629d5b461e35e0" + 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", - "protoc-gen-go/descriptor", "ptypes", "ptypes/any", "ptypes/duration", - "ptypes/empty", "ptypes/timestamp", - "ptypes/wrappers" ] - revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265" - version = "v1.1.0" - -[[projects]] - name = "github.com/googleapis/gax-go" - packages = ["."] - revision = "317e0006254c44a0ac427cc52a0e083ff0b9622f" - version = "v2.0.0" + pruneopts = "UT" + revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5" + version = "v1.2.0" [[projects]] + digest = "1:ff5ebae34cfbf047d505ee150de27e60570e8c394b3b8fdbb720ff6ac71985fc" name = "github.com/matttproud/golang_protobuf_extensions" packages = ["pbutil"] - revision = "3247c84500bff8d9fb6d579d800f20b3e091582c" - version = "v1.0.0" + pruneopts = "UT" + revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c" + version = "v1.0.1" [[projects]] + digest = "1:824c8f3aa4c5f23928fa84ebbd5ed2e9443b3f0cb958a40c1f2fbed5cf5e64b1" name = "github.com/openzipkin/zipkin-go" packages = [ ".", @@ -60,81 +49,90 @@ "model", "propagation", "reporter", - "reporter/http" + "reporter/http", ] - revision = "f197ec29e729f226d23370ea60f0e49b8f44ccf4" - version = "v0.1.0" + pruneopts = "UT" + revision = "d455a5674050831c1e187644faa4046d653433c2" + version = "v0.1.1" [[projects]] + digest = "1:d14a5f4bfecf017cb780bdde1b6483e5deb87e12c332544d2c430eda58734bcb" name = "github.com/prometheus/client_golang" packages = [ "prometheus", - "prometheus/promhttp" + "prometheus/promhttp", ] + pruneopts = "UT" revision = "c5b7fccd204277076155f10851dad72b76a49317" version = "v0.8.0" [[projects]] branch = "master" + digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4" name = "github.com/prometheus/client_model" packages = ["go"] - revision = "99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c" + pruneopts = "UT" + revision = "5c3871d89910bfb32f5fcab2aa4b9ec68e65a99f" [[projects]] branch = "master" + digest = "1:63b68062b8968092eb86bedc4e68894bd096ea6b24920faca8b9dcf451f54bb5" name = "github.com/prometheus/common" packages = [ "expfmt", "internal/bitbucket.org/ww/goautoneg", - "model" + "model", ] - revision = "7600349dcfe1abd18d72d3a1770870d9800a7801" + pruneopts = "UT" + revision = "c7de2306084e37d54b8be01f3541a8464345e9a5" [[projects]] branch = "master" + digest = "1:8c49953a1414305f2ff5465147ee576dd705487c35b15918fcd4efdc0cb7a290" name = "github.com/prometheus/procfs" packages = [ ".", "internal/util", "nfs", - "xfs" + "xfs", ] - revision = "8b1c2da0d56deffdbb9e48d4414b4e674bd8083e" + pruneopts = "UT" + revision = "05ee40e3a273f7245e8777337fc7b46e533a9a92" [[projects]] branch = "master" + digest = "1:deafe4ab271911fec7de5b693d7faae3f38796d9eb8622e2b9e7df42bb3dfea9" name = "golang.org/x/net" packages = [ "context", - "context/ctxhttp", "http/httpguts", "http2", "http2/hpack", "idna", "internal/timeseries", - "trace" + "trace", ] - revision = "9ef9f5bb98a1fdc41f8cf6c250a4404b4085e389" - -[[projects]] - branch = "master" - name = "golang.org/x/oauth2" - packages = [ - ".", - "google", - "internal", - "jws", - "jwt" - ] - revision = "dd5f5d8e78ce062a4aa881dff95a94f2a0fd405a" + 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", @@ -150,79 +148,48 @@ "unicode/bidi", "unicode/cldr", "unicode/norm", - "unicode/rangetable" + "unicode/rangetable", ] + pruneopts = "UT" revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" version = "v0.3.0" [[projects]] branch = "master" + digest = "1:c0c17c94fe8bc1ab34e7f586a4a8b788c5e1f4f9f750ff23395b8b2f5a523530" name = "google.golang.org/api" - packages = [ - "googleapi/transport", - "internal", - "iterator", - "option", - "support/bundler", - "transport", - "transport/grpc", - "transport/http" - ] - revision = "4f7dd2b006a4ffd9fd683c1c734d2fe91ca0ea1c" - -[[projects]] - name = "google.golang.org/appengine" - packages = [ - ".", - "internal", - "internal/app_identity", - "internal/base", - "internal/datastore", - "internal/log", - "internal/modules", - "internal/remote_api", - "internal/socket", - "internal/urlfetch", - "socket", - "urlfetch" - ] - revision = "150dc57a1b433e64154302bdc40b6bb8aefa313a" - version = "v1.0.0" + packages = ["support/bundler"] + pruneopts = "UT" + revision = "e21acd801f91da814261b938941d193bb036441a" [[projects]] branch = "master" + digest = "1:077c1c599507b3b3e9156d17d36e1e61928ee9b53a5b420f10f28ebd4a0b275c" name = "google.golang.org/genproto" - packages = [ - "googleapis/api/annotations", - "googleapis/api/distribution", - "googleapis/api/label", - "googleapis/api/metric", - "googleapis/api/monitoredres", - "googleapis/devtools/cloudtrace/v2", - "googleapis/monitoring/v3", - "googleapis/rpc/code", - "googleapis/rpc/status", - "protobuf/field_mask" - ] - revision = "11a468237815f3a3ddf9f7c6e8b6b3b382a24d15" + packages = ["googleapis/rpc/status"] + pruneopts = "UT" + revision = "c66870c02cf823ceb633bcd05be3c7cda29976f4" [[projects]] + digest = "1:3dd7996ce6bf52dec6a2f69fa43e7c4cefea1d4dfa3c8ab7a5f8a9f7434e239d" name = "google.golang.org/grpc" packages = [ ".", "balancer", "balancer/base", "balancer/roundrobin", - "channelz", "codes", "connectivity", "credentials", - "credentials/oauth", "encoding", "encoding/proto", - "grpclb/grpc_lb_v1/messages", "grpclog", "internal", + "internal/backoff", + "internal/channelz", + "internal/envconfig", + "internal/grpcrand", + "internal/transport", "keepalive", "metadata", "naming", @@ -233,14 +200,32 @@ "stats", "status", "tap", - "transport" ] - revision = "41344da2231b913fa3d983840a57a6b1b7b631a1" - version = "v1.12.0" + pruneopts = "UT" + revision = "32fb0ac620c32ba40a4626ddf94d90d12cce3455" + version = "v1.14.0" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "3fd3b357ae771c152cbc6b6d7b731c00c91c871cf2dbccb2f155ecc84ec80c4f" + 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 index c3f8292..a9f3cd6 100644 --- a/vendor/go.opencensus.io/Gopkg.toml +++ b/vendor/go.opencensus.io/Gopkg.toml @@ -2,10 +2,6 @@ # to avoid locking to a particular minor version which can cause dep to not be # able to find a satisfying dependency graph. -[[constraint]] - name = "cloud.google.com/go" - version = ">=0.21.0" - [[constraint]] branch = "master" name = "git.apache.org/thrift.git" @@ -27,18 +23,10 @@ branch = "master" name = "golang.org/x/net" -[[constraint]] - branch = "master" - name = "golang.org/x/oauth2" - [[constraint]] branch = "master" name = "google.golang.org/api" -[[constraint]] - branch = "master" - name = "google.golang.org/genproto" - [[constraint]] name = "google.golang.org/grpc" version = "1.11.3" diff --git a/vendor/go.opencensus.io/README.md b/vendor/go.opencensus.io/README.md index 1a4a58b..bc50ee4 100644 --- a/vendor/go.opencensus.io/README.md +++ b/vendor/go.opencensus.io/README.md @@ -22,17 +22,40 @@ The use of vendoring or a dependency management tool is recommended. 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/basvanbeek/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 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. -Currently, OpenCensus supports: +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 [Monitoring][exporter-stackdriver] and [Trace][exporter-stackdriver] +* [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 + ## Overview ![OpenCensus Overview](https://i.imgur.com/cf4ElHE.jpg) @@ -42,13 +65,6 @@ 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. -Start with instrumenting HTTP and gRPC clients and servers, -then add additional custom instrumentation if needed. - -* [HTTP guide](https://github.com/census-instrumentation/opencensus-go/tree/master/examples/http) -* [gRPC guide](https://github.com/census-instrumentation/opencensus-go/tree/master/examples/grpc) - - ## Tags Tags represent propagated key-value pairs. They are propagated using `context.Context` @@ -115,26 +131,79 @@ 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: "my.org/video_size_distribution", + 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 subscribe to view: %v", err) + log.Fatalf("Failed to register view: %v", err) } ``` -Subscribe begins collecting data for the view. Subscribed views' data will be +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, "your choice of name") +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 uses the OpenCensus' [binary propagation format](https://godoc.org/go.opencensus.io/trace/propagation). +* HTTP integrations uses 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 @@ -166,7 +235,7 @@ 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 +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 diff --git a/vendor/go.opencensus.io/go.mod b/vendor/go.opencensus.io/go.mod new file mode 100644 index 0000000..7a1ccc6 --- /dev/null +++ b/vendor/go.opencensus.io/go.mod @@ -0,0 +1,20 @@ +module go.opencensus.io + +require ( + git.apache.org/thrift.git v0.0.0-20180807212849-6e67faa92827 + github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 + github.com/golang/protobuf v1.2.0 + 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-20180821023952-922f4815f713 + golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f + golang.org/x/sys v0.0.0-20180821140842-3b58ed4ad339 + golang.org/x/text v0.3.0 + google.golang.org/api v0.0.0-20180818000503-e21acd801f91 + google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 + google.golang.org/grpc v1.14.0 +) diff --git a/vendor/go.opencensus.io/opencensus.go b/vendor/go.opencensus.io/opencensus.go index eb8e721..3b4e0c6 100644 --- a/vendor/go.opencensus.io/opencensus.go +++ b/vendor/go.opencensus.io/opencensus.go @@ -17,5 +17,5 @@ package opencensus // import "go.opencensus.io" // Version is the current release version of OpenCensus in use. func Version() string { - return "0.14.0" + return "0.16.0" } diff --git a/vendor/go.opencensus.io/plugin/ochttp/client.go b/vendor/go.opencensus.io/plugin/ochttp/client.go index 37f42b3..68faf24 100644 --- a/vendor/go.opencensus.io/plugin/ochttp/client.go +++ b/vendor/go.opencensus.io/plugin/ochttp/client.go @@ -16,14 +16,18 @@ 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 -// stats and tracing. The zero value is intended to be a useful default, but for -// now it's recommended that you explicitly set Propagation. +// 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. @@ -43,17 +47,34 @@ type Transport struct { // for spans started by this transport. StartOptions 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 + } rt = &traceTransport{ base: rt, format: format, @@ -61,6 +82,8 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) { Sampler: t.StartOptions.Sampler, SpanKind: trace.SpanKindClient, }, + formatSpanName: spanNameFormatter, + newClientTrace: t.NewClientTrace, } rt = statsTransport{base: rt} return rt.RoundTrip(req) diff --git a/vendor/go.opencensus.io/plugin/ochttp/server.go b/vendor/go.opencensus.io/plugin/ochttp/server.go index 4b3c855..72aa8c2 100644 --- a/vendor/go.opencensus.io/plugin/ochttp/server.go +++ b/vendor/go.opencensus.io/plugin/ochttp/server.go @@ -15,10 +15,8 @@ package ochttp import ( - "bufio" "context" - "errors" - "net" + "io" "net/http" "strconv" "sync" @@ -30,16 +28,19 @@ import ( "go.opencensus.io/trace/propagation" ) -// Handler is a http.Handler that is aware of the incoming request's span. +// 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. -// -// Incoming propagation mechanism is determined by the given HTTP propagators. type Handler struct { // Propagation defines how traces are propagated. If unspecified, // B3 propagation will be used. @@ -60,6 +61,11 @@ type Handler struct { // 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) { @@ -76,7 +82,15 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } func (h *Handler) startTrace(w http.ResponseWriter, r *http.Request) (*http.Request, func()) { - name := spanNameFromURL(r.URL) + 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() var span *trace.Span sc, ok := h.extractSpanContext(r) @@ -126,7 +140,7 @@ func (h *Handler) startStats(w http.ResponseWriter, r *http.Request) (http.Respo track.reqSize = r.ContentLength } stats.Record(ctx, ServerRequestCount.M(1)) - return track, track.end + return track.wrappedResponseWriter(), track.end } type trackingResponseWriter struct { @@ -140,39 +154,9 @@ type trackingResponseWriter struct { writer http.ResponseWriter } -// Compile time assertions for widely used net/http interfaces -var _ http.CloseNotifier = (*trackingResponseWriter)(nil) -var _ http.Flusher = (*trackingResponseWriter)(nil) -var _ http.Hijacker = (*trackingResponseWriter)(nil) -var _ http.Pusher = (*trackingResponseWriter)(nil) +// Compile time assertion for ResponseWriter interface var _ http.ResponseWriter = (*trackingResponseWriter)(nil) -var errHijackerUnimplemented = errors.New("ResponseWriter does not implement http.Hijacker") - -func (t *trackingResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { - hj, ok := t.writer.(http.Hijacker) - if !ok { - return nil, nil, errHijackerUnimplemented - } - return hj.Hijack() -} - -func (t *trackingResponseWriter) CloseNotify() <-chan bool { - cn, ok := t.writer.(http.CloseNotifier) - if !ok { - return nil - } - return cn.CloseNotify() -} - -func (t *trackingResponseWriter) Push(target string, opts *http.PushOptions) error { - pusher, ok := t.writer.(http.Pusher) - if !ok { - return http.ErrNotSupported - } - return pusher.Push(target, opts) -} - func (t *trackingResponseWriter) end() { t.endOnce.Do(func() { if t.statusCode == 0 { @@ -210,8 +194,231 @@ func (t *trackingResponseWriter) WriteHeader(statusCode int) { t.statusLine = http.StatusText(t.statusCode) } -func (t *trackingResponseWriter) Flush() { - if flusher, ok := t.writer.(http.Flusher); ok { - flusher.Flush() +// 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_annotator.go b/vendor/go.opencensus.io/plugin/ochttp/span_annotator.go new file mode 100644 index 0000000..1282287 --- /dev/null +++ b/vendor/go.opencensus.io/plugin/ochttp/span_annotator.go @@ -0,0 +1,160 @@ +// 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 +} + +// NewSpanAnnotator returns a httptrace.ClientTrace which annotates all emitted +// httptrace events on the provided Span. +func NewSpanAnnotator(_ *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 index 2bd11f6..19a8825 100644 --- a/vendor/go.opencensus.io/plugin/ochttp/stats.go +++ b/vendor/go.opencensus.io/plugin/ochttp/stats.go @@ -41,6 +41,10 @@ var ( // 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, @@ -48,6 +52,10 @@ var ( 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.). @@ -61,7 +69,7 @@ var ( ) // Package ochttp provides some convenience views. -// You need to subscribe to the views for data to actually be collected. +// You need to register the views for data to actually be collected. var ( ClientRequestCountView = &view.View{ Name: "opencensus.io/http/client/request_count", diff --git a/vendor/go.opencensus.io/plugin/ochttp/trace.go b/vendor/go.opencensus.io/plugin/ochttp/trace.go index 79bbfd1..980b639 100644 --- a/vendor/go.opencensus.io/plugin/ochttp/trace.go +++ b/vendor/go.opencensus.io/plugin/ochttp/trace.go @@ -17,7 +17,7 @@ package ochttp import ( "io" "net/http" - "net/url" + "net/http/httptrace" "go.opencensus.io/plugin/ochttp/propagation/b3" "go.opencensus.io/trace" @@ -39,9 +39,11 @@ const ( ) type traceTransport struct { - base http.RoundTripper - startOptions trace.StartOptions - format propagation.HTTPFormat + 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. @@ -50,14 +52,19 @@ type traceTransport struct { // 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 := spanNameFromURL(req.URL) + name := t.formatSpanName(req) // TODO(jbd): Discuss whether we want to prefix // outgoing requests with Sent. - _, span := trace.StartSpan(req.Context(), name, + ctx, span := trace.StartSpan(req.Context(), name, trace.WithSampler(t.startOptions.Sampler), trace.WithSpanKind(trace.SpanKindClient)) - req = req.WithContext(trace.WithSpan(req.Context(), span)) + if t.newClientTrace != nil { + req = req.WithContext(httptrace.WithClientTrace(ctx, t.newClientTrace(req, span))) + } else { + req = req.WithContext(ctx) + } + if t.format != nil { t.format.SpanContextToRequest(span.SpanContext(), req) } @@ -127,8 +134,8 @@ func (t *traceTransport) CancelRequest(req *http.Request) { } } -func spanNameFromURL(u *url.URL) string { - return u.Path +func spanNameFromURL(req *http.Request) string { + return req.URL.Path } func requestAttrs(r *http.Request) []trace.Attribute { @@ -146,7 +153,7 @@ func responseAttrs(resp *http.Response) []trace.Attribute { } } -// TraceStatus converts the HTTP status code to a trace.Status that +// 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 @@ -197,3 +204,15 @@ var codeToStr = map[int32]string{ 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/measure.go b/vendor/go.opencensus.io/stats/measure.go index aa555c2..7b4b49c 100644 --- a/vendor/go.opencensus.io/stats/measure.go +++ b/vendor/go.opencensus.io/stats/measure.go @@ -20,19 +20,31 @@ import ( "sync/atomic" ) -// Measure represents a type of metric to be tracked and recorded. -// For example, latency, request Mb/s, and response Mb/s are measures +// 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. // -// Each measure needs to be registered before being used. -// Measure constructors such as Int64 and -// Float64 automatically registers the measure -// by the given name. -// Each registered measure needs to be unique by name. -// Measures also have a description and a unit. +// 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 } diff --git a/vendor/go.opencensus.io/stats/measure_float64.go b/vendor/go.opencensus.io/stats/measure_float64.go index 8de6b52..da4b5a8 100644 --- a/vendor/go.opencensus.io/stats/measure_float64.go +++ b/vendor/go.opencensus.io/stats/measure_float64.go @@ -15,7 +15,7 @@ package stats -// Float64Measure is a measure of type float64. +// Float64Measure is a measure for float64 values. type Float64Measure struct { md *measureDescriptor } @@ -44,8 +44,10 @@ func (m *Float64Measure) M(v float64) Measurement { return Measurement{m: m, v: v} } -// Float64 creates a new measure of type Float64Measure. -// It never returns an error. +// 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 index b6fd25f..5fedaad 100644 --- a/vendor/go.opencensus.io/stats/measure_int64.go +++ b/vendor/go.opencensus.io/stats/measure_int64.go @@ -15,7 +15,7 @@ package stats -// Int64Measure is a measure of type int64. +// Int64Measure is a measure for int64 values. type Int64Measure struct { md *measureDescriptor } @@ -44,8 +44,10 @@ func (m *Int64Measure) M(v int64) Measurement { return Measurement{m: m, v: float64(v)} } -// Int64 creates a new measure of type Int64Measure. -// It never returns an error. +// 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/view/collector.go b/vendor/go.opencensus.io/stats/view/collector.go index 863a5b6..250395d 100644 --- a/vendor/go.opencensus.io/stats/view/collector.go +++ b/vendor/go.opencensus.io/stats/view/collector.go @@ -40,11 +40,12 @@ func (c *collector) addSample(s string, v float64) { aggregator.addSample(v) } +// collectRows returns a snapshot of the collected Row values. func (c *collector) collectedRows(keys []tag.Key) []*Row { - var rows []*Row + rows := make([]*Row, 0, len(c.signatures)) for sig, aggregator := range c.signatures { tags := decodeTags([]byte(sig), keys) - row := &Row{tags, aggregator} + row := &Row{Tags: tags, Data: aggregator.clone()} rows = append(rows, row) } return rows diff --git a/vendor/go.opencensus.io/stats/view/export.go b/vendor/go.opencensus.io/stats/view/export.go index ffd0d1a..7cb5971 100644 --- a/vendor/go.opencensus.io/stats/view/export.go +++ b/vendor/go.opencensus.io/stats/view/export.go @@ -27,6 +27,9 @@ var ( // 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) diff --git a/vendor/go.opencensus.io/stats/view/view.go b/vendor/go.opencensus.io/stats/view/view.go index 87bf5d4..22323e2 100644 --- a/vendor/go.opencensus.io/stats/view/view.go +++ b/vendor/go.opencensus.io/stats/view/view.go @@ -29,7 +29,7 @@ import ( ) // View allows users to aggregate the recorded stats.Measurements. -// Views need to be passed to the Subscribe function to be before data will be +// 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. @@ -71,10 +71,10 @@ func (v *View) same(other *View) bool { // defaults for Name and Description and sorting the TagKeys func (v *View) canonicalize() error { if v.Measure == nil { - return fmt.Errorf("cannot subscribe view %q: measure not set", v.Name) + return fmt.Errorf("cannot register view %q: measure not set", v.Name) } if v.Aggregation == nil { - return fmt.Errorf("cannot subscribe view %q: aggregation not set", v.Name) + return fmt.Errorf("cannot register view %q: aggregation not set", v.Name) } if v.Name == "" { v.Name = v.Measure.Name() diff --git a/vendor/go.opencensus.io/stats/view/worker.go b/vendor/go.opencensus.io/stats/view/worker.go index ba9d7fc..fef7bf5 100644 --- a/vendor/go.opencensus.io/stats/view/worker.go +++ b/vendor/go.opencensus.io/stats/view/worker.go @@ -49,8 +49,8 @@ var defaultWorker *worker var defaultReportingDuration = 10 * time.Second -// Find returns a subscribed view associated with this name. -// If no subscribed view is found, nil is returned. +// 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, @@ -62,7 +62,7 @@ func Find(name string) (v *View) { } // Register begins collecting data for the given views. -// Once a view is subscribed, it reports data to the registered exporters. +// 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 { @@ -181,7 +181,7 @@ func (w *worker) tryRegisterView(v *View) (*viewInternal, error) { } if x, ok := w.views[vi.view.Name]; ok { if !x.view.same(vi.view) { - return nil, fmt.Errorf("cannot subscribe view %q; a different view with the same name is already subscribed", v.Name) + 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 @@ -194,40 +194,30 @@ func (w *worker) tryRegisterView(v *View) (*viewInternal, error) { return vi, nil } -func (w *worker) reportUsage(now time.Time) { - for _, v := range w.views { - if !v.isSubscribed() { - continue - } - rows := v.collectedRows() - _, ok := w.startTimes[v] - if !ok { - w.startTimes[v] = now - } - // Make sure collector is never going - // to mutate the exported data. - rows = deepCopyRowData(rows) - 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) 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 deepCopyRowData(rows []*Row) []*Row { - newRows := make([]*Row, 0, len(rows)) - for _, r := range rows { - newRows = append(newRows, &Row{ - Data: r.Data.clone(), - Tags: r.Tags, - }) +func (w *worker) reportUsage(now time.Time) { + for _, v := range w.views { + w.reportView(v, now) } - return newRows } diff --git a/vendor/go.opencensus.io/stats/view/worker_commands.go b/vendor/go.opencensus.io/stats/view/worker_commands.go index ef79ec3..06c3c54 100644 --- a/vendor/go.opencensus.io/stats/view/worker_commands.go +++ b/vendor/go.opencensus.io/stats/view/worker_commands.go @@ -73,7 +73,7 @@ func (cmd *registerViewReq) handleCommand(w *worker) { } } -// unregisterFromViewReq is the command to unsubscribe to a view. Has no +// 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 { @@ -88,6 +88,9 @@ func (cmd *unregisterFromViewReq) handleCommand(w *worker) { 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. @@ -143,7 +146,7 @@ type recordReq struct { func (cmd *recordReq) handleCommand(w *worker) { for _, m := range cmd.ms { - if (m == stats.Measurement{}) { // not subscribed + if (m == stats.Measurement{}) { // not registered continue } ref := w.getMeasureRef(m.Measure().Name()) @@ -154,7 +157,7 @@ func (cmd *recordReq) handleCommand(w *worker) { } // setReportingPeriodReq is the command to modify the duration between -// reporting the collected data to the subscribed clients. +// reporting the collected data to the registered clients. type setReportingPeriodReq struct { d time.Duration c chan bool diff --git a/vendor/go.opencensus.io/tag/map_codec.go b/vendor/go.opencensus.io/tag/map_codec.go index 33be1f0..3e99895 100644 --- a/vendor/go.opencensus.io/tag/map_codec.go +++ b/vendor/go.opencensus.io/tag/map_codec.go @@ -177,45 +177,58 @@ func Encode(m *Map) []byte { // 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 ts, nil + return nil } version := eg.readByte() if version > tagsVersionID { - return nil, fmt.Errorf("cannot decode: unsupported version: %q; supports only up to: %q", 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 nil, fmt.Errorf("cannot decode: invalid key type: %q", typ) + return fmt.Errorf("cannot decode: invalid key type: %q", typ) } k, err := eg.readBytesWithVarintLen() if err != nil { - return nil, err + return err } v, err := eg.readBytesWithVarintLen() if err != nil { - return nil, err + return err } key, err := NewKey(string(k)) if err != nil { - return nil, err // no partial failures + return err } val := string(v) if !checkValue(val) { - return nil, errInvalidValue // no partial failures + return errInvalidValue + } + fn(key, val) + if err != nil { + return err } - ts.upsert(key, val) } - return ts, nil + return nil } diff --git a/vendor/go.opencensus.io/trace/config.go b/vendor/go.opencensus.io/trace/config.go index d5473a7..e464671 100644 --- a/vendor/go.opencensus.io/trace/config.go +++ b/vendor/go.opencensus.io/trace/config.go @@ -14,7 +14,10 @@ package trace -import "go.opencensus.io/trace/internal" +import ( + "go.opencensus.io/trace/internal" + "sync" +) // Config represents the global tracing configuration. type Config struct { @@ -25,10 +28,14 @@ type Config struct { 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 diff --git a/vendor/go.opencensus.io/trace/doc.go b/vendor/go.opencensus.io/trace/doc.go index a2b54e5..db00044 100644 --- a/vendor/go.opencensus.io/trace/doc.go +++ b/vendor/go.opencensus.io/trace/doc.go @@ -42,7 +42,7 @@ It is common to want to capture all the activity of a function call in a span. F 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, "my.org/Run") + ctx, span := trace.StartSpan(ctx, "example.com/Run") defer span.End() StartSpan will create a new top-level span if the context diff --git a/vendor/go.opencensus.io/trace/export.go b/vendor/go.opencensus.io/trace/export.go index c522550..77a8c73 100644 --- a/vendor/go.opencensus.io/trace/export.go +++ b/vendor/go.opencensus.io/trace/export.go @@ -16,6 +16,7 @@ package trace import ( "sync" + "sync/atomic" "time" ) @@ -30,9 +31,11 @@ type Exporter interface { ExportSpan(s *SpanData) } +type exportersMap map[Exporter]struct{} + var ( - exportersMu sync.Mutex - exporters map[Exporter]struct{} + exporterMu sync.Mutex + exporters atomic.Value ) // RegisterExporter adds to the list of Exporters that will receive sampled @@ -40,20 +43,31 @@ var ( // // Binaries can register exporters, libraries shouldn't register exporters. func RegisterExporter(e Exporter) { - exportersMu.Lock() - if exporters == nil { - exporters = make(map[Exporter]struct{}) + exporterMu.Lock() + new := make(exportersMap) + if old, ok := exporters.Load().(exportersMap); ok { + for k, v := range old { + new[k] = v + } } - exporters[e] = struct{}{} - exportersMu.Unlock() + 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) { - exportersMu.Lock() - delete(exporters, e) - exportersMu.Unlock() + 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. diff --git a/vendor/go.opencensus.io/trace/trace.go b/vendor/go.opencensus.io/trace/trace.go index 19c6930..887e90b 100644 --- a/vendor/go.opencensus.io/trace/trace.go +++ b/vendor/go.opencensus.io/trace/trace.go @@ -98,13 +98,6 @@ func FromContext(ctx context.Context) *Span { return s } -// WithSpan returns a new context with the given Span attached. -// -// Deprecated: Use NewContext. -func WithSpan(parent context.Context, s *Span) context.Context { - return NewContext(parent, 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) @@ -154,6 +147,9 @@ func WithSampler(sampler Sampler) StartOption { // 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 @@ -174,6 +170,9 @@ func StartSpan(ctx context.Context, name string, o ...StartOption) (context.Cont // // 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 { @@ -185,26 +184,6 @@ func StartSpanWithRemoteParent(ctx context.Context, name string, parent SpanCont return NewContext(ctx, span), span } -// NewSpan returns a new span. -// -// If parent is not nil, created span will be a child of the parent. -// -// Deprecated: Use StartSpan. -func NewSpan(name string, parent *Span, o StartOptions) *Span { - var parentSpanContext SpanContext - if parent != nil { - parentSpanContext = parent.SpanContext() - } - return startSpanInternal(name, parent != nil, parentSpanContext, false, o) -} - -// NewSpanWithRemoteParent returns a new span with the given parent SpanContext. -// -// Deprecated: Use StartSpanWithRemoteParent. -func NewSpanWithRemoteParent(name string, parent SpanContext, o StartOptions) *Span { - return startSpanInternal(name, true, parent, true, o) -} - func startSpanInternal(name string, hasParent bool, parent SpanContext, remoteParent bool, o StartOptions) *Span { span := &Span{} span.spanContext = parent @@ -269,19 +248,19 @@ func (s *Span) End() { if s.executionTracerTaskEnd != nil { s.executionTracerTaskEnd() } - // TODO: optimize to avoid this call if sd won't be used. - sd := s.makeSpanData() - sd.EndTime = internal.MonotonicEndTime(sd.StartTime) - if s.spanStore != nil { - s.spanStore.finished(s, sd) - } - if s.spanContext.IsSampled() { - // TODO: consider holding exportersMu for less time. - exportersMu.Lock() - for e := range exporters { - e.ExportSpan(sd) + 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) + } } - exportersMu.Unlock() } }) } @@ -310,6 +289,16 @@ func (s *Span) SpanContext() 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() { @@ -481,22 +470,28 @@ func init() { type defaultIDGenerator struct { sync.Mutex - traceIDRand *rand.Rand + + // 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 - nextSpanID uint64 - spanIDInc uint64 + traceIDRand *rand.Rand } // NewSpanID returns a non-zero span ID from a randomly-chosen sequence. -// mu should be held while this function is called. func (gen *defaultIDGenerator) NewSpanID() [8]byte { - gen.Lock() - id := gen.nextSpanID - gen.nextSpanID += gen.spanIDInc - if gen.nextSpanID == 0 { - gen.nextSpanID += gen.spanIDInc + var id uint64 + for id == 0 { + id = atomic.AddUint64(&gen.nextSpanID, gen.spanIDInc) } - gen.Unlock() var sid [8]byte binary.LittleEndian.PutUint64(sid[:], id) return sid -- cgit v1.2.3