aboutsummaryrefslogtreecommitdiff
path: root/vendor/go.opencensus.io/plugin/ochttp
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/go.opencensus.io/plugin/ochttp')
-rw-r--r--vendor/go.opencensus.io/plugin/ochttp/client.go84
-rw-r--r--vendor/go.opencensus.io/plugin/ochttp/client_stats.go125
-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/server.go217
-rw-r--r--vendor/go.opencensus.io/plugin/ochttp/stats.go173
-rw-r--r--vendor/go.opencensus.io/plugin/ochttp/trace.go199
7 files changed, 940 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..37f42b3
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/client.go
@@ -0,0 +1,84 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package ochttp
+
+import (
+ "net/http"
+
+ "go.opencensus.io/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.
+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
+
+ // 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()
+ // TODO: remove excessive nesting of http.RoundTrippers here.
+ format := t.Propagation
+ if format == nil {
+ format = defaultFormat
+ }
+ rt = &traceTransport{
+ base: rt,
+ format: format,
+ startOptions: trace.StartOptions{
+ Sampler: t.StartOptions.Sampler,
+ SpanKind: trace.SpanKindClient,
+ },
+ }
+ 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..9b286b9
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/client_stats.go
@@ -0,0 +1,125 @@
+// 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(Host, req.URL.Host),
+ tag.Upsert(Path, req.URL.Path),
+ tag.Upsert(Method, req.Method))
+ req = req.WithContext(ctx)
+ track := &tracker{
+ start: time.Now(),
+ ctx: ctx,
+ }
+ if req.Body == nil {
+ // TODO: Handle cases where ContentLength is not set.
+ track.reqSize = -1
+ } else if req.ContentLength > 0 {
+ track.reqSize = req.ContentLength
+ }
+ stats.Record(ctx, ClientRequestCount.M(1))
+
+ // Perform request.
+ resp, err := t.base.RoundTrip(req)
+
+ if err != nil {
+ track.statusCode = http.StatusInternalServerError
+ track.end()
+ } else {
+ track.statusCode = resp.StatusCode
+ if resp.Body == nil {
+ track.end()
+ } else {
+ track.body = resp.Body
+ resp.Body = track
+ }
+ }
+ return resp, err
+}
+
+// CancelRequest cancels an in-flight request by closing its connection.
+func (t statsTransport) CancelRequest(req *http.Request) {
+ type canceler interface {
+ CancelRequest(*http.Request)
+ }
+ if cr, ok := t.base.(canceler); ok {
+ cr.CancelRequest(req)
+ }
+}
+
+type tracker struct {
+ ctx context.Context
+ respSize int64
+ reqSize int64
+ start time.Time
+ body io.ReadCloser
+ statusCode int
+ endOnce sync.Once
+}
+
+var _ io.ReadCloser = (*tracker)(nil)
+
+func (t *tracker) end() {
+ t.endOnce.Do(func() {
+ m := []stats.Measurement{
+ ClientLatency.M(float64(time.Since(t.start)) / float64(time.Millisecond)),
+ ClientResponseBytes.M(t.respSize),
+ }
+ if t.reqSize >= 0 {
+ m = append(m, ClientRequestBytes.M(t.reqSize))
+ }
+ ctx, _ := tag.New(t.ctx, tag.Upsert(StatusCode, strconv.Itoa(t.statusCode)))
+ stats.Record(ctx, m...)
+ })
+}
+
+func (t *tracker) Read(b []byte) (int, error) {
+ n, err := t.body.Read(b)
+ switch err {
+ case nil:
+ t.respSize += int64(n)
+ return n, nil
+ case io.EOF:
+ t.end()
+ }
+ return n, err
+}
+
+func (t *tracker) Close() error {
+ // Invoking endSpan on Close will help catch the cases
+ // in which a read returned a non-nil error, we set the
+ // span status but didn't end the span.
+ t.end()
+ return t.body.Close()
+}
diff --git a/vendor/go.opencensus.io/plugin/ochttp/doc.go b/vendor/go.opencensus.io/plugin/ochttp/doc.go
new file mode 100644
index 0000000..10e626b
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/doc.go
@@ -0,0 +1,19 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package ochttp provides OpenCensus instrumentation for net/http package.
+//
+// For server instrumentation, see Handler. For client-side instrumentation,
+// see Transport.
+package ochttp // import "go.opencensus.io/plugin/ochttp"
diff --git a/vendor/go.opencensus.io/plugin/ochttp/propagation/b3/b3.go b/vendor/go.opencensus.io/plugin/ochttp/propagation/b3/b3.go
new file mode 100644
index 0000000..f777772
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/propagation/b3/b3.go
@@ -0,0 +1,123 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package b3 contains a propagation.HTTPFormat implementation
+// for B3 propagation. See https://github.com/openzipkin/b3-propagation
+// for more details.
+package b3 // import "go.opencensus.io/plugin/ochttp/propagation/b3"
+
+import (
+ "encoding/hex"
+ "net/http"
+
+ "go.opencensus.io/trace"
+ "go.opencensus.io/trace/propagation"
+)
+
+// B3 headers that OpenCensus understands.
+const (
+ TraceIDHeader = "X-B3-TraceId"
+ SpanIDHeader = "X-B3-SpanId"
+ SampledHeader = "X-B3-Sampled"
+)
+
+// HTTPFormat implements propagation.HTTPFormat to propagate
+// traces in HTTP headers in B3 propagation format.
+// HTTPFormat skips the X-B3-ParentId and X-B3-Flags headers
+// because there are additional fields not represented in the
+// OpenCensus span context. Spans created from the incoming
+// header will be the direct children of the client-side span.
+// Similarly, reciever of the outgoing spans should use client-side
+// span created by OpenCensus as the parent.
+type HTTPFormat struct{}
+
+var _ propagation.HTTPFormat = (*HTTPFormat)(nil)
+
+// SpanContextFromRequest extracts a B3 span context from incoming requests.
+func (f *HTTPFormat) SpanContextFromRequest(req *http.Request) (sc trace.SpanContext, ok bool) {
+ tid, ok := ParseTraceID(req.Header.Get(TraceIDHeader))
+ if !ok {
+ return trace.SpanContext{}, false
+ }
+ sid, ok := ParseSpanID(req.Header.Get(SpanIDHeader))
+ if !ok {
+ return trace.SpanContext{}, false
+ }
+ sampled, _ := ParseSampled(req.Header.Get(SampledHeader))
+ return trace.SpanContext{
+ TraceID: tid,
+ SpanID: sid,
+ TraceOptions: sampled,
+ }, true
+}
+
+// ParseTraceID parses the value of the X-B3-TraceId header.
+func ParseTraceID(tid string) (trace.TraceID, bool) {
+ if tid == "" {
+ return trace.TraceID{}, false
+ }
+ b, err := hex.DecodeString(tid)
+ if err != nil {
+ return trace.TraceID{}, false
+ }
+ var traceID trace.TraceID
+ if len(b) <= 8 {
+ // The lower 64-bits.
+ start := 8 + (8 - len(b))
+ copy(traceID[start:], b)
+ } else {
+ start := 16 - len(b)
+ copy(traceID[start:], b)
+ }
+
+ return traceID, true
+}
+
+// ParseSpanID parses the value of the X-B3-SpanId or X-B3-ParentSpanId headers.
+func ParseSpanID(sid string) (spanID trace.SpanID, ok bool) {
+ if sid == "" {
+ return trace.SpanID{}, false
+ }
+ b, err := hex.DecodeString(sid)
+ if err != nil {
+ return trace.SpanID{}, false
+ }
+ start := 8 - len(b)
+ copy(spanID[start:], b)
+ return spanID, true
+}
+
+// ParseSampled parses the value of the X-B3-Sampled header.
+func ParseSampled(sampled string) (trace.TraceOptions, bool) {
+ switch sampled {
+ case "true", "1":
+ return trace.TraceOptions(1), true
+ default:
+ return trace.TraceOptions(0), false
+ }
+}
+
+// SpanContextToRequest modifies the given request to include B3 headers.
+func (f *HTTPFormat) SpanContextToRequest(sc trace.SpanContext, req *http.Request) {
+ req.Header.Set(TraceIDHeader, hex.EncodeToString(sc.TraceID[:]))
+ req.Header.Set(SpanIDHeader, hex.EncodeToString(sc.SpanID[:]))
+
+ var sampled string
+ if sc.IsSampled() {
+ sampled = "1"
+ } else {
+ sampled = "0"
+ }
+ req.Header.Set(SampledHeader, sampled)
+}
diff --git a/vendor/go.opencensus.io/plugin/ochttp/server.go b/vendor/go.opencensus.io/plugin/ochttp/server.go
new file mode 100644
index 0000000..4b3c855
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/server.go
@@ -0,0 +1,217 @@
+// 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 (
+ "bufio"
+ "context"
+ "errors"
+ "net"
+ "net/http"
+ "strconv"
+ "sync"
+ "time"
+
+ "go.opencensus.io/stats"
+ "go.opencensus.io/tag"
+ "go.opencensus.io/trace"
+ "go.opencensus.io/trace/propagation"
+)
+
+// Handler is a http.Handler that is aware of the incoming request's span.
+//
+// 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.
+ 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
+
+ // 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
+}
+
+func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ var traceEnd, statsEnd func()
+ r, traceEnd = h.startTrace(w, r)
+ defer traceEnd()
+ w, statsEnd = h.startStats(w, r)
+ defer statsEnd()
+ handler := h.Handler
+ if handler == nil {
+ handler = http.DefaultServeMux
+ }
+ handler.ServeHTTP(w, r)
+}
+
+func (h *Handler) startTrace(w http.ResponseWriter, r *http.Request) (*http.Request, func()) {
+ name := spanNameFromURL(r.URL)
+ ctx := r.Context()
+ var span *trace.Span
+ sc, ok := h.extractSpanContext(r)
+ if ok && !h.IsPublicEndpoint {
+ ctx, span = trace.StartSpanWithRemoteParent(ctx, name, sc,
+ trace.WithSampler(h.StartOptions.Sampler),
+ trace.WithSpanKind(trace.SpanKindServer))
+ } else {
+ ctx, span = trace.StartSpan(ctx, name,
+ trace.WithSampler(h.StartOptions.Sampler),
+ trace.WithSpanKind(trace.SpanKindServer),
+ )
+ if ok {
+ span.AddLink(trace.Link{
+ TraceID: sc.TraceID,
+ SpanID: sc.SpanID,
+ Type: trace.LinkTypeChild,
+ Attributes: nil,
+ })
+ }
+ }
+ span.AddAttributes(requestAttrs(r)...)
+ return r.WithContext(ctx), span.End
+}
+
+func (h *Handler) extractSpanContext(r *http.Request) (trace.SpanContext, bool) {
+ if h.Propagation == nil {
+ return defaultFormat.SpanContextFromRequest(r)
+ }
+ return h.Propagation.SpanContextFromRequest(r)
+}
+
+func (h *Handler) startStats(w http.ResponseWriter, r *http.Request) (http.ResponseWriter, func()) {
+ ctx, _ := tag.New(r.Context(),
+ tag.Upsert(Host, r.URL.Host),
+ tag.Upsert(Path, r.URL.Path),
+ tag.Upsert(Method, r.Method))
+ track := &trackingResponseWriter{
+ start: time.Now(),
+ ctx: ctx,
+ writer: w,
+ }
+ if r.Body == nil {
+ // TODO: Handle cases where ContentLength is not set.
+ track.reqSize = -1
+ } else if r.ContentLength > 0 {
+ track.reqSize = r.ContentLength
+ }
+ stats.Record(ctx, ServerRequestCount.M(1))
+ return track, 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 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)
+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 {
+ t.statusCode = 200
+ }
+
+ span := trace.FromContext(t.ctx)
+ span.SetStatus(TraceStatus(t.statusCode, t.statusLine))
+
+ 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))
+ }
+ ctx, _ := tag.New(t.ctx, tag.Upsert(StatusCode, strconv.Itoa(t.statusCode)))
+ stats.Record(ctx, m...)
+ })
+}
+
+func (t *trackingResponseWriter) Header() http.Header {
+ return t.writer.Header()
+}
+
+func (t *trackingResponseWriter) Write(data []byte) (int, error) {
+ n, err := t.writer.Write(data)
+ t.respSize += int64(n)
+ return n, err
+}
+
+func (t *trackingResponseWriter) WriteHeader(statusCode int) {
+ t.writer.WriteHeader(statusCode)
+ t.statusCode = statusCode
+ t.statusLine = http.StatusText(t.statusCode)
+}
+
+func (t *trackingResponseWriter) Flush() {
+ if flusher, ok := t.writer.(http.Flusher); ok {
+ flusher.Flush()
+ }
+}
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..2bd11f6
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/stats.go
@@ -0,0 +1,173 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package ochttp
+
+import (
+ "go.opencensus.io/stats"
+ "go.opencensus.io/stats/view"
+ "go.opencensus.io/tag"
+)
+
+// The following client HTTP measures are supported for use in custom views.
+var (
+ ClientRequestCount = stats.Int64("opencensus.io/http/client/request_count", "Number of HTTP requests started", stats.UnitDimensionless)
+ ClientRequestBytes = stats.Int64("opencensus.io/http/client/request_bytes", "HTTP request body size if set as ContentLength (uncompressed)", stats.UnitBytes)
+ ClientResponseBytes = stats.Int64("opencensus.io/http/client/response_bytes", "HTTP response body size (uncompressed)", stats.UnitBytes)
+ ClientLatency = stats.Float64("opencensus.io/http/client/latency", "End-to-end latency", 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.
+ Host, _ = tag.NewKey("http.host")
+
+ // StatusCode is the numeric HTTP response status code,
+ // or "error" if a transport error occurred and no status code was read.
+ StatusCode, _ = tag.NewKey("http.status")
+
+ // Path is the URL path (not including query string) in the request.
+ Path, _ = tag.NewKey("http.path")
+
+ // Method is the HTTP method of the request, capitalized (GET, POST, etc.).
+ Method, _ = tag.NewKey("http.method")
+)
+
+// Default distributions used by views in this package.
+var (
+ DefaultSizeDistribution = view.Distribution(0, 1024, 2048, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216, 67108864, 268435456, 1073741824, 4294967296)
+ DefaultLatencyDistribution = view.Distribution(0, 1, 2, 3, 4, 5, 6, 8, 10, 13, 16, 20, 25, 30, 40, 50, 65, 80, 100, 130, 160, 200, 250, 300, 400, 500, 650, 800, 1000, 2000, 5000, 10000, 20000, 50000, 100000)
+)
+
+// Package ochttp provides some convenience views.
+// You need to subscribe to the views for data to actually be collected.
+var (
+ ClientRequestCountView = &view.View{
+ Name: "opencensus.io/http/client/request_count",
+ Description: "Count of HTTP requests started",
+ Measure: ClientRequestCount,
+ Aggregation: view.Count(),
+ }
+
+ ClientRequestBytesView = &view.View{
+ Name: "opencensus.io/http/client/request_bytes",
+ Description: "Size distribution of HTTP request body",
+ Measure: ClientRequestBytes,
+ Aggregation: DefaultSizeDistribution,
+ }
+
+ ClientResponseBytesView = &view.View{
+ Name: "opencensus.io/http/client/response_bytes",
+ Description: "Size distribution of HTTP response body",
+ Measure: ClientResponseBytes,
+ Aggregation: DefaultSizeDistribution,
+ }
+
+ ClientLatencyView = &view.View{
+ Name: "opencensus.io/http/client/latency",
+ Description: "Latency distribution of HTTP requests",
+ Measure: ClientLatency,
+ Aggregation: DefaultLatencyDistribution,
+ }
+
+ ClientRequestCountByMethod = &view.View{
+ Name: "opencensus.io/http/client/request_count_by_method",
+ Description: "Client request count by HTTP method",
+ TagKeys: []tag.Key{Method},
+ Measure: ClientRequestCount,
+ Aggregation: view.Count(),
+ }
+
+ 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: ClientLatency,
+ Aggregation: view.Count(),
+ }
+
+ 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.
+var DefaultClientViews = []*view.View{
+ ClientRequestCountView,
+ ClientRequestBytesView,
+ ClientResponseBytesView,
+ ClientLatencyView,
+ ClientRequestCountByMethod,
+ ClientResponseCountByStatusCode,
+}
+
+// DefaultServerViews are the default server views provided by this package.
+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..79bbfd1
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/trace.go
@@ -0,0 +1,199 @@
+// 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/url"
+
+ "go.opencensus.io/plugin/ochttp/propagation/b3"
+ "go.opencensus.io/trace"
+ "go.opencensus.io/trace/propagation"
+)
+
+// TODO(jbd): Add godoc examples.
+
+var defaultFormat propagation.HTTPFormat = &b3.HTTPFormat{}
+
+// Attributes recorded on the span for the requests.
+// Only trace exporters will need them.
+const (
+ HostAttribute = "http.host"
+ MethodAttribute = "http.method"
+ PathAttribute = "http.path"
+ UserAgentAttribute = "http.user_agent"
+ StatusCodeAttribute = "http.status_code"
+)
+
+type traceTransport struct {
+ base http.RoundTripper
+ startOptions trace.StartOptions
+ format propagation.HTTPFormat
+}
+
+// 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 := spanNameFromURL(req.URL)
+ // TODO(jbd): Discuss whether we want to prefix
+ // outgoing requests with Sent.
+ _, 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.format != nil {
+ t.format.SpanContextToRequest(span.SpanContext(), req)
+ }
+
+ span.AddAttributes(requestAttrs(req)...)
+ resp, err := t.base.RoundTrip(req)
+ if err != nil {
+ span.SetStatus(trace.Status{Code: trace.StatusCodeUnknown, Message: err.Error()})
+ span.End()
+ return resp, err
+ }
+
+ span.AddAttributes(responseAttrs(resp)...)
+ span.SetStatus(TraceStatus(resp.StatusCode, resp.Status))
+
+ // span.End() will be invoked after
+ // a read from resp.Body returns io.EOF or when
+ // resp.Body.Close() is invoked.
+ resp.Body = &bodyTracker{rc: resp.Body, span: span}
+ return resp, err
+}
+
+// bodyTracker wraps a response.Body and invokes
+// trace.EndSpan on encountering io.EOF on reading
+// the body of the original response.
+type bodyTracker struct {
+ rc io.ReadCloser
+ span *trace.Span
+}
+
+var _ io.ReadCloser = (*bodyTracker)(nil)
+
+func (bt *bodyTracker) Read(b []byte) (int, error) {
+ n, err := bt.rc.Read(b)
+
+ switch err {
+ case nil:
+ return n, nil
+ case io.EOF:
+ bt.span.End()
+ default:
+ // For all other errors, set the span status
+ bt.span.SetStatus(trace.Status{
+ // Code 2 is the error code for Internal server error.
+ Code: 2,
+ Message: err.Error(),
+ })
+ }
+ return n, err
+}
+
+func (bt *bodyTracker) Close() error {
+ // Invoking endSpan on Close will help catch the cases
+ // in which a read returned a non-nil error, we set the
+ // span status but didn't end the span.
+ bt.span.End()
+ return bt.rc.Close()
+}
+
+// CancelRequest cancels an in-flight request by closing its connection.
+func (t *traceTransport) CancelRequest(req *http.Request) {
+ type canceler interface {
+ CancelRequest(*http.Request)
+ }
+ if cr, ok := t.base.(canceler); ok {
+ cr.CancelRequest(req)
+ }
+}
+
+func spanNameFromURL(u *url.URL) string {
+ return u.Path
+}
+
+func requestAttrs(r *http.Request) []trace.Attribute {
+ return []trace.Attribute{
+ trace.StringAttribute(PathAttribute, r.URL.Path),
+ trace.StringAttribute(HostAttribute, r.URL.Host),
+ trace.StringAttribute(MethodAttribute, r.Method),
+ trace.StringAttribute(UserAgentAttribute, r.UserAgent()),
+ }
+}
+
+func responseAttrs(resp *http.Response) []trace.Attribute {
+ return []trace.Attribute{
+ trace.Int64Attribute(StatusCodeAttribute, int64(resp.StatusCode)),
+ }
+}
+
+// TraceStatus converts the HTTP status code to a trace.Status that
+// represents the outcome as closely as possible.
+func TraceStatus(httpStatusCode int, statusLine string) trace.Status {
+ var code int32
+ if httpStatusCode < 200 || httpStatusCode >= 400 {
+ code = trace.StatusCodeUnknown
+ }
+ switch httpStatusCode {
+ case 499:
+ code = trace.StatusCodeCancelled
+ case http.StatusBadRequest:
+ code = trace.StatusCodeInvalidArgument
+ case http.StatusGatewayTimeout:
+ code = trace.StatusCodeDeadlineExceeded
+ case http.StatusNotFound:
+ code = trace.StatusCodeNotFound
+ case http.StatusForbidden:
+ code = trace.StatusCodePermissionDenied
+ case http.StatusUnauthorized: // 401 is actually unauthenticated.
+ code = trace.StatusCodeUnauthenticated
+ case http.StatusTooManyRequests:
+ code = trace.StatusCodeResourceExhausted
+ case http.StatusNotImplemented:
+ code = trace.StatusCodeUnimplemented
+ case http.StatusServiceUnavailable:
+ code = trace.StatusCodeUnavailable
+ case http.StatusOK:
+ code = trace.StatusCodeOK
+ }
+ return trace.Status{Code: code, Message: codeToStr[code]}
+}
+
+var codeToStr = map[int32]string{
+ trace.StatusCodeOK: `"OK"`,
+ trace.StatusCodeCancelled: `"CANCELLED"`,
+ trace.StatusCodeUnknown: `"UNKNOWN"`,
+ trace.StatusCodeInvalidArgument: `"INVALID_ARGUMENT"`,
+ trace.StatusCodeDeadlineExceeded: `"DEADLINE_EXCEEDED"`,
+ trace.StatusCodeNotFound: `"NOT_FOUND"`,
+ trace.StatusCodeAlreadyExists: `"ALREADY_EXISTS"`,
+ trace.StatusCodePermissionDenied: `"PERMISSION_DENIED"`,
+ trace.StatusCodeResourceExhausted: `"RESOURCE_EXHAUSTED"`,
+ trace.StatusCodeFailedPrecondition: `"FAILED_PRECONDITION"`,
+ trace.StatusCodeAborted: `"ABORTED"`,
+ trace.StatusCodeOutOfRange: `"OUT_OF_RANGE"`,
+ trace.StatusCodeUnimplemented: `"UNIMPLEMENTED"`,
+ trace.StatusCodeInternal: `"INTERNAL"`,
+ trace.StatusCodeUnavailable: `"UNAVAILABLE"`,
+ trace.StatusCodeDataLoss: `"DATA_LOSS"`,
+ trace.StatusCodeUnauthenticated: `"UNAUTHENTICATED"`,
+}