aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/go.opencensus.io/plugin/ochttp
diff options
context:
space:
mode:
authorNathan Dench <ndenc2@gmail.com>2019-05-24 15:16:44 +1000
committerNathan Dench <ndenc2@gmail.com>2019-05-24 15:16:44 +1000
commit107c1cdb09c575aa2f61d97f48d8587eb6bada4c (patch)
treeca7d008643efc555c388baeaf1d986e0b6b3e28c /vendor/go.opencensus.io/plugin/ochttp
parent844b5a68d8af4791755b8f0ad293cc99f5959183 (diff)
downloadterraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.gz
terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.zst
terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.zip
Upgrade to 0.12
Diffstat (limited to 'vendor/go.opencensus.io/plugin/ochttp')
-rw-r--r--vendor/go.opencensus.io/plugin/ochttp/client.go117
-rw-r--r--vendor/go.opencensus.io/plugin/ochttp/client_stats.go135
-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.go51
-rw-r--r--vendor/go.opencensus.io/plugin/ochttp/server.go440
-rw-r--r--vendor/go.opencensus.io/plugin/ochttp/span_annotating_client_trace.go169
-rw-r--r--vendor/go.opencensus.io/plugin/ochttp/stats.go265
-rw-r--r--vendor/go.opencensus.io/plugin/ochttp/trace.go228
9 files changed, 1547 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 @@
1// Copyright 2018, OpenCensus Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package ochttp
16
17import (
18 "net/http"
19 "net/http/httptrace"
20
21 "go.opencensus.io/trace"
22 "go.opencensus.io/trace/propagation"
23)
24
25// Transport is an http.RoundTripper that instruments all outgoing requests with
26// OpenCensus stats and tracing.
27//
28// The zero value is intended to be a useful default, but for
29// now it's recommended that you explicitly set Propagation, since the default
30// for this may change.
31type Transport struct {
32 // Base may be set to wrap another http.RoundTripper that does the actual
33 // requests. By default http.DefaultTransport is used.
34 //
35 // If base HTTP roundtripper implements CancelRequest,
36 // the returned round tripper will be cancelable.
37 Base http.RoundTripper
38
39 // Propagation defines how traces are propagated. If unspecified, a default
40 // (currently B3 format) will be used.
41 Propagation propagation.HTTPFormat
42
43 // StartOptions are applied to the span started by this Transport around each
44 // request.
45 //
46 // StartOptions.SpanKind will always be set to trace.SpanKindClient
47 // for spans started by this transport.
48 StartOptions trace.StartOptions
49
50 // GetStartOptions allows to set start options per request. If set,
51 // StartOptions is going to be ignored.
52 GetStartOptions func(*http.Request) trace.StartOptions
53
54 // NameFromRequest holds the function to use for generating the span name
55 // from the information found in the outgoing HTTP Request. By default the
56 // name equals the URL Path.
57 FormatSpanName func(*http.Request) string
58
59 // NewClientTrace may be set to a function allowing the current *trace.Span
60 // to be annotated with HTTP request event information emitted by the
61 // httptrace package.
62 NewClientTrace func(*http.Request, *trace.Span) *httptrace.ClientTrace
63
64 // TODO: Implement tag propagation for HTTP.
65}
66
67// RoundTrip implements http.RoundTripper, delegating to Base and recording stats and traces for the request.
68func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
69 rt := t.base()
70 if isHealthEndpoint(req.URL.Path) {
71 return rt.RoundTrip(req)
72 }
73 // TODO: remove excessive nesting of http.RoundTrippers here.
74 format := t.Propagation
75 if format == nil {
76 format = defaultFormat
77 }
78 spanNameFormatter := t.FormatSpanName
79 if spanNameFormatter == nil {
80 spanNameFormatter = spanNameFromURL
81 }
82
83 startOpts := t.StartOptions
84 if t.GetStartOptions != nil {
85 startOpts = t.GetStartOptions(req)
86 }
87
88 rt = &traceTransport{
89 base: rt,
90 format: format,
91 startOptions: trace.StartOptions{
92 Sampler: startOpts.Sampler,
93 SpanKind: trace.SpanKindClient,
94 },
95 formatSpanName: spanNameFormatter,
96 newClientTrace: t.NewClientTrace,
97 }
98 rt = statsTransport{base: rt}
99 return rt.RoundTrip(req)
100}
101
102func (t *Transport) base() http.RoundTripper {
103 if t.Base != nil {
104 return t.Base
105 }
106 return http.DefaultTransport
107}
108
109// CancelRequest cancels an in-flight request by closing its connection.
110func (t *Transport) CancelRequest(req *http.Request) {
111 type canceler interface {
112 CancelRequest(*http.Request)
113 }
114 if cr, ok := t.base().(canceler); ok {
115 cr.CancelRequest(req)
116 }
117}
diff --git a/vendor/go.opencensus.io/plugin/ochttp/client_stats.go b/vendor/go.opencensus.io/plugin/ochttp/client_stats.go
new file mode 100644
index 0000000..066ebb8
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/client_stats.go
@@ -0,0 +1,135 @@
1// Copyright 2018, OpenCensus Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package ochttp
16
17import (
18 "context"
19 "io"
20 "net/http"
21 "strconv"
22 "sync"
23 "time"
24
25 "go.opencensus.io/stats"
26 "go.opencensus.io/tag"
27)
28
29// statsTransport is an http.RoundTripper that collects stats for the outgoing requests.
30type statsTransport struct {
31 base http.RoundTripper
32}
33
34// RoundTrip implements http.RoundTripper, delegating to Base and recording stats for the request.
35func (t statsTransport) RoundTrip(req *http.Request) (*http.Response, error) {
36 ctx, _ := tag.New(req.Context(),
37 tag.Upsert(KeyClientHost, req.URL.Host),
38 tag.Upsert(Host, req.URL.Host),
39 tag.Upsert(KeyClientPath, req.URL.Path),
40 tag.Upsert(Path, req.URL.Path),
41 tag.Upsert(KeyClientMethod, req.Method),
42 tag.Upsert(Method, req.Method))
43 req = req.WithContext(ctx)
44 track := &tracker{
45 start: time.Now(),
46 ctx: ctx,
47 }
48 if req.Body == nil {
49 // TODO: Handle cases where ContentLength is not set.
50 track.reqSize = -1
51 } else if req.ContentLength > 0 {
52 track.reqSize = req.ContentLength
53 }
54 stats.Record(ctx, ClientRequestCount.M(1))
55
56 // Perform request.
57 resp, err := t.base.RoundTrip(req)
58
59 if err != nil {
60 track.statusCode = http.StatusInternalServerError
61 track.end()
62 } else {
63 track.statusCode = resp.StatusCode
64 if resp.Body == nil {
65 track.end()
66 } else {
67 track.body = resp.Body
68 resp.Body = track
69 }
70 }
71 return resp, err
72}
73
74// CancelRequest cancels an in-flight request by closing its connection.
75func (t statsTransport) CancelRequest(req *http.Request) {
76 type canceler interface {
77 CancelRequest(*http.Request)
78 }
79 if cr, ok := t.base.(canceler); ok {
80 cr.CancelRequest(req)
81 }
82}
83
84type tracker struct {
85 ctx context.Context
86 respSize int64
87 reqSize int64
88 start time.Time
89 body io.ReadCloser
90 statusCode int
91 endOnce sync.Once
92}
93
94var _ io.ReadCloser = (*tracker)(nil)
95
96func (t *tracker) end() {
97 t.endOnce.Do(func() {
98 latencyMs := float64(time.Since(t.start)) / float64(time.Millisecond)
99 m := []stats.Measurement{
100 ClientSentBytes.M(t.reqSize),
101 ClientReceivedBytes.M(t.respSize),
102 ClientRoundtripLatency.M(latencyMs),
103 ClientLatency.M(latencyMs),
104 ClientResponseBytes.M(t.respSize),
105 }
106 if t.reqSize >= 0 {
107 m = append(m, ClientRequestBytes.M(t.reqSize))
108 }
109
110 stats.RecordWithTags(t.ctx, []tag.Mutator{
111 tag.Upsert(StatusCode, strconv.Itoa(t.statusCode)),
112 tag.Upsert(KeyClientStatus, strconv.Itoa(t.statusCode)),
113 }, m...)
114 })
115}
116
117func (t *tracker) Read(b []byte) (int, error) {
118 n, err := t.body.Read(b)
119 switch err {
120 case nil:
121 t.respSize += int64(n)
122 return n, nil
123 case io.EOF:
124 t.end()
125 }
126 return n, err
127}
128
129func (t *tracker) Close() error {
130 // Invoking endSpan on Close will help catch the cases
131 // in which a read returned a non-nil error, we set the
132 // span status but didn't end the span.
133 t.end()
134 return t.body.Close()
135}
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 @@
1// Copyright 2018, OpenCensus Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Package ochttp provides OpenCensus instrumentation for net/http package.
16//
17// For server instrumentation, see Handler. For client-side instrumentation,
18// see Transport.
19package 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 @@
1// Copyright 2018, OpenCensus Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Package b3 contains a propagation.HTTPFormat implementation
16// for B3 propagation. See https://github.com/openzipkin/b3-propagation
17// for more details.
18package b3 // import "go.opencensus.io/plugin/ochttp/propagation/b3"
19
20import (
21 "encoding/hex"
22 "net/http"
23
24 "go.opencensus.io/trace"
25 "go.opencensus.io/trace/propagation"
26)
27
28// B3 headers that OpenCensus understands.
29const (
30 TraceIDHeader = "X-B3-TraceId"
31 SpanIDHeader = "X-B3-SpanId"
32 SampledHeader = "X-B3-Sampled"
33)
34
35// HTTPFormat implements propagation.HTTPFormat to propagate
36// traces in HTTP headers in B3 propagation format.
37// HTTPFormat skips the X-B3-ParentId and X-B3-Flags headers
38// because there are additional fields not represented in the
39// OpenCensus span context. Spans created from the incoming
40// header will be the direct children of the client-side span.
41// Similarly, reciever of the outgoing spans should use client-side
42// span created by OpenCensus as the parent.
43type HTTPFormat struct{}
44
45var _ propagation.HTTPFormat = (*HTTPFormat)(nil)
46
47// SpanContextFromRequest extracts a B3 span context from incoming requests.
48func (f *HTTPFormat) SpanContextFromRequest(req *http.Request) (sc trace.SpanContext, ok bool) {
49 tid, ok := ParseTraceID(req.Header.Get(TraceIDHeader))
50 if !ok {
51 return trace.SpanContext{}, false
52 }
53 sid, ok := ParseSpanID(req.Header.Get(SpanIDHeader))
54 if !ok {
55 return trace.SpanContext{}, false
56 }
57 sampled, _ := ParseSampled(req.Header.Get(SampledHeader))
58 return trace.SpanContext{
59 TraceID: tid,
60 SpanID: sid,
61 TraceOptions: sampled,
62 }, true
63}
64
65// ParseTraceID parses the value of the X-B3-TraceId header.
66func ParseTraceID(tid string) (trace.TraceID, bool) {
67 if tid == "" {
68 return trace.TraceID{}, false
69 }
70 b, err := hex.DecodeString(tid)
71 if err != nil {
72 return trace.TraceID{}, false
73 }
74 var traceID trace.TraceID
75 if len(b) <= 8 {
76 // The lower 64-bits.
77 start := 8 + (8 - len(b))
78 copy(traceID[start:], b)
79 } else {
80 start := 16 - len(b)
81 copy(traceID[start:], b)
82 }
83
84 return traceID, true
85}
86
87// ParseSpanID parses the value of the X-B3-SpanId or X-B3-ParentSpanId headers.
88func ParseSpanID(sid string) (spanID trace.SpanID, ok bool) {
89 if sid == "" {
90 return trace.SpanID{}, false
91 }
92 b, err := hex.DecodeString(sid)
93 if err != nil {
94 return trace.SpanID{}, false
95 }
96 start := 8 - len(b)
97 copy(spanID[start:], b)
98 return spanID, true
99}
100
101// ParseSampled parses the value of the X-B3-Sampled header.
102func ParseSampled(sampled string) (trace.TraceOptions, bool) {
103 switch sampled {
104 case "true", "1":
105 return trace.TraceOptions(1), true
106 default:
107 return trace.TraceOptions(0), false
108 }
109}
110
111// SpanContextToRequest modifies the given request to include B3 headers.
112func (f *HTTPFormat) SpanContextToRequest(sc trace.SpanContext, req *http.Request) {
113 req.Header.Set(TraceIDHeader, hex.EncodeToString(sc.TraceID[:]))
114 req.Header.Set(SpanIDHeader, hex.EncodeToString(sc.SpanID[:]))
115
116 var sampled string
117 if sc.IsSampled() {
118 sampled = "1"
119 } else {
120 sampled = "0"
121 }
122 req.Header.Set(SampledHeader, sampled)
123}
diff --git a/vendor/go.opencensus.io/plugin/ochttp/route.go b/vendor/go.opencensus.io/plugin/ochttp/route.go
new file mode 100644
index 0000000..dbe22d5
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/route.go
@@ -0,0 +1,51 @@
1// Copyright 2018, OpenCensus Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package ochttp
16
17import (
18 "net/http"
19
20 "go.opencensus.io/tag"
21)
22
23// WithRouteTag returns an http.Handler that records stats with the
24// http_server_route tag set to the given value.
25func WithRouteTag(handler http.Handler, route string) http.Handler {
26 return taggedHandlerFunc(func(w http.ResponseWriter, r *http.Request) []tag.Mutator {
27 addRoute := []tag.Mutator{tag.Upsert(KeyServerRoute, route)}
28 ctx, _ := tag.New(r.Context(), addRoute...)
29 r = r.WithContext(ctx)
30 handler.ServeHTTP(w, r)
31 return addRoute
32 })
33}
34
35// taggedHandlerFunc is a http.Handler that returns tags describing the
36// processing of the request. These tags will be recorded along with the
37// measures in this package at the end of the request.
38type taggedHandlerFunc func(w http.ResponseWriter, r *http.Request) []tag.Mutator
39
40func (h taggedHandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) {
41 tags := h(w, r)
42 if a, ok := r.Context().Value(addedTagsKey{}).(*addedTags); ok {
43 a.t = append(a.t, tags...)
44 }
45}
46
47type addedTagsKey struct{}
48
49type addedTags struct {
50 t []tag.Mutator
51}
diff --git a/vendor/go.opencensus.io/plugin/ochttp/server.go b/vendor/go.opencensus.io/plugin/ochttp/server.go
new file mode 100644
index 0000000..ff72de9
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/server.go
@@ -0,0 +1,440 @@
1// Copyright 2018, OpenCensus Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package ochttp
16
17import (
18 "context"
19 "io"
20 "net/http"
21 "strconv"
22 "sync"
23 "time"
24
25 "go.opencensus.io/stats"
26 "go.opencensus.io/tag"
27 "go.opencensus.io/trace"
28 "go.opencensus.io/trace/propagation"
29)
30
31// Handler is an http.Handler wrapper to instrument your HTTP server with
32// OpenCensus. It supports both stats and tracing.
33//
34// Tracing
35//
36// This handler is aware of the incoming request's span, reading it from request
37// headers as configured using the Propagation field.
38// The extracted span can be accessed from the incoming request's
39// context.
40//
41// span := trace.FromContext(r.Context())
42//
43// The server span will be automatically ended at the end of ServeHTTP.
44type Handler struct {
45 // Propagation defines how traces are propagated. If unspecified,
46 // B3 propagation will be used.
47 Propagation propagation.HTTPFormat
48
49 // Handler is the handler used to handle the incoming request.
50 Handler http.Handler
51
52 // StartOptions are applied to the span started by this Handler around each
53 // request.
54 //
55 // StartOptions.SpanKind will always be set to trace.SpanKindServer
56 // for spans started by this transport.
57 StartOptions trace.StartOptions
58
59 // GetStartOptions allows to set start options per request. If set,
60 // StartOptions is going to be ignored.
61 GetStartOptions func(*http.Request) trace.StartOptions
62
63 // IsPublicEndpoint should be set to true for publicly accessible HTTP(S)
64 // servers. If true, any trace metadata set on the incoming request will
65 // be added as a linked trace instead of being added as a parent of the
66 // current trace.
67 IsPublicEndpoint bool
68
69 // FormatSpanName holds the function to use for generating the span name
70 // from the information found in the incoming HTTP Request. By default the
71 // name equals the URL Path.
72 FormatSpanName func(*http.Request) string
73}
74
75func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
76 var tags addedTags
77 r, traceEnd := h.startTrace(w, r)
78 defer traceEnd()
79 w, statsEnd := h.startStats(w, r)
80 defer statsEnd(&tags)
81 handler := h.Handler
82 if handler == nil {
83 handler = http.DefaultServeMux
84 }
85 r = r.WithContext(context.WithValue(r.Context(), addedTagsKey{}, &tags))
86 handler.ServeHTTP(w, r)
87}
88
89func (h *Handler) startTrace(w http.ResponseWriter, r *http.Request) (*http.Request, func()) {
90 if isHealthEndpoint(r.URL.Path) {
91 return r, func() {}
92 }
93 var name string
94 if h.FormatSpanName == nil {
95 name = spanNameFromURL(r)
96 } else {
97 name = h.FormatSpanName(r)
98 }
99 ctx := r.Context()
100
101 startOpts := h.StartOptions
102 if h.GetStartOptions != nil {
103 startOpts = h.GetStartOptions(r)
104 }
105
106 var span *trace.Span
107 sc, ok := h.extractSpanContext(r)
108 if ok && !h.IsPublicEndpoint {
109 ctx, span = trace.StartSpanWithRemoteParent(ctx, name, sc,
110 trace.WithSampler(startOpts.Sampler),
111 trace.WithSpanKind(trace.SpanKindServer))
112 } else {
113 ctx, span = trace.StartSpan(ctx, name,
114 trace.WithSampler(startOpts.Sampler),
115 trace.WithSpanKind(trace.SpanKindServer),
116 )
117 if ok {
118 span.AddLink(trace.Link{
119 TraceID: sc.TraceID,
120 SpanID: sc.SpanID,
121 Type: trace.LinkTypeChild,
122 Attributes: nil,
123 })
124 }
125 }
126 span.AddAttributes(requestAttrs(r)...)
127 return r.WithContext(ctx), span.End
128}
129
130func (h *Handler) extractSpanContext(r *http.Request) (trace.SpanContext, bool) {
131 if h.Propagation == nil {
132 return defaultFormat.SpanContextFromRequest(r)
133 }
134 return h.Propagation.SpanContextFromRequest(r)
135}
136
137func (h *Handler) startStats(w http.ResponseWriter, r *http.Request) (http.ResponseWriter, func(tags *addedTags)) {
138 ctx, _ := tag.New(r.Context(),
139 tag.Upsert(Host, r.URL.Host),
140 tag.Upsert(Path, r.URL.Path),
141 tag.Upsert(Method, r.Method))
142 track := &trackingResponseWriter{
143 start: time.Now(),
144 ctx: ctx,
145 writer: w,
146 }
147 if r.Body == nil {
148 // TODO: Handle cases where ContentLength is not set.
149 track.reqSize = -1
150 } else if r.ContentLength > 0 {
151 track.reqSize = r.ContentLength
152 }
153 stats.Record(ctx, ServerRequestCount.M(1))
154 return track.wrappedResponseWriter(), track.end
155}
156
157type trackingResponseWriter struct {
158 ctx context.Context
159 reqSize int64
160 respSize int64
161 start time.Time
162 statusCode int
163 statusLine string
164 endOnce sync.Once
165 writer http.ResponseWriter
166}
167
168// Compile time assertion for ResponseWriter interface
169var _ http.ResponseWriter = (*trackingResponseWriter)(nil)
170
171var logTagsErrorOnce sync.Once
172
173func (t *trackingResponseWriter) end(tags *addedTags) {
174 t.endOnce.Do(func() {
175 if t.statusCode == 0 {
176 t.statusCode = 200
177 }
178
179 span := trace.FromContext(t.ctx)
180 span.SetStatus(TraceStatus(t.statusCode, t.statusLine))
181 span.AddAttributes(trace.Int64Attribute(StatusCodeAttribute, int64(t.statusCode)))
182
183 m := []stats.Measurement{
184 ServerLatency.M(float64(time.Since(t.start)) / float64(time.Millisecond)),
185 ServerResponseBytes.M(t.respSize),
186 }
187 if t.reqSize >= 0 {
188 m = append(m, ServerRequestBytes.M(t.reqSize))
189 }
190 allTags := make([]tag.Mutator, len(tags.t)+1)
191 allTags[0] = tag.Upsert(StatusCode, strconv.Itoa(t.statusCode))
192 copy(allTags[1:], tags.t)
193 stats.RecordWithTags(t.ctx, allTags, m...)
194 })
195}
196
197func (t *trackingResponseWriter) Header() http.Header {
198 return t.writer.Header()
199}
200
201func (t *trackingResponseWriter) Write(data []byte) (int, error) {
202 n, err := t.writer.Write(data)
203 t.respSize += int64(n)
204 return n, err
205}
206
207func (t *trackingResponseWriter) WriteHeader(statusCode int) {
208 t.writer.WriteHeader(statusCode)
209 t.statusCode = statusCode
210 t.statusLine = http.StatusText(t.statusCode)
211}
212
213// wrappedResponseWriter returns a wrapped version of the original
214// ResponseWriter and only implements the same combination of additional
215// interfaces as the original.
216// This implementation is based on https://github.com/felixge/httpsnoop.
217func (t *trackingResponseWriter) wrappedResponseWriter() http.ResponseWriter {
218 var (
219 hj, i0 = t.writer.(http.Hijacker)
220 cn, i1 = t.writer.(http.CloseNotifier)
221 pu, i2 = t.writer.(http.Pusher)
222 fl, i3 = t.writer.(http.Flusher)
223 rf, i4 = t.writer.(io.ReaderFrom)
224 )
225
226 switch {
227 case !i0 && !i1 && !i2 && !i3 && !i4:
228 return struct {
229 http.ResponseWriter
230 }{t}
231 case !i0 && !i1 && !i2 && !i3 && i4:
232 return struct {
233 http.ResponseWriter
234 io.ReaderFrom
235 }{t, rf}
236 case !i0 && !i1 && !i2 && i3 && !i4:
237 return struct {
238 http.ResponseWriter
239 http.Flusher
240 }{t, fl}
241 case !i0 && !i1 && !i2 && i3 && i4:
242 return struct {
243 http.ResponseWriter
244 http.Flusher
245 io.ReaderFrom
246 }{t, fl, rf}
247 case !i0 && !i1 && i2 && !i3 && !i4:
248 return struct {
249 http.ResponseWriter
250 http.Pusher
251 }{t, pu}
252 case !i0 && !i1 && i2 && !i3 && i4:
253 return struct {
254 http.ResponseWriter
255 http.Pusher
256 io.ReaderFrom
257 }{t, pu, rf}
258 case !i0 && !i1 && i2 && i3 && !i4:
259 return struct {
260 http.ResponseWriter
261 http.Pusher
262 http.Flusher
263 }{t, pu, fl}
264 case !i0 && !i1 && i2 && i3 && i4:
265 return struct {
266 http.ResponseWriter
267 http.Pusher
268 http.Flusher
269 io.ReaderFrom
270 }{t, pu, fl, rf}
271 case !i0 && i1 && !i2 && !i3 && !i4:
272 return struct {
273 http.ResponseWriter
274 http.CloseNotifier
275 }{t, cn}
276 case !i0 && i1 && !i2 && !i3 && i4:
277 return struct {
278 http.ResponseWriter
279 http.CloseNotifier
280 io.ReaderFrom
281 }{t, cn, rf}
282 case !i0 && i1 && !i2 && i3 && !i4:
283 return struct {
284 http.ResponseWriter
285 http.CloseNotifier
286 http.Flusher
287 }{t, cn, fl}
288 case !i0 && i1 && !i2 && i3 && i4:
289 return struct {
290 http.ResponseWriter
291 http.CloseNotifier
292 http.Flusher
293 io.ReaderFrom
294 }{t, cn, fl, rf}
295 case !i0 && i1 && i2 && !i3 && !i4:
296 return struct {
297 http.ResponseWriter
298 http.CloseNotifier
299 http.Pusher
300 }{t, cn, pu}
301 case !i0 && i1 && i2 && !i3 && i4:
302 return struct {
303 http.ResponseWriter
304 http.CloseNotifier
305 http.Pusher
306 io.ReaderFrom
307 }{t, cn, pu, rf}
308 case !i0 && i1 && i2 && i3 && !i4:
309 return struct {
310 http.ResponseWriter
311 http.CloseNotifier
312 http.Pusher
313 http.Flusher
314 }{t, cn, pu, fl}
315 case !i0 && i1 && i2 && i3 && i4:
316 return struct {
317 http.ResponseWriter
318 http.CloseNotifier
319 http.Pusher
320 http.Flusher
321 io.ReaderFrom
322 }{t, cn, pu, fl, rf}
323 case i0 && !i1 && !i2 && !i3 && !i4:
324 return struct {
325 http.ResponseWriter
326 http.Hijacker
327 }{t, hj}
328 case i0 && !i1 && !i2 && !i3 && i4:
329 return struct {
330 http.ResponseWriter
331 http.Hijacker
332 io.ReaderFrom
333 }{t, hj, rf}
334 case i0 && !i1 && !i2 && i3 && !i4:
335 return struct {
336 http.ResponseWriter
337 http.Hijacker
338 http.Flusher
339 }{t, hj, fl}
340 case i0 && !i1 && !i2 && i3 && i4:
341 return struct {
342 http.ResponseWriter
343 http.Hijacker
344 http.Flusher
345 io.ReaderFrom
346 }{t, hj, fl, rf}
347 case i0 && !i1 && i2 && !i3 && !i4:
348 return struct {
349 http.ResponseWriter
350 http.Hijacker
351 http.Pusher
352 }{t, hj, pu}
353 case i0 && !i1 && i2 && !i3 && i4:
354 return struct {
355 http.ResponseWriter
356 http.Hijacker
357 http.Pusher
358 io.ReaderFrom
359 }{t, hj, pu, rf}
360 case i0 && !i1 && i2 && i3 && !i4:
361 return struct {
362 http.ResponseWriter
363 http.Hijacker
364 http.Pusher
365 http.Flusher
366 }{t, hj, pu, fl}
367 case i0 && !i1 && i2 && i3 && i4:
368 return struct {
369 http.ResponseWriter
370 http.Hijacker
371 http.Pusher
372 http.Flusher
373 io.ReaderFrom
374 }{t, hj, pu, fl, rf}
375 case i0 && i1 && !i2 && !i3 && !i4:
376 return struct {
377 http.ResponseWriter
378 http.Hijacker
379 http.CloseNotifier
380 }{t, hj, cn}
381 case i0 && i1 && !i2 && !i3 && i4:
382 return struct {
383 http.ResponseWriter
384 http.Hijacker
385 http.CloseNotifier
386 io.ReaderFrom
387 }{t, hj, cn, rf}
388 case i0 && i1 && !i2 && i3 && !i4:
389 return struct {
390 http.ResponseWriter
391 http.Hijacker
392 http.CloseNotifier
393 http.Flusher
394 }{t, hj, cn, fl}
395 case i0 && i1 && !i2 && i3 && i4:
396 return struct {
397 http.ResponseWriter
398 http.Hijacker
399 http.CloseNotifier
400 http.Flusher
401 io.ReaderFrom
402 }{t, hj, cn, fl, rf}
403 case i0 && i1 && i2 && !i3 && !i4:
404 return struct {
405 http.ResponseWriter
406 http.Hijacker
407 http.CloseNotifier
408 http.Pusher
409 }{t, hj, cn, pu}
410 case i0 && i1 && i2 && !i3 && i4:
411 return struct {
412 http.ResponseWriter
413 http.Hijacker
414 http.CloseNotifier
415 http.Pusher
416 io.ReaderFrom
417 }{t, hj, cn, pu, rf}
418 case i0 && i1 && i2 && i3 && !i4:
419 return struct {
420 http.ResponseWriter
421 http.Hijacker
422 http.CloseNotifier
423 http.Pusher
424 http.Flusher
425 }{t, hj, cn, pu, fl}
426 case i0 && i1 && i2 && i3 && i4:
427 return struct {
428 http.ResponseWriter
429 http.Hijacker
430 http.CloseNotifier
431 http.Pusher
432 http.Flusher
433 io.ReaderFrom
434 }{t, hj, cn, pu, fl, rf}
435 default:
436 return struct {
437 http.ResponseWriter
438 }{t}
439 }
440}
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 @@
1// Copyright 2018, OpenCensus Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package ochttp
16
17import (
18 "crypto/tls"
19 "net/http"
20 "net/http/httptrace"
21 "strings"
22
23 "go.opencensus.io/trace"
24)
25
26type spanAnnotator struct {
27 sp *trace.Span
28}
29
30// TODO: Remove NewSpanAnnotator at the next release.
31
32// NewSpanAnnotator returns a httptrace.ClientTrace which annotates
33// all emitted httptrace events on the provided Span.
34// Deprecated: Use NewSpanAnnotatingClientTrace instead
35func NewSpanAnnotator(r *http.Request, s *trace.Span) *httptrace.ClientTrace {
36 return NewSpanAnnotatingClientTrace(r, s)
37}
38
39// NewSpanAnnotatingClientTrace returns a httptrace.ClientTrace which annotates
40// all emitted httptrace events on the provided Span.
41func NewSpanAnnotatingClientTrace(_ *http.Request, s *trace.Span) *httptrace.ClientTrace {
42 sa := spanAnnotator{sp: s}
43
44 return &httptrace.ClientTrace{
45 GetConn: sa.getConn,
46 GotConn: sa.gotConn,
47 PutIdleConn: sa.putIdleConn,
48 GotFirstResponseByte: sa.gotFirstResponseByte,
49 Got100Continue: sa.got100Continue,
50 DNSStart: sa.dnsStart,
51 DNSDone: sa.dnsDone,
52 ConnectStart: sa.connectStart,
53 ConnectDone: sa.connectDone,
54 TLSHandshakeStart: sa.tlsHandshakeStart,
55 TLSHandshakeDone: sa.tlsHandshakeDone,
56 WroteHeaders: sa.wroteHeaders,
57 Wait100Continue: sa.wait100Continue,
58 WroteRequest: sa.wroteRequest,
59 }
60}
61
62func (s spanAnnotator) getConn(hostPort string) {
63 attrs := []trace.Attribute{
64 trace.StringAttribute("httptrace.get_connection.host_port", hostPort),
65 }
66 s.sp.Annotate(attrs, "GetConn")
67}
68
69func (s spanAnnotator) gotConn(info httptrace.GotConnInfo) {
70 attrs := []trace.Attribute{
71 trace.BoolAttribute("httptrace.got_connection.reused", info.Reused),
72 trace.BoolAttribute("httptrace.got_connection.was_idle", info.WasIdle),
73 }
74 if info.WasIdle {
75 attrs = append(attrs,
76 trace.StringAttribute("httptrace.got_connection.idle_time", info.IdleTime.String()))
77 }
78 s.sp.Annotate(attrs, "GotConn")
79}
80
81// PutIdleConn implements a httptrace.ClientTrace hook
82func (s spanAnnotator) putIdleConn(err error) {
83 var attrs []trace.Attribute
84 if err != nil {
85 attrs = append(attrs,
86 trace.StringAttribute("httptrace.put_idle_connection.error", err.Error()))
87 }
88 s.sp.Annotate(attrs, "PutIdleConn")
89}
90
91func (s spanAnnotator) gotFirstResponseByte() {
92 s.sp.Annotate(nil, "GotFirstResponseByte")
93}
94
95func (s spanAnnotator) got100Continue() {
96 s.sp.Annotate(nil, "Got100Continue")
97}
98
99func (s spanAnnotator) dnsStart(info httptrace.DNSStartInfo) {
100 attrs := []trace.Attribute{
101 trace.StringAttribute("httptrace.dns_start.host", info.Host),
102 }
103 s.sp.Annotate(attrs, "DNSStart")
104}
105
106func (s spanAnnotator) dnsDone(info httptrace.DNSDoneInfo) {
107 var addrs []string
108 for _, addr := range info.Addrs {
109 addrs = append(addrs, addr.String())
110 }
111 attrs := []trace.Attribute{
112 trace.StringAttribute("httptrace.dns_done.addrs", strings.Join(addrs, " , ")),
113 }
114 if info.Err != nil {
115 attrs = append(attrs,
116 trace.StringAttribute("httptrace.dns_done.error", info.Err.Error()))
117 }
118 s.sp.Annotate(attrs, "DNSDone")
119}
120
121func (s spanAnnotator) connectStart(network, addr string) {
122 attrs := []trace.Attribute{
123 trace.StringAttribute("httptrace.connect_start.network", network),
124 trace.StringAttribute("httptrace.connect_start.addr", addr),
125 }
126 s.sp.Annotate(attrs, "ConnectStart")
127}
128
129func (s spanAnnotator) connectDone(network, addr string, err error) {
130 attrs := []trace.Attribute{
131 trace.StringAttribute("httptrace.connect_done.network", network),
132 trace.StringAttribute("httptrace.connect_done.addr", addr),
133 }
134 if err != nil {
135 attrs = append(attrs,
136 trace.StringAttribute("httptrace.connect_done.error", err.Error()))
137 }
138 s.sp.Annotate(attrs, "ConnectDone")
139}
140
141func (s spanAnnotator) tlsHandshakeStart() {
142 s.sp.Annotate(nil, "TLSHandshakeStart")
143}
144
145func (s spanAnnotator) tlsHandshakeDone(_ tls.ConnectionState, err error) {
146 var attrs []trace.Attribute
147 if err != nil {
148 attrs = append(attrs,
149 trace.StringAttribute("httptrace.tls_handshake_done.error", err.Error()))
150 }
151 s.sp.Annotate(attrs, "TLSHandshakeDone")
152}
153
154func (s spanAnnotator) wroteHeaders() {
155 s.sp.Annotate(nil, "WroteHeaders")
156}
157
158func (s spanAnnotator) wait100Continue() {
159 s.sp.Annotate(nil, "Wait100Continue")
160}
161
162func (s spanAnnotator) wroteRequest(info httptrace.WroteRequestInfo) {
163 var attrs []trace.Attribute
164 if info.Err != nil {
165 attrs = append(attrs,
166 trace.StringAttribute("httptrace.wrote_request.error", info.Err.Error()))
167 }
168 s.sp.Annotate(attrs, "WroteRequest")
169}
diff --git a/vendor/go.opencensus.io/plugin/ochttp/stats.go b/vendor/go.opencensus.io/plugin/ochttp/stats.go
new file mode 100644
index 0000000..46dcc8e
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/stats.go
@@ -0,0 +1,265 @@
1// Copyright 2018, OpenCensus Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package ochttp
16
17import (
18 "go.opencensus.io/stats"
19 "go.opencensus.io/stats/view"
20 "go.opencensus.io/tag"
21)
22
23// The following client HTTP measures are supported for use in custom views.
24var (
25 // Deprecated: Use a Count aggregation over one of the other client measures to achieve the same effect.
26 ClientRequestCount = stats.Int64("opencensus.io/http/client/request_count", "Number of HTTP requests started", stats.UnitDimensionless)
27 // Deprecated: Use ClientSentBytes.
28 ClientRequestBytes = stats.Int64("opencensus.io/http/client/request_bytes", "HTTP request body size if set as ContentLength (uncompressed)", stats.UnitBytes)
29 // Deprecated: Use ClientReceivedBytes.
30 ClientResponseBytes = stats.Int64("opencensus.io/http/client/response_bytes", "HTTP response body size (uncompressed)", stats.UnitBytes)
31 // Deprecated: Use ClientRoundtripLatency.
32 ClientLatency = stats.Float64("opencensus.io/http/client/latency", "End-to-end latency", stats.UnitMilliseconds)
33)
34
35// Client measures supported for use in custom views.
36var (
37 ClientSentBytes = stats.Int64(
38 "opencensus.io/http/client/sent_bytes",
39 "Total bytes sent in request body (not including headers)",
40 stats.UnitBytes,
41 )
42 ClientReceivedBytes = stats.Int64(
43 "opencensus.io/http/client/received_bytes",
44 "Total bytes received in response bodies (not including headers but including error responses with bodies)",
45 stats.UnitBytes,
46 )
47 ClientRoundtripLatency = stats.Float64(
48 "opencensus.io/http/client/roundtrip_latency",
49 "Time between first byte of request headers sent to last byte of response received, or terminal error",
50 stats.UnitMilliseconds,
51 )
52)
53
54// The following server HTTP measures are supported for use in custom views:
55var (
56 ServerRequestCount = stats.Int64("opencensus.io/http/server/request_count", "Number of HTTP requests started", stats.UnitDimensionless)
57 ServerRequestBytes = stats.Int64("opencensus.io/http/server/request_bytes", "HTTP request body size if set as ContentLength (uncompressed)", stats.UnitBytes)
58 ServerResponseBytes = stats.Int64("opencensus.io/http/server/response_bytes", "HTTP response body size (uncompressed)", stats.UnitBytes)
59 ServerLatency = stats.Float64("opencensus.io/http/server/latency", "End-to-end latency", stats.UnitMilliseconds)
60)
61
62// The following tags are applied to stats recorded by this package. Host, Path
63// and Method are applied to all measures. StatusCode is not applied to
64// ClientRequestCount or ServerRequestCount, since it is recorded before the status is known.
65var (
66 // Host is the value of the HTTP Host header.
67 //
68 // The value of this tag can be controlled by the HTTP client, so you need
69 // to watch out for potentially generating high-cardinality labels in your
70 // metrics backend if you use this tag in views.
71 Host, _ = tag.NewKey("http.host")
72
73 // StatusCode is the numeric HTTP response status code,
74 // or "error" if a transport error occurred and no status code was read.
75 StatusCode, _ = tag.NewKey("http.status")
76
77 // Path is the URL path (not including query string) in the request.
78 //
79 // The value of this tag can be controlled by the HTTP client, so you need
80 // to watch out for potentially generating high-cardinality labels in your
81 // metrics backend if you use this tag in views.
82 Path, _ = tag.NewKey("http.path")
83
84 // Method is the HTTP method of the request, capitalized (GET, POST, etc.).
85 Method, _ = tag.NewKey("http.method")
86
87 // KeyServerRoute is a low cardinality string representing the logical
88 // handler of the request. This is usually the pattern registered on the a
89 // ServeMux (or similar string).
90 KeyServerRoute, _ = tag.NewKey("http_server_route")
91)
92
93// Client tag keys.
94var (
95 // KeyClientMethod is the HTTP method, capitalized (i.e. GET, POST, PUT, DELETE, etc.).
96 KeyClientMethod, _ = tag.NewKey("http_client_method")
97 // KeyClientPath is the URL path (not including query string).
98 KeyClientPath, _ = tag.NewKey("http_client_path")
99 // KeyClientStatus is the HTTP status code as an integer (e.g. 200, 404, 500.), or "error" if no response status line was received.
100 KeyClientStatus, _ = tag.NewKey("http_client_status")
101 // KeyClientHost is the value of the request Host header.
102 KeyClientHost, _ = tag.NewKey("http_client_host")
103)
104
105// Default distributions used by views in this package.
106var (
107 DefaultSizeDistribution = view.Distribution(0, 1024, 2048, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216, 67108864, 268435456, 1073741824, 4294967296)
108 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)
109)
110
111// Package ochttp provides some convenience views.
112// You still need to register these views for data to actually be collected.
113var (
114 ClientSentBytesDistribution = &view.View{
115 Name: "opencensus.io/http/client/sent_bytes",
116 Measure: ClientSentBytes,
117 Aggregation: DefaultSizeDistribution,
118 Description: "Total bytes sent in request body (not including headers), by HTTP method and response status",
119 TagKeys: []tag.Key{KeyClientMethod, KeyClientStatus},
120 }
121
122 ClientReceivedBytesDistribution = &view.View{
123 Name: "opencensus.io/http/client/received_bytes",
124 Measure: ClientReceivedBytes,
125 Aggregation: DefaultSizeDistribution,
126 Description: "Total bytes received in response bodies (not including headers but including error responses with bodies), by HTTP method and response status",
127 TagKeys: []tag.Key{KeyClientMethod, KeyClientStatus},
128 }
129
130 ClientRoundtripLatencyDistribution = &view.View{
131 Name: "opencensus.io/http/client/roundtrip_latency",
132 Measure: ClientRoundtripLatency,
133 Aggregation: DefaultLatencyDistribution,
134 Description: "End-to-end latency, by HTTP method and response status",
135 TagKeys: []tag.Key{KeyClientMethod, KeyClientStatus},
136 }
137
138 ClientCompletedCount = &view.View{
139 Name: "opencensus.io/http/client/completed_count",
140 Measure: ClientRoundtripLatency,
141 Aggregation: view.Count(),
142 Description: "Count of completed requests, by HTTP method and response status",
143 TagKeys: []tag.Key{KeyClientMethod, KeyClientStatus},
144 }
145)
146
147var (
148 // Deprecated: No direct replacement, but see ClientCompletedCount.
149 ClientRequestCountView = &view.View{
150 Name: "opencensus.io/http/client/request_count",
151 Description: "Count of HTTP requests started",
152 Measure: ClientRequestCount,
153 Aggregation: view.Count(),
154 }
155
156 // Deprecated: Use ClientSentBytesDistribution.
157 ClientRequestBytesView = &view.View{
158 Name: "opencensus.io/http/client/request_bytes",
159 Description: "Size distribution of HTTP request body",
160 Measure: ClientSentBytes,
161 Aggregation: DefaultSizeDistribution,
162 }
163
164 // Deprecated: Use ClientReceivedBytesDistribution.
165 ClientResponseBytesView = &view.View{
166 Name: "opencensus.io/http/client/response_bytes",
167 Description: "Size distribution of HTTP response body",
168 Measure: ClientReceivedBytes,
169 Aggregation: DefaultSizeDistribution,
170 }
171
172 // Deprecated: Use ClientRoundtripLatencyDistribution.
173 ClientLatencyView = &view.View{
174 Name: "opencensus.io/http/client/latency",
175 Description: "Latency distribution of HTTP requests",
176 Measure: ClientRoundtripLatency,
177 Aggregation: DefaultLatencyDistribution,
178 }
179
180 // Deprecated: Use ClientCompletedCount.
181 ClientRequestCountByMethod = &view.View{
182 Name: "opencensus.io/http/client/request_count_by_method",
183 Description: "Client request count by HTTP method",
184 TagKeys: []tag.Key{Method},
185 Measure: ClientSentBytes,
186 Aggregation: view.Count(),
187 }
188
189 // Deprecated: Use ClientCompletedCount.
190 ClientResponseCountByStatusCode = &view.View{
191 Name: "opencensus.io/http/client/response_count_by_status_code",
192 Description: "Client response count by status code",
193 TagKeys: []tag.Key{StatusCode},
194 Measure: ClientRoundtripLatency,
195 Aggregation: view.Count(),
196 }
197)
198
199var (
200 ServerRequestCountView = &view.View{
201 Name: "opencensus.io/http/server/request_count",
202 Description: "Count of HTTP requests started",
203 Measure: ServerRequestCount,
204 Aggregation: view.Count(),
205 }
206
207 ServerRequestBytesView = &view.View{
208 Name: "opencensus.io/http/server/request_bytes",
209 Description: "Size distribution of HTTP request body",
210 Measure: ServerRequestBytes,
211 Aggregation: DefaultSizeDistribution,
212 }
213
214 ServerResponseBytesView = &view.View{
215 Name: "opencensus.io/http/server/response_bytes",
216 Description: "Size distribution of HTTP response body",
217 Measure: ServerResponseBytes,
218 Aggregation: DefaultSizeDistribution,
219 }
220
221 ServerLatencyView = &view.View{
222 Name: "opencensus.io/http/server/latency",
223 Description: "Latency distribution of HTTP requests",
224 Measure: ServerLatency,
225 Aggregation: DefaultLatencyDistribution,
226 }
227
228 ServerRequestCountByMethod = &view.View{
229 Name: "opencensus.io/http/server/request_count_by_method",
230 Description: "Server request count by HTTP method",
231 TagKeys: []tag.Key{Method},
232 Measure: ServerRequestCount,
233 Aggregation: view.Count(),
234 }
235
236 ServerResponseCountByStatusCode = &view.View{
237 Name: "opencensus.io/http/server/response_count_by_status_code",
238 Description: "Server response count by status code",
239 TagKeys: []tag.Key{StatusCode},
240 Measure: ServerLatency,
241 Aggregation: view.Count(),
242 }
243)
244
245// DefaultClientViews are the default client views provided by this package.
246// Deprecated: No replacement. Register the views you would like individually.
247var DefaultClientViews = []*view.View{
248 ClientRequestCountView,
249 ClientRequestBytesView,
250 ClientResponseBytesView,
251 ClientLatencyView,
252 ClientRequestCountByMethod,
253 ClientResponseCountByStatusCode,
254}
255
256// DefaultServerViews are the default server views provided by this package.
257// Deprecated: No replacement. Register the views you would like individually.
258var DefaultServerViews = []*view.View{
259 ServerRequestCountView,
260 ServerRequestBytesView,
261 ServerResponseBytesView,
262 ServerLatencyView,
263 ServerRequestCountByMethod,
264 ServerResponseCountByStatusCode,
265}
diff --git a/vendor/go.opencensus.io/plugin/ochttp/trace.go b/vendor/go.opencensus.io/plugin/ochttp/trace.go
new file mode 100644
index 0000000..819a2d5
--- /dev/null
+++ b/vendor/go.opencensus.io/plugin/ochttp/trace.go
@@ -0,0 +1,228 @@
1// Copyright 2018, OpenCensus Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package ochttp
16
17import (
18 "io"
19 "net/http"
20 "net/http/httptrace"
21
22 "go.opencensus.io/plugin/ochttp/propagation/b3"
23 "go.opencensus.io/trace"
24 "go.opencensus.io/trace/propagation"
25)
26
27// TODO(jbd): Add godoc examples.
28
29var defaultFormat propagation.HTTPFormat = &b3.HTTPFormat{}
30
31// Attributes recorded on the span for the requests.
32// Only trace exporters will need them.
33const (
34 HostAttribute = "http.host"
35 MethodAttribute = "http.method"
36 PathAttribute = "http.path"
37 UserAgentAttribute = "http.user_agent"
38 StatusCodeAttribute = "http.status_code"
39)
40
41type traceTransport struct {
42 base http.RoundTripper
43 startOptions trace.StartOptions
44 format propagation.HTTPFormat
45 formatSpanName func(*http.Request) string
46 newClientTrace func(*http.Request, *trace.Span) *httptrace.ClientTrace
47}
48
49// TODO(jbd): Add message events for request and response size.
50
51// RoundTrip creates a trace.Span and inserts it into the outgoing request's headers.
52// The created span can follow a parent span, if a parent is presented in
53// the request's context.
54func (t *traceTransport) RoundTrip(req *http.Request) (*http.Response, error) {
55 name := t.formatSpanName(req)
56 // TODO(jbd): Discuss whether we want to prefix
57 // outgoing requests with Sent.
58 ctx, span := trace.StartSpan(req.Context(), name,
59 trace.WithSampler(t.startOptions.Sampler),
60 trace.WithSpanKind(trace.SpanKindClient))
61
62 if t.newClientTrace != nil {
63 req = req.WithContext(httptrace.WithClientTrace(ctx, t.newClientTrace(req, span)))
64 } else {
65 req = req.WithContext(ctx)
66 }
67
68 if t.format != nil {
69 // SpanContextToRequest will modify its Request argument, which is
70 // contrary to the contract for http.RoundTripper, so we need to
71 // pass it a copy of the Request.
72 // However, the Request struct itself was already copied by
73 // the WithContext calls above and so we just need to copy the header.
74 header := make(http.Header)
75 for k, v := range req.Header {
76 header[k] = v
77 }
78 req.Header = header
79 t.format.SpanContextToRequest(span.SpanContext(), req)
80 }
81
82 span.AddAttributes(requestAttrs(req)...)
83 resp, err := t.base.RoundTrip(req)
84 if err != nil {
85 span.SetStatus(trace.Status{Code: trace.StatusCodeUnknown, Message: err.Error()})
86 span.End()
87 return resp, err
88 }
89
90 span.AddAttributes(responseAttrs(resp)...)
91 span.SetStatus(TraceStatus(resp.StatusCode, resp.Status))
92
93 // span.End() will be invoked after
94 // a read from resp.Body returns io.EOF or when
95 // resp.Body.Close() is invoked.
96 resp.Body = &bodyTracker{rc: resp.Body, span: span}
97 return resp, err
98}
99
100// bodyTracker wraps a response.Body and invokes
101// trace.EndSpan on encountering io.EOF on reading
102// the body of the original response.
103type bodyTracker struct {
104 rc io.ReadCloser
105 span *trace.Span
106}
107
108var _ io.ReadCloser = (*bodyTracker)(nil)
109
110func (bt *bodyTracker) Read(b []byte) (int, error) {
111 n, err := bt.rc.Read(b)
112
113 switch err {
114 case nil:
115 return n, nil
116 case io.EOF:
117 bt.span.End()
118 default:
119 // For all other errors, set the span status
120 bt.span.SetStatus(trace.Status{
121 // Code 2 is the error code for Internal server error.
122 Code: 2,
123 Message: err.Error(),
124 })
125 }
126 return n, err
127}
128
129func (bt *bodyTracker) Close() error {
130 // Invoking endSpan on Close will help catch the cases
131 // in which a read returned a non-nil error, we set the
132 // span status but didn't end the span.
133 bt.span.End()
134 return bt.rc.Close()
135}
136
137// CancelRequest cancels an in-flight request by closing its connection.
138func (t *traceTransport) CancelRequest(req *http.Request) {
139 type canceler interface {
140 CancelRequest(*http.Request)
141 }
142 if cr, ok := t.base.(canceler); ok {
143 cr.CancelRequest(req)
144 }
145}
146
147func spanNameFromURL(req *http.Request) string {
148 return req.URL.Path
149}
150
151func requestAttrs(r *http.Request) []trace.Attribute {
152 return []trace.Attribute{
153 trace.StringAttribute(PathAttribute, r.URL.Path),
154 trace.StringAttribute(HostAttribute, r.URL.Host),
155 trace.StringAttribute(MethodAttribute, r.Method),
156 trace.StringAttribute(UserAgentAttribute, r.UserAgent()),
157 }
158}
159
160func responseAttrs(resp *http.Response) []trace.Attribute {
161 return []trace.Attribute{
162 trace.Int64Attribute(StatusCodeAttribute, int64(resp.StatusCode)),
163 }
164}
165
166// TraceStatus is a utility to convert the HTTP status code to a trace.Status that
167// represents the outcome as closely as possible.
168func TraceStatus(httpStatusCode int, statusLine string) trace.Status {
169 var code int32
170 if httpStatusCode < 200 || httpStatusCode >= 400 {
171 code = trace.StatusCodeUnknown
172 }
173 switch httpStatusCode {
174 case 499:
175 code = trace.StatusCodeCancelled
176 case http.StatusBadRequest:
177 code = trace.StatusCodeInvalidArgument
178 case http.StatusGatewayTimeout:
179 code = trace.StatusCodeDeadlineExceeded
180 case http.StatusNotFound:
181 code = trace.StatusCodeNotFound
182 case http.StatusForbidden:
183 code = trace.StatusCodePermissionDenied
184 case http.StatusUnauthorized: // 401 is actually unauthenticated.
185 code = trace.StatusCodeUnauthenticated
186 case http.StatusTooManyRequests:
187 code = trace.StatusCodeResourceExhausted
188 case http.StatusNotImplemented:
189 code = trace.StatusCodeUnimplemented
190 case http.StatusServiceUnavailable:
191 code = trace.StatusCodeUnavailable
192 case http.StatusOK:
193 code = trace.StatusCodeOK
194 }
195 return trace.Status{Code: code, Message: codeToStr[code]}
196}
197
198var codeToStr = map[int32]string{
199 trace.StatusCodeOK: `OK`,
200 trace.StatusCodeCancelled: `CANCELLED`,
201 trace.StatusCodeUnknown: `UNKNOWN`,
202 trace.StatusCodeInvalidArgument: `INVALID_ARGUMENT`,
203 trace.StatusCodeDeadlineExceeded: `DEADLINE_EXCEEDED`,
204 trace.StatusCodeNotFound: `NOT_FOUND`,
205 trace.StatusCodeAlreadyExists: `ALREADY_EXISTS`,
206 trace.StatusCodePermissionDenied: `PERMISSION_DENIED`,
207 trace.StatusCodeResourceExhausted: `RESOURCE_EXHAUSTED`,
208 trace.StatusCodeFailedPrecondition: `FAILED_PRECONDITION`,
209 trace.StatusCodeAborted: `ABORTED`,
210 trace.StatusCodeOutOfRange: `OUT_OF_RANGE`,
211 trace.StatusCodeUnimplemented: `UNIMPLEMENTED`,
212 trace.StatusCodeInternal: `INTERNAL`,
213 trace.StatusCodeUnavailable: `UNAVAILABLE`,
214 trace.StatusCodeDataLoss: `DATA_LOSS`,
215 trace.StatusCodeUnauthenticated: `UNAUTHENTICATED`,
216}
217
218func isHealthEndpoint(path string) bool {
219 // Health checking is pretty frequent and
220 // traces collected for health endpoints
221 // can be extremely noisy and expensive.
222 // Disable canonical health checking endpoints
223 // like /healthz and /_ah/health for now.
224 if path == "/healthz" || path == "/_ah/health" {
225 return true
226 }
227 return false
228}