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/trace.go | |
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/trace.go')
-rw-r--r-- | vendor/go.opencensus.io/plugin/ochttp/trace.go | 228 |
1 files changed, 228 insertions, 0 deletions
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 | } | ||