1
2
3
4
5
6
7
8
9
10
11
12
13
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
32
33
34
35
36
37
38
39
40
41
42
43
44 type Handler struct {
45
46
47 Propagation propagation.HTTPFormat
48
49
50 Handler http.Handler
51
52
53
54
55
56
57 StartOptions trace.StartOptions
58
59
60
61 GetStartOptions func(*http.Request) trace.StartOptions
62
63
64
65
66
67 IsPublicEndpoint bool
68
69
70
71
72 FormatSpanName func(*http.Request) string
73
74
75
76
77
78 IsHealthEndpoint func(*http.Request) bool
79 }
80
81 func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
82 var tags addedTags
83 r, traceEnd := h.startTrace(w, r)
84 defer traceEnd()
85 w, statsEnd := h.startStats(w, r)
86 defer statsEnd(&tags)
87 handler := h.Handler
88 if handler == nil {
89 handler = http.DefaultServeMux
90 }
91 r = r.WithContext(context.WithValue(r.Context(), addedTagsKey{}, &tags))
92 handler.ServeHTTP(w, r)
93 }
94
95 func (h *Handler) startTrace(w http.ResponseWriter, r *http.Request) (*http.Request, func()) {
96 if h.IsHealthEndpoint != nil && h.IsHealthEndpoint(r) || isHealthEndpoint(r.URL.Path) {
97 return r, func() {}
98 }
99 var name string
100 if h.FormatSpanName == nil {
101 name = spanNameFromURL(r)
102 } else {
103 name = h.FormatSpanName(r)
104 }
105 ctx := r.Context()
106
107 startOpts := h.StartOptions
108 if h.GetStartOptions != nil {
109 startOpts = h.GetStartOptions(r)
110 }
111
112 var span *trace.Span
113 sc, ok := h.extractSpanContext(r)
114 if ok && !h.IsPublicEndpoint {
115 ctx, span = trace.StartSpanWithRemoteParent(ctx, name, sc,
116 trace.WithSampler(startOpts.Sampler),
117 trace.WithSpanKind(trace.SpanKindServer))
118 } else {
119 ctx, span = trace.StartSpan(ctx, name,
120 trace.WithSampler(startOpts.Sampler),
121 trace.WithSpanKind(trace.SpanKindServer),
122 )
123 if ok {
124 span.AddLink(trace.Link{
125 TraceID: sc.TraceID,
126 SpanID: sc.SpanID,
127 Type: trace.LinkTypeParent,
128 Attributes: nil,
129 })
130 }
131 }
132 span.AddAttributes(requestAttrs(r)...)
133 if r.Body == nil {
134
135 } else if r.ContentLength > 0 {
136 span.AddMessageReceiveEvent(0,
137 r.ContentLength, -1)
138 }
139 return r.WithContext(ctx), span.End
140 }
141
142 func (h *Handler) extractSpanContext(r *http.Request) (trace.SpanContext, bool) {
143 if h.Propagation == nil {
144 return defaultFormat.SpanContextFromRequest(r)
145 }
146 return h.Propagation.SpanContextFromRequest(r)
147 }
148
149 func (h *Handler) startStats(w http.ResponseWriter, r *http.Request) (http.ResponseWriter, func(tags *addedTags)) {
150 ctx, _ := tag.New(r.Context(),
151 tag.Upsert(Host, r.Host),
152 tag.Upsert(Path, r.URL.Path),
153 tag.Upsert(Method, r.Method))
154 track := &trackingResponseWriter{
155 start: time.Now(),
156 ctx: ctx,
157 writer: w,
158 }
159 if r.Body == nil {
160
161 track.reqSize = -1
162 } else if r.ContentLength > 0 {
163 track.reqSize = r.ContentLength
164 }
165 stats.Record(ctx, ServerRequestCount.M(1))
166 return track.wrappedResponseWriter(), track.end
167 }
168
169 type trackingResponseWriter struct {
170 ctx context.Context
171 reqSize int64
172 respSize int64
173 start time.Time
174 statusCode int
175 statusLine string
176 endOnce sync.Once
177 writer http.ResponseWriter
178 }
179
180
181 var _ http.ResponseWriter = (*trackingResponseWriter)(nil)
182
183 func (t *trackingResponseWriter) end(tags *addedTags) {
184 t.endOnce.Do(func() {
185 if t.statusCode == 0 {
186 t.statusCode = 200
187 }
188
189 span := trace.FromContext(t.ctx)
190 span.SetStatus(TraceStatus(t.statusCode, t.statusLine))
191 span.AddAttributes(trace.Int64Attribute(StatusCodeAttribute, int64(t.statusCode)))
192
193 m := []stats.Measurement{
194 ServerLatency.M(float64(time.Since(t.start)) / float64(time.Millisecond)),
195 ServerResponseBytes.M(t.respSize),
196 }
197 if t.reqSize >= 0 {
198 m = append(m, ServerRequestBytes.M(t.reqSize))
199 }
200 allTags := make([]tag.Mutator, len(tags.t)+1)
201 allTags[0] = tag.Upsert(StatusCode, strconv.Itoa(t.statusCode))
202 copy(allTags[1:], tags.t)
203 stats.RecordWithTags(t.ctx, allTags, m...)
204 })
205 }
206
207 func (t *trackingResponseWriter) Header() http.Header {
208 return t.writer.Header()
209 }
210
211 func (t *trackingResponseWriter) Write(data []byte) (int, error) {
212 n, err := t.writer.Write(data)
213 t.respSize += int64(n)
214
215 span := trace.FromContext(t.ctx)
216 span.AddMessageSendEvent(0 , int64(n), -1)
217 return n, err
218 }
219
220 func (t *trackingResponseWriter) WriteHeader(statusCode int) {
221 t.writer.WriteHeader(statusCode)
222 t.statusCode = statusCode
223 t.statusLine = http.StatusText(t.statusCode)
224 }
225
226
227
228
229
230
231
232 func (t *trackingResponseWriter) wrappedResponseWriter() http.ResponseWriter {
233 var (
234 hj, i0 = t.writer.(http.Hijacker)
235 cn, i1 = t.writer.(http.CloseNotifier)
236 pu, i2 = t.writer.(http.Pusher)
237 fl, i3 = t.writer.(http.Flusher)
238 rf, i4 = t.writer.(io.ReaderFrom)
239 )
240
241 switch {
242 case !i0 && !i1 && !i2 && !i3 && !i4:
243 return struct {
244 http.ResponseWriter
245 }{t}
246 case !i0 && !i1 && !i2 && !i3 && i4:
247 return struct {
248 http.ResponseWriter
249 io.ReaderFrom
250 }{t, rf}
251 case !i0 && !i1 && !i2 && i3 && !i4:
252 return struct {
253 http.ResponseWriter
254 http.Flusher
255 }{t, fl}
256 case !i0 && !i1 && !i2 && i3 && i4:
257 return struct {
258 http.ResponseWriter
259 http.Flusher
260 io.ReaderFrom
261 }{t, fl, rf}
262 case !i0 && !i1 && i2 && !i3 && !i4:
263 return struct {
264 http.ResponseWriter
265 http.Pusher
266 }{t, pu}
267 case !i0 && !i1 && i2 && !i3 && i4:
268 return struct {
269 http.ResponseWriter
270 http.Pusher
271 io.ReaderFrom
272 }{t, pu, rf}
273 case !i0 && !i1 && i2 && i3 && !i4:
274 return struct {
275 http.ResponseWriter
276 http.Pusher
277 http.Flusher
278 }{t, pu, fl}
279 case !i0 && !i1 && i2 && i3 && i4:
280 return struct {
281 http.ResponseWriter
282 http.Pusher
283 http.Flusher
284 io.ReaderFrom
285 }{t, pu, fl, rf}
286 case !i0 && i1 && !i2 && !i3 && !i4:
287 return struct {
288 http.ResponseWriter
289 http.CloseNotifier
290 }{t, cn}
291 case !i0 && i1 && !i2 && !i3 && i4:
292 return struct {
293 http.ResponseWriter
294 http.CloseNotifier
295 io.ReaderFrom
296 }{t, cn, rf}
297 case !i0 && i1 && !i2 && i3 && !i4:
298 return struct {
299 http.ResponseWriter
300 http.CloseNotifier
301 http.Flusher
302 }{t, cn, fl}
303 case !i0 && i1 && !i2 && i3 && i4:
304 return struct {
305 http.ResponseWriter
306 http.CloseNotifier
307 http.Flusher
308 io.ReaderFrom
309 }{t, cn, fl, rf}
310 case !i0 && i1 && i2 && !i3 && !i4:
311 return struct {
312 http.ResponseWriter
313 http.CloseNotifier
314 http.Pusher
315 }{t, cn, pu}
316 case !i0 && i1 && i2 && !i3 && i4:
317 return struct {
318 http.ResponseWriter
319 http.CloseNotifier
320 http.Pusher
321 io.ReaderFrom
322 }{t, cn, pu, rf}
323 case !i0 && i1 && i2 && i3 && !i4:
324 return struct {
325 http.ResponseWriter
326 http.CloseNotifier
327 http.Pusher
328 http.Flusher
329 }{t, cn, pu, fl}
330 case !i0 && i1 && i2 && i3 && i4:
331 return struct {
332 http.ResponseWriter
333 http.CloseNotifier
334 http.Pusher
335 http.Flusher
336 io.ReaderFrom
337 }{t, cn, pu, fl, rf}
338 case i0 && !i1 && !i2 && !i3 && !i4:
339 return struct {
340 http.ResponseWriter
341 http.Hijacker
342 }{t, hj}
343 case i0 && !i1 && !i2 && !i3 && i4:
344 return struct {
345 http.ResponseWriter
346 http.Hijacker
347 io.ReaderFrom
348 }{t, hj, rf}
349 case i0 && !i1 && !i2 && i3 && !i4:
350 return struct {
351 http.ResponseWriter
352 http.Hijacker
353 http.Flusher
354 }{t, hj, fl}
355 case i0 && !i1 && !i2 && i3 && i4:
356 return struct {
357 http.ResponseWriter
358 http.Hijacker
359 http.Flusher
360 io.ReaderFrom
361 }{t, hj, fl, rf}
362 case i0 && !i1 && i2 && !i3 && !i4:
363 return struct {
364 http.ResponseWriter
365 http.Hijacker
366 http.Pusher
367 }{t, hj, pu}
368 case i0 && !i1 && i2 && !i3 && i4:
369 return struct {
370 http.ResponseWriter
371 http.Hijacker
372 http.Pusher
373 io.ReaderFrom
374 }{t, hj, pu, rf}
375 case i0 && !i1 && i2 && i3 && !i4:
376 return struct {
377 http.ResponseWriter
378 http.Hijacker
379 http.Pusher
380 http.Flusher
381 }{t, hj, pu, fl}
382 case i0 && !i1 && i2 && i3 && i4:
383 return struct {
384 http.ResponseWriter
385 http.Hijacker
386 http.Pusher
387 http.Flusher
388 io.ReaderFrom
389 }{t, hj, pu, fl, rf}
390 case i0 && i1 && !i2 && !i3 && !i4:
391 return struct {
392 http.ResponseWriter
393 http.Hijacker
394 http.CloseNotifier
395 }{t, hj, cn}
396 case i0 && i1 && !i2 && !i3 && i4:
397 return struct {
398 http.ResponseWriter
399 http.Hijacker
400 http.CloseNotifier
401 io.ReaderFrom
402 }{t, hj, cn, rf}
403 case i0 && i1 && !i2 && i3 && !i4:
404 return struct {
405 http.ResponseWriter
406 http.Hijacker
407 http.CloseNotifier
408 http.Flusher
409 }{t, hj, cn, fl}
410 case i0 && i1 && !i2 && i3 && i4:
411 return struct {
412 http.ResponseWriter
413 http.Hijacker
414 http.CloseNotifier
415 http.Flusher
416 io.ReaderFrom
417 }{t, hj, cn, fl, rf}
418 case i0 && i1 && i2 && !i3 && !i4:
419 return struct {
420 http.ResponseWriter
421 http.Hijacker
422 http.CloseNotifier
423 http.Pusher
424 }{t, hj, cn, pu}
425 case i0 && i1 && i2 && !i3 && i4:
426 return struct {
427 http.ResponseWriter
428 http.Hijacker
429 http.CloseNotifier
430 http.Pusher
431 io.ReaderFrom
432 }{t, hj, cn, pu, rf}
433 case i0 && i1 && i2 && i3 && !i4:
434 return struct {
435 http.ResponseWriter
436 http.Hijacker
437 http.CloseNotifier
438 http.Pusher
439 http.Flusher
440 }{t, hj, cn, pu, fl}
441 case i0 && i1 && i2 && i3 && i4:
442 return struct {
443 http.ResponseWriter
444 http.Hijacker
445 http.CloseNotifier
446 http.Pusher
447 http.Flusher
448 io.ReaderFrom
449 }{t, hj, cn, pu, fl, rf}
450 default:
451 return struct {
452 http.ResponseWriter
453 }{t}
454 }
455 }
456
View as plain text