You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

108 lines
3.2 KiB

  1. // Copyright 2017 Google LLC
  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. // +build go1.7
  15. package trace
  16. import (
  17. "net/http"
  18. )
  19. // Transport is an http.RoundTripper that traces the outgoing requests.
  20. //
  21. // Transport is safe for concurrent usage.
  22. type Transport struct {
  23. // Base is the base http.RoundTripper to be used to do the actual request.
  24. //
  25. // Optional. If nil, http.DefaultTransport is used.
  26. Base http.RoundTripper
  27. }
  28. // RoundTrip creates a trace.Span and inserts it into the outgoing request's headers.
  29. // The created span can follow a parent span, if a parent is presented in
  30. // the request's context.
  31. func (t Transport) RoundTrip(req *http.Request) (*http.Response, error) {
  32. span := FromContext(req.Context()).NewRemoteChild(req)
  33. resp, err := t.base().RoundTrip(req)
  34. // TODO(jbd): Is it possible to defer the span.Finish?
  35. // In cases where RoundTrip panics, we still can finish the span.
  36. span.Finish(WithResponse(resp))
  37. return resp, err
  38. }
  39. // CancelRequest cancels an in-flight request by closing its connection.
  40. func (t Transport) CancelRequest(req *http.Request) {
  41. type canceler interface {
  42. CancelRequest(*http.Request)
  43. }
  44. if cr, ok := t.base().(canceler); ok {
  45. cr.CancelRequest(req)
  46. }
  47. }
  48. func (t Transport) base() http.RoundTripper {
  49. if t.Base != nil {
  50. return t.Base
  51. }
  52. return http.DefaultTransport
  53. }
  54. // HTTPHandler returns a http.Handler from the given handler
  55. // that is aware of the incoming request's span.
  56. // The span can be extracted from the incoming request in handler
  57. // functions from incoming request's context:
  58. //
  59. // span := trace.FromContext(r.Context())
  60. //
  61. // The span will be auto finished by the handler.
  62. func (c *Client) HTTPHandler(h http.Handler) http.Handler {
  63. if c == nil {
  64. return h
  65. }
  66. return &handler{traceClient: c, handler: h}
  67. }
  68. type handler struct {
  69. traceClient *Client
  70. handler http.Handler
  71. }
  72. func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  73. traceID, parentSpanID, options, optionsOk, ok := traceInfoFromHeader(r.Header.Get(httpHeader))
  74. if !ok {
  75. traceID = nextTraceID()
  76. }
  77. t := &trace{
  78. traceID: traceID,
  79. client: h.traceClient,
  80. globalOptions: options,
  81. localOptions: options,
  82. }
  83. span := startNewChildWithRequest(r, t, parentSpanID)
  84. span.span.Kind = spanKindServer
  85. span.rootSpan = true
  86. configureSpanFromPolicy(span, h.traceClient.policy, ok)
  87. defer span.Finish()
  88. r = r.WithContext(NewContext(r.Context(), span))
  89. if ok && !optionsOk {
  90. // Inject the trace context back to the response with the sampling options.
  91. // TODO(jbd): Remove when there is a better way to report the client's sampling.
  92. w.Header().Set(httpHeader, spanHeader(traceID, parentSpanID, span.trace.localOptions))
  93. }
  94. h.handler.ServeHTTP(w, r)
  95. }