summaryrefslogtreecommitdiff
path: root/vendor/go.opencensus.io/plugin
diff options
context:
space:
mode:
authorn1c00o <n@nc0.fr>2023-02-05 14:05:26 +0100
committerNicolas <34602094+n1c00o@users.noreply.github.com>2023-02-06 22:35:54 +0100
commitb371cb11a5877ede8847351e95c7847b5024a551 (patch)
tree958227cf8562503246976744b89370d389de5f66 /vendor/go.opencensus.io/plugin
parent03e0c597ad5f3539ad33976fe02c11a9e39f34d6 (diff)
Init Go module
Diffstat (limited to 'vendor/go.opencensus.io/plugin')
-rw-r--r--vendor/go.opencensus.io/plugin/ochttp/client.go117
-rw-r--r--vendor/go.opencensus.io/plugin/ochttp/client_stats.go143
-rw-r--r--vendor/go.opencensus.io/plugin/ochttp/doc.go19
-rw-r--r--vendor/go.opencensus.io/plugin/ochttp/propagation/b3/b3.go123
-rw-r--r--vendor/go.opencensus.io/plugin/ochttp/route.go61
-rw-r--r--vendor/go.opencensus.io/plugin/ochttp/server.go455
-rw-r--r--vendor/go.opencensus.io/plugin/ochttp/span_annotating_client_trace.go169
-rw-r--r--vendor/go.opencensus.io/plugin/ochttp/stats.go292
-rw-r--r--vendor/go.opencensus.io/plugin/ochttp/trace.go244
-rw-r--r--vendor/go.opencensus.io/plugin/ochttp/wrapped_body.go44
10 files changed, 1667 insertions, 0 deletions
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..17142aa
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/client_stats.go
@@ -0,0 +1,143 @@
+// 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.Host),
+ tag.Upsert(Host, req.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 req.Method != "HEAD" {
+ track.respContentLength = resp.ContentLength
+ }
+ if resp.Body == nil {
+ track.end()
+ } else {
+ track.body = resp.Body
+ resp.Body = wrappedBody(track, resp.Body)
+ }
+ }
+ 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
+ respContentLength 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)
+ respSize := t.respSize
+ if t.respSize == 0 && t.respContentLength > 0 {
+ respSize = t.respContentLength
+ }
+ m := []stats.Measurement{
+ ClientSentBytes.M(t.reqSize),
+ ClientReceivedBytes.M(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)
+ t.respSize += int64(n)
+ switch err {
+ case nil:
+ 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..9ad8852
--- /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, receiver 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 || len(b) > 16 {
+ 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 || len(b) > 8 {
+ 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..5e6a343
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/route.go
@@ -0,0 +1,61 @@
+// 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"
+ "net/http"
+
+ "go.opencensus.io/tag"
+)
+
+// SetRoute sets the http_server_route tag to the given value.
+// It's useful when an HTTP framework does not support the http.Handler interface
+// and using WithRouteTag is not an option, but provides a way to hook into the request flow.
+func SetRoute(ctx context.Context, route string) {
+ if a, ok := ctx.Value(addedTagsKey{}).(*addedTags); ok {
+ a.t = append(a.t, tag.Upsert(KeyServerRoute, route))
+ }
+}
+
+// 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..f7c8434
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/server.go
@@ -0,0 +1,455 @@
+// 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
+
+ // IsHealthEndpoint holds the function to use for determining if the
+ // incoming HTTP request should be considered a health check. This is in
+ // addition to the private isHealthEndpoint func which may also indicate
+ // tracing should be skipped.
+ IsHealthEndpoint func(*http.Request) bool
+}
+
+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 h.IsHealthEndpoint != nil && h.IsHealthEndpoint(r) || 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.LinkTypeParent,
+ Attributes: nil,
+ })
+ }
+ }
+ span.AddAttributes(requestAttrs(r)...)
+ if r.Body == nil {
+ // TODO: Handle cases where ContentLength is not set.
+ } else if r.ContentLength > 0 {
+ span.AddMessageReceiveEvent(0, /* TODO: messageID */
+ r.ContentLength, -1)
+ }
+ 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.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)
+
+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)
+ // Add message event for request bytes sent.
+ span := trace.FromContext(t.ctx)
+ span.AddMessageSendEvent(0 /* TODO: messageID */, int64(n), -1)
+ 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..ee37290
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/stats.go
@@ -0,0 +1,292 @@
+// 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"
+)
+
+// Deprecated: client HTTP measures.
+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)
+)
+
+// The following client HTTP measures are 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.MustNewKey("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.MustNewKey("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.MustNewKey("http.path")
+
+ // Method is the HTTP method of the request, capitalized (GET, POST, etc.).
+ Method = tag.MustNewKey("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.MustNewKey("http_server_route")
+)
+
+// Client tag keys.
+var (
+ // KeyClientMethod is the HTTP method, capitalized (i.e. GET, POST, PUT, DELETE, etc.).
+ KeyClientMethod = tag.MustNewKey("http_client_method")
+ // KeyClientPath is the URL path (not including query string).
+ KeyClientPath = tag.MustNewKey("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.MustNewKey("http_client_status")
+ // KeyClientHost is the value of the request Host header.
+ KeyClientHost = tag.MustNewKey("http_client_host")
+)
+
+// Default distributions used by views in this package.
+var (
+ DefaultSizeDistribution = view.Distribution(1024, 2048, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216, 67108864, 268435456, 1073741824, 4294967296)
+ DefaultLatencyDistribution = view.Distribution(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 for client measures.
+// 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},
+ }
+)
+
+// Deprecated: Old client Views.
+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 instead.
+ ClientResponseBytesView = &view.View{
+ Name: "opencensus.io/http/client/response_bytes",
+ Description: "Size distribution of HTTP response body",
+ Measure: ClientReceivedBytes,
+ Aggregation: DefaultSizeDistribution,
+ }
+
+ // Deprecated: Use ClientRoundtripLatencyDistribution instead.
+ ClientLatencyView = &view.View{
+ Name: "opencensus.io/http/client/latency",
+ Description: "Latency distribution of HTTP requests",
+ Measure: ClientRoundtripLatency,
+ Aggregation: DefaultLatencyDistribution,
+ }
+
+ // Deprecated: Use ClientCompletedCount instead.
+ 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 instead.
+ 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(),
+ }
+)
+
+// Package ochttp provides some convenience views for server measures.
+// You still need to register these views for data to actually be collected.
+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..ed3a5db
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/trace.go
@@ -0,0 +1,244 @@
+// 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"
+ URLAttribute = "http.url"
+ 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.
+ bt := &bodyTracker{rc: resp.Body, span: span}
+ resp.Body = wrappedBody(bt, resp.Body)
+ 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 {
+ userAgent := r.UserAgent()
+
+ attrs := make([]trace.Attribute, 0, 5)
+ attrs = append(attrs,
+ trace.StringAttribute(PathAttribute, r.URL.Path),
+ trace.StringAttribute(URLAttribute, r.URL.String()),
+ trace.StringAttribute(HostAttribute, r.Host),
+ trace.StringAttribute(MethodAttribute, r.Method),
+ )
+
+ if userAgent != "" {
+ attrs = append(attrs, trace.StringAttribute(UserAgentAttribute, userAgent))
+ }
+
+ return attrs
+}
+
+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.StatusUnprocessableEntity:
+ 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
+ case http.StatusConflict:
+ code = trace.StatusCodeAlreadyExists
+ }
+
+ 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/plugin/ochttp/wrapped_body.go b/vendor/go.opencensus.io/plugin/ochttp/wrapped_body.go
new file mode 100644
index 0000000..7d75cae
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/wrapped_body.go
@@ -0,0 +1,44 @@
+// Copyright 2019, 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"
+)
+
+// wrappedBody returns a wrapped version of the original
+// Body and only implements the same combination of additional
+// interfaces as the original.
+func wrappedBody(wrapper io.ReadCloser, body io.ReadCloser) io.ReadCloser {
+ var (
+ wr, i0 = body.(io.Writer)
+ )
+ switch {
+ case !i0:
+ return struct {
+ io.ReadCloser
+ }{wrapper}
+
+ case i0:
+ return struct {
+ io.ReadCloser
+ io.Writer
+ }{wrapper, wr}
+ default:
+ return struct {
+ io.ReadCloser
+ }{wrapper}
+ }
+}