server.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  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. package ochttp
  15. import (
  16. "context"
  17. "io"
  18. "net/http"
  19. "strconv"
  20. "sync"
  21. "time"
  22. "go.opencensus.io/stats"
  23. "go.opencensus.io/tag"
  24. "go.opencensus.io/trace"
  25. "go.opencensus.io/trace/propagation"
  26. )
  27. // Handler is an http.Handler wrapper to instrument your HTTP server with
  28. // OpenCensus. It supports both stats and tracing.
  29. //
  30. // # Tracing
  31. //
  32. // This handler is aware of the incoming request's span, reading it from request
  33. // headers as configured using the Propagation field.
  34. // The extracted span can be accessed from the incoming request's
  35. // context.
  36. //
  37. // span := trace.FromContext(r.Context())
  38. //
  39. // The server span will be automatically ended at the end of ServeHTTP.
  40. type Handler struct {
  41. // Propagation defines how traces are propagated. If unspecified,
  42. // B3 propagation will be used.
  43. Propagation propagation.HTTPFormat
  44. // Handler is the handler used to handle the incoming request.
  45. Handler http.Handler
  46. // StartOptions are applied to the span started by this Handler around each
  47. // request.
  48. //
  49. // StartOptions.SpanKind will always be set to trace.SpanKindServer
  50. // for spans started by this transport.
  51. StartOptions trace.StartOptions
  52. // GetStartOptions allows to set start options per request. If set,
  53. // StartOptions is going to be ignored.
  54. GetStartOptions func(*http.Request) trace.StartOptions
  55. // IsPublicEndpoint should be set to true for publicly accessible HTTP(S)
  56. // servers. If true, any trace metadata set on the incoming request will
  57. // be added as a linked trace instead of being added as a parent of the
  58. // current trace.
  59. IsPublicEndpoint bool
  60. // FormatSpanName holds the function to use for generating the span name
  61. // from the information found in the incoming HTTP Request. By default the
  62. // name equals the URL Path.
  63. FormatSpanName func(*http.Request) string
  64. // IsHealthEndpoint holds the function to use for determining if the
  65. // incoming HTTP request should be considered a health check. This is in
  66. // addition to the private isHealthEndpoint func which may also indicate
  67. // tracing should be skipped.
  68. IsHealthEndpoint func(*http.Request) bool
  69. }
  70. func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  71. var tags addedTags
  72. r, traceEnd := h.startTrace(w, r)
  73. defer traceEnd()
  74. w, statsEnd := h.startStats(w, r)
  75. defer statsEnd(&tags)
  76. handler := h.Handler
  77. if handler == nil {
  78. handler = http.DefaultServeMux
  79. }
  80. r = r.WithContext(context.WithValue(r.Context(), addedTagsKey{}, &tags))
  81. handler.ServeHTTP(w, r)
  82. }
  83. func (h *Handler) startTrace(w http.ResponseWriter, r *http.Request) (*http.Request, func()) {
  84. if h.IsHealthEndpoint != nil && h.IsHealthEndpoint(r) || isHealthEndpoint(r.URL.Path) {
  85. return r, func() {}
  86. }
  87. var name string
  88. if h.FormatSpanName == nil {
  89. name = spanNameFromURL(r)
  90. } else {
  91. name = h.FormatSpanName(r)
  92. }
  93. ctx := r.Context()
  94. startOpts := h.StartOptions
  95. if h.GetStartOptions != nil {
  96. startOpts = h.GetStartOptions(r)
  97. }
  98. var span *trace.Span
  99. sc, ok := h.extractSpanContext(r)
  100. if ok && !h.IsPublicEndpoint {
  101. ctx, span = trace.StartSpanWithRemoteParent(ctx, name, sc,
  102. trace.WithSampler(startOpts.Sampler),
  103. trace.WithSpanKind(trace.SpanKindServer))
  104. } else {
  105. ctx, span = trace.StartSpan(ctx, name,
  106. trace.WithSampler(startOpts.Sampler),
  107. trace.WithSpanKind(trace.SpanKindServer),
  108. )
  109. if ok {
  110. span.AddLink(trace.Link{
  111. TraceID: sc.TraceID,
  112. SpanID: sc.SpanID,
  113. Type: trace.LinkTypeParent,
  114. Attributes: nil,
  115. })
  116. }
  117. }
  118. span.AddAttributes(requestAttrs(r)...)
  119. if r.Body == nil {
  120. // TODO: Handle cases where ContentLength is not set.
  121. } else if r.ContentLength > 0 {
  122. span.AddMessageReceiveEvent(0, /* TODO: messageID */
  123. r.ContentLength, -1)
  124. }
  125. return r.WithContext(ctx), span.End
  126. }
  127. func (h *Handler) extractSpanContext(r *http.Request) (trace.SpanContext, bool) {
  128. if h.Propagation == nil {
  129. return defaultFormat.SpanContextFromRequest(r)
  130. }
  131. return h.Propagation.SpanContextFromRequest(r)
  132. }
  133. func (h *Handler) startStats(w http.ResponseWriter, r *http.Request) (http.ResponseWriter, func(tags *addedTags)) {
  134. ctx, _ := tag.New(r.Context(),
  135. tag.Upsert(Host, r.Host),
  136. tag.Upsert(Path, r.URL.Path),
  137. tag.Upsert(Method, r.Method))
  138. track := &trackingResponseWriter{
  139. start: time.Now(),
  140. ctx: ctx,
  141. writer: w,
  142. }
  143. if r.Body == nil {
  144. // TODO: Handle cases where ContentLength is not set.
  145. track.reqSize = -1
  146. } else if r.ContentLength > 0 {
  147. track.reqSize = r.ContentLength
  148. }
  149. stats.Record(ctx, ServerRequestCount.M(1))
  150. return track.wrappedResponseWriter(), track.end
  151. }
  152. type trackingResponseWriter struct {
  153. ctx context.Context
  154. reqSize int64
  155. respSize int64
  156. start time.Time
  157. statusCode int
  158. statusLine string
  159. endOnce sync.Once
  160. writer http.ResponseWriter
  161. }
  162. // Compile time assertion for ResponseWriter interface
  163. var _ http.ResponseWriter = (*trackingResponseWriter)(nil)
  164. func (t *trackingResponseWriter) end(tags *addedTags) {
  165. t.endOnce.Do(func() {
  166. if t.statusCode == 0 {
  167. t.statusCode = 200
  168. }
  169. span := trace.FromContext(t.ctx)
  170. span.SetStatus(TraceStatus(t.statusCode, t.statusLine))
  171. span.AddAttributes(trace.Int64Attribute(StatusCodeAttribute, int64(t.statusCode)))
  172. m := []stats.Measurement{
  173. ServerLatency.M(float64(time.Since(t.start)) / float64(time.Millisecond)),
  174. ServerResponseBytes.M(t.respSize),
  175. }
  176. if t.reqSize >= 0 {
  177. m = append(m, ServerRequestBytes.M(t.reqSize))
  178. }
  179. allTags := make([]tag.Mutator, len(tags.t)+1)
  180. allTags[0] = tag.Upsert(StatusCode, strconv.Itoa(t.statusCode))
  181. copy(allTags[1:], tags.t)
  182. stats.RecordWithTags(t.ctx, allTags, m...)
  183. })
  184. }
  185. func (t *trackingResponseWriter) Header() http.Header {
  186. return t.writer.Header()
  187. }
  188. func (t *trackingResponseWriter) Write(data []byte) (int, error) {
  189. n, err := t.writer.Write(data)
  190. t.respSize += int64(n)
  191. // Add message event for request bytes sent.
  192. span := trace.FromContext(t.ctx)
  193. span.AddMessageSendEvent(0 /* TODO: messageID */, int64(n), -1)
  194. return n, err
  195. }
  196. func (t *trackingResponseWriter) WriteHeader(statusCode int) {
  197. t.writer.WriteHeader(statusCode)
  198. t.statusCode = statusCode
  199. t.statusLine = http.StatusText(t.statusCode)
  200. }
  201. // wrappedResponseWriter returns a wrapped version of the original
  202. //
  203. // ResponseWriter and only implements the same combination of additional
  204. //
  205. // interfaces as the original.
  206. // This implementation is based on https://github.com/felixge/httpsnoop.
  207. func (t *trackingResponseWriter) wrappedResponseWriter() http.ResponseWriter {
  208. var (
  209. hj, i0 = t.writer.(http.Hijacker)
  210. cn, i1 = t.writer.(http.CloseNotifier)
  211. pu, i2 = t.writer.(http.Pusher)
  212. fl, i3 = t.writer.(http.Flusher)
  213. rf, i4 = t.writer.(io.ReaderFrom)
  214. )
  215. switch {
  216. case !i0 && !i1 && !i2 && !i3 && !i4:
  217. return struct {
  218. http.ResponseWriter
  219. }{t}
  220. case !i0 && !i1 && !i2 && !i3 && i4:
  221. return struct {
  222. http.ResponseWriter
  223. io.ReaderFrom
  224. }{t, rf}
  225. case !i0 && !i1 && !i2 && i3 && !i4:
  226. return struct {
  227. http.ResponseWriter
  228. http.Flusher
  229. }{t, fl}
  230. case !i0 && !i1 && !i2 && i3 && i4:
  231. return struct {
  232. http.ResponseWriter
  233. http.Flusher
  234. io.ReaderFrom
  235. }{t, fl, rf}
  236. case !i0 && !i1 && i2 && !i3 && !i4:
  237. return struct {
  238. http.ResponseWriter
  239. http.Pusher
  240. }{t, pu}
  241. case !i0 && !i1 && i2 && !i3 && i4:
  242. return struct {
  243. http.ResponseWriter
  244. http.Pusher
  245. io.ReaderFrom
  246. }{t, pu, rf}
  247. case !i0 && !i1 && i2 && i3 && !i4:
  248. return struct {
  249. http.ResponseWriter
  250. http.Pusher
  251. http.Flusher
  252. }{t, pu, fl}
  253. case !i0 && !i1 && i2 && i3 && i4:
  254. return struct {
  255. http.ResponseWriter
  256. http.Pusher
  257. http.Flusher
  258. io.ReaderFrom
  259. }{t, pu, fl, rf}
  260. case !i0 && i1 && !i2 && !i3 && !i4:
  261. return struct {
  262. http.ResponseWriter
  263. http.CloseNotifier
  264. }{t, cn}
  265. case !i0 && i1 && !i2 && !i3 && i4:
  266. return struct {
  267. http.ResponseWriter
  268. http.CloseNotifier
  269. io.ReaderFrom
  270. }{t, cn, rf}
  271. case !i0 && i1 && !i2 && i3 && !i4:
  272. return struct {
  273. http.ResponseWriter
  274. http.CloseNotifier
  275. http.Flusher
  276. }{t, cn, fl}
  277. case !i0 && i1 && !i2 && i3 && i4:
  278. return struct {
  279. http.ResponseWriter
  280. http.CloseNotifier
  281. http.Flusher
  282. io.ReaderFrom
  283. }{t, cn, fl, rf}
  284. case !i0 && i1 && i2 && !i3 && !i4:
  285. return struct {
  286. http.ResponseWriter
  287. http.CloseNotifier
  288. http.Pusher
  289. }{t, cn, pu}
  290. case !i0 && i1 && i2 && !i3 && i4:
  291. return struct {
  292. http.ResponseWriter
  293. http.CloseNotifier
  294. http.Pusher
  295. io.ReaderFrom
  296. }{t, cn, pu, rf}
  297. case !i0 && i1 && i2 && i3 && !i4:
  298. return struct {
  299. http.ResponseWriter
  300. http.CloseNotifier
  301. http.Pusher
  302. http.Flusher
  303. }{t, cn, pu, fl}
  304. case !i0 && i1 && i2 && i3 && i4:
  305. return struct {
  306. http.ResponseWriter
  307. http.CloseNotifier
  308. http.Pusher
  309. http.Flusher
  310. io.ReaderFrom
  311. }{t, cn, pu, fl, rf}
  312. case i0 && !i1 && !i2 && !i3 && !i4:
  313. return struct {
  314. http.ResponseWriter
  315. http.Hijacker
  316. }{t, hj}
  317. case i0 && !i1 && !i2 && !i3 && i4:
  318. return struct {
  319. http.ResponseWriter
  320. http.Hijacker
  321. io.ReaderFrom
  322. }{t, hj, rf}
  323. case i0 && !i1 && !i2 && i3 && !i4:
  324. return struct {
  325. http.ResponseWriter
  326. http.Hijacker
  327. http.Flusher
  328. }{t, hj, fl}
  329. case i0 && !i1 && !i2 && i3 && i4:
  330. return struct {
  331. http.ResponseWriter
  332. http.Hijacker
  333. http.Flusher
  334. io.ReaderFrom
  335. }{t, hj, fl, rf}
  336. case i0 && !i1 && i2 && !i3 && !i4:
  337. return struct {
  338. http.ResponseWriter
  339. http.Hijacker
  340. http.Pusher
  341. }{t, hj, pu}
  342. case i0 && !i1 && i2 && !i3 && i4:
  343. return struct {
  344. http.ResponseWriter
  345. http.Hijacker
  346. http.Pusher
  347. io.ReaderFrom
  348. }{t, hj, pu, rf}
  349. case i0 && !i1 && i2 && i3 && !i4:
  350. return struct {
  351. http.ResponseWriter
  352. http.Hijacker
  353. http.Pusher
  354. http.Flusher
  355. }{t, hj, pu, fl}
  356. case i0 && !i1 && i2 && i3 && i4:
  357. return struct {
  358. http.ResponseWriter
  359. http.Hijacker
  360. http.Pusher
  361. http.Flusher
  362. io.ReaderFrom
  363. }{t, hj, pu, fl, rf}
  364. case i0 && i1 && !i2 && !i3 && !i4:
  365. return struct {
  366. http.ResponseWriter
  367. http.Hijacker
  368. http.CloseNotifier
  369. }{t, hj, cn}
  370. case i0 && i1 && !i2 && !i3 && i4:
  371. return struct {
  372. http.ResponseWriter
  373. http.Hijacker
  374. http.CloseNotifier
  375. io.ReaderFrom
  376. }{t, hj, cn, rf}
  377. case i0 && i1 && !i2 && i3 && !i4:
  378. return struct {
  379. http.ResponseWriter
  380. http.Hijacker
  381. http.CloseNotifier
  382. http.Flusher
  383. }{t, hj, cn, fl}
  384. case i0 && i1 && !i2 && i3 && i4:
  385. return struct {
  386. http.ResponseWriter
  387. http.Hijacker
  388. http.CloseNotifier
  389. http.Flusher
  390. io.ReaderFrom
  391. }{t, hj, cn, fl, rf}
  392. case i0 && i1 && i2 && !i3 && !i4:
  393. return struct {
  394. http.ResponseWriter
  395. http.Hijacker
  396. http.CloseNotifier
  397. http.Pusher
  398. }{t, hj, cn, pu}
  399. case i0 && i1 && i2 && !i3 && i4:
  400. return struct {
  401. http.ResponseWriter
  402. http.Hijacker
  403. http.CloseNotifier
  404. http.Pusher
  405. io.ReaderFrom
  406. }{t, hj, cn, pu, rf}
  407. case i0 && i1 && i2 && i3 && !i4:
  408. return struct {
  409. http.ResponseWriter
  410. http.Hijacker
  411. http.CloseNotifier
  412. http.Pusher
  413. http.Flusher
  414. }{t, hj, cn, pu, fl}
  415. case i0 && i1 && i2 && i3 && i4:
  416. return struct {
  417. http.ResponseWriter
  418. http.Hijacker
  419. http.CloseNotifier
  420. http.Pusher
  421. http.Flusher
  422. io.ReaderFrom
  423. }{t, hj, cn, pu, fl, rf}
  424. default:
  425. return struct {
  426. http.ResponseWriter
  427. }{t}
  428. }
  429. }