diff options
author | Nathan Dench <ndenc2@gmail.com> | 2019-05-24 15:16:44 +1000 |
---|---|---|
committer | Nathan Dench <ndenc2@gmail.com> | 2019-05-24 15:16:44 +1000 |
commit | 107c1cdb09c575aa2f61d97f48d8587eb6bada4c (patch) | |
tree | ca7d008643efc555c388baeaf1d986e0b6b3e28c /vendor/go.opencensus.io/plugin/ochttp | |
parent | 844b5a68d8af4791755b8f0ad293cc99f5959183 (diff) | |
download | terraform-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.go | 117 | ||||
-rw-r--r-- | vendor/go.opencensus.io/plugin/ochttp/client_stats.go | 135 | ||||
-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 | 51 | ||||
-rw-r--r-- | vendor/go.opencensus.io/plugin/ochttp/server.go | 440 | ||||
-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 | 265 | ||||
-rw-r--r-- | vendor/go.opencensus.io/plugin/ochttp/trace.go | 228 |
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 | |||
15 | package ochttp | ||
16 | |||
17 | import ( | ||
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. | ||
31 | type 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. | ||
68 | func (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 | |||
102 | func (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. | ||
110 | func (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 | |||
15 | package ochttp | ||
16 | |||
17 | import ( | ||
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. | ||
30 | type statsTransport struct { | ||
31 | base http.RoundTripper | ||
32 | } | ||
33 | |||
34 | // RoundTrip implements http.RoundTripper, delegating to Base and recording stats for the request. | ||
35 | func (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. | ||
75 | func (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 | |||
84 | type 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 | |||
94 | var _ io.ReadCloser = (*tracker)(nil) | ||
95 | |||
96 | func (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 | |||
117 | func (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 | |||
129 | func (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. | ||
19 | package ochttp // import "go.opencensus.io/plugin/ochttp" | ||
diff --git a/vendor/go.opencensus.io/plugin/ochttp/propagation/b3/b3.go b/vendor/go.opencensus.io/plugin/ochttp/propagation/b3/b3.go new file mode 100644 index 0000000..f777772 --- /dev/null +++ b/vendor/go.opencensus.io/plugin/ochttp/propagation/b3/b3.go | |||
@@ -0,0 +1,123 @@ | |||
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. | ||
18 | package b3 // import "go.opencensus.io/plugin/ochttp/propagation/b3" | ||
19 | |||
20 | import ( | ||
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. | ||
29 | const ( | ||
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. | ||
43 | type HTTPFormat struct{} | ||
44 | |||
45 | var _ propagation.HTTPFormat = (*HTTPFormat)(nil) | ||
46 | |||
47 | // SpanContextFromRequest extracts a B3 span context from incoming requests. | ||
48 | func (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. | ||
66 | func 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. | ||
88 | func 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. | ||
102 | func 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. | ||
112 | func (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 | |||
15 | package ochttp | ||
16 | |||
17 | import ( | ||
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. | ||
25 | func 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. | ||
38 | type taggedHandlerFunc func(w http.ResponseWriter, r *http.Request) []tag.Mutator | ||
39 | |||
40 | func (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 | |||
47 | type addedTagsKey struct{} | ||
48 | |||
49 | type 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 | |||
15 | package ochttp | ||
16 | |||
17 | import ( | ||
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. | ||
44 | type 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 | |||
75 | func (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 | |||
89 | func (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 | |||
130 | func (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 | |||
137 | func (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 | |||
157 | type 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 | ||
169 | var _ http.ResponseWriter = (*trackingResponseWriter)(nil) | ||
170 | |||
171 | var logTagsErrorOnce sync.Once | ||
172 | |||
173 | func (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 | |||
197 | func (t *trackingResponseWriter) Header() http.Header { | ||
198 | return t.writer.Header() | ||
199 | } | ||
200 | |||
201 | func (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 | |||
207 | func (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. | ||
217 | func (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 | |||
15 | package ochttp | ||
16 | |||
17 | import ( | ||
18 | "crypto/tls" | ||
19 | "net/http" | ||
20 | "net/http/httptrace" | ||
21 | "strings" | ||
22 | |||
23 | "go.opencensus.io/trace" | ||
24 | ) | ||
25 | |||
26 | type 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 | ||
35 | func 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. | ||
41 | func 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 | |||
62 | func (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 | |||
69 | func (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 | ||
82 | func (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 | |||
91 | func (s spanAnnotator) gotFirstResponseByte() { | ||
92 | s.sp.Annotate(nil, "GotFirstResponseByte") | ||
93 | } | ||
94 | |||
95 | func (s spanAnnotator) got100Continue() { | ||
96 | s.sp.Annotate(nil, "Got100Continue") | ||
97 | } | ||
98 | |||
99 | func (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 | |||
106 | func (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 | |||
121 | func (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 | |||
129 | func (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 | |||
141 | func (s spanAnnotator) tlsHandshakeStart() { | ||
142 | s.sp.Annotate(nil, "TLSHandshakeStart") | ||
143 | } | ||
144 | |||
145 | func (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 | |||
154 | func (s spanAnnotator) wroteHeaders() { | ||
155 | s.sp.Annotate(nil, "WroteHeaders") | ||
156 | } | ||
157 | |||
158 | func (s spanAnnotator) wait100Continue() { | ||
159 | s.sp.Annotate(nil, "Wait100Continue") | ||
160 | } | ||
161 | |||
162 | func (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 | |||
15 | package ochttp | ||
16 | |||
17 | import ( | ||
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. | ||
24 | var ( | ||
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. | ||
36 | var ( | ||
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: | ||
55 | var ( | ||
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. | ||
65 | var ( | ||
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. | ||
94 | var ( | ||
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. | ||
106 | var ( | ||
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. | ||
113 | var ( | ||
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 | |||
147 | var ( | ||
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 | |||
199 | var ( | ||
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. | ||
247 | var 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. | ||
258 | var 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 | |||
15 | package ochttp | ||
16 | |||
17 | import ( | ||
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 | |||
29 | var defaultFormat propagation.HTTPFormat = &b3.HTTPFormat{} | ||
30 | |||
31 | // Attributes recorded on the span for the requests. | ||
32 | // Only trace exporters will need them. | ||
33 | const ( | ||
34 | HostAttribute = "http.host" | ||
35 | MethodAttribute = "http.method" | ||
36 | PathAttribute = "http.path" | ||
37 | UserAgentAttribute = "http.user_agent" | ||
38 | StatusCodeAttribute = "http.status_code" | ||
39 | ) | ||
40 | |||
41 | type 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. | ||
54 | func (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. | ||
103 | type bodyTracker struct { | ||
104 | rc io.ReadCloser | ||
105 | span *trace.Span | ||
106 | } | ||
107 | |||
108 | var _ io.ReadCloser = (*bodyTracker)(nil) | ||
109 | |||
110 | func (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 | |||
129 | func (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. | ||
138 | func (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 | |||
147 | func spanNameFromURL(req *http.Request) string { | ||
148 | return req.URL.Path | ||
149 | } | ||
150 | |||
151 | func 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 | |||
160 | func 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. | ||
168 | func 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 | |||
198 | var 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 | |||
218 | func 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 | } | ||