diff options
| author | n1c00o <n@nc0.fr> | 2023-02-05 14:05:26 +0100 | 
|---|---|---|
| committer | Nicolas <34602094+n1c00o@users.noreply.github.com> | 2023-02-06 22:35:54 +0100 | 
| commit | b371cb11a5877ede8847351e95c7847b5024a551 (patch) | |
| tree | 958227cf8562503246976744b89370d389de5f66 /vendor/go.opencensus.io/plugin | |
| parent | 03e0c597ad5f3539ad33976fe02c11a9e39f34d6 (diff) | |
Init Go module
Diffstat (limited to 'vendor/go.opencensus.io/plugin')
| -rw-r--r-- | vendor/go.opencensus.io/plugin/ochttp/client.go | 117 | ||||
| -rw-r--r-- | vendor/go.opencensus.io/plugin/ochttp/client_stats.go | 143 | ||||
| -rw-r--r-- | vendor/go.opencensus.io/plugin/ochttp/doc.go | 19 | ||||
| -rw-r--r-- | vendor/go.opencensus.io/plugin/ochttp/propagation/b3/b3.go | 123 | ||||
| -rw-r--r-- | vendor/go.opencensus.io/plugin/ochttp/route.go | 61 | ||||
| -rw-r--r-- | vendor/go.opencensus.io/plugin/ochttp/server.go | 455 | ||||
| -rw-r--r-- | vendor/go.opencensus.io/plugin/ochttp/span_annotating_client_trace.go | 169 | ||||
| -rw-r--r-- | vendor/go.opencensus.io/plugin/ochttp/stats.go | 292 | ||||
| -rw-r--r-- | vendor/go.opencensus.io/plugin/ochttp/trace.go | 244 | ||||
| -rw-r--r-- | vendor/go.opencensus.io/plugin/ochttp/wrapped_body.go | 44 | 
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} +	} +}  | 
