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.
 
 
 

118 lines
3.6 KiB

  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. "net/http"
  17. "net/http/httptrace"
  18. "go.opencensus.io/trace"
  19. "go.opencensus.io/trace/propagation"
  20. )
  21. // Transport is an http.RoundTripper that instruments all outgoing requests with
  22. // OpenCensus stats and tracing.
  23. //
  24. // The zero value is intended to be a useful default, but for
  25. // now it's recommended that you explicitly set Propagation, since the default
  26. // for this may change.
  27. type Transport struct {
  28. // Base may be set to wrap another http.RoundTripper that does the actual
  29. // requests. By default http.DefaultTransport is used.
  30. //
  31. // If base HTTP roundtripper implements CancelRequest,
  32. // the returned round tripper will be cancelable.
  33. Base http.RoundTripper
  34. // Propagation defines how traces are propagated. If unspecified, a default
  35. // (currently B3 format) will be used.
  36. Propagation propagation.HTTPFormat
  37. // StartOptions are applied to the span started by this Transport around each
  38. // request.
  39. //
  40. // StartOptions.SpanKind will always be set to trace.SpanKindClient
  41. // for spans started by this transport.
  42. StartOptions trace.StartOptions
  43. // GetStartOptions allows to set start options per request. If set,
  44. // StartOptions is going to be ignored.
  45. GetStartOptions func(*http.Request) trace.StartOptions
  46. // NameFromRequest holds the function to use for generating the span name
  47. // from the information found in the outgoing HTTP Request. By default the
  48. // name equals the URL Path.
  49. FormatSpanName func(*http.Request) string
  50. // NewClientTrace may be set to a function allowing the current *trace.Span
  51. // to be annotated with HTTP request event information emitted by the
  52. // httptrace package.
  53. NewClientTrace func(*http.Request, *trace.Span) *httptrace.ClientTrace
  54. // TODO: Implement tag propagation for HTTP.
  55. }
  56. // RoundTrip implements http.RoundTripper, delegating to Base and recording stats and traces for the request.
  57. func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
  58. rt := t.base()
  59. if isHealthEndpoint(req.URL.Path) {
  60. return rt.RoundTrip(req)
  61. }
  62. // TODO: remove excessive nesting of http.RoundTrippers here.
  63. format := t.Propagation
  64. if format == nil {
  65. format = defaultFormat
  66. }
  67. spanNameFormatter := t.FormatSpanName
  68. if spanNameFormatter == nil {
  69. spanNameFormatter = spanNameFromURL
  70. }
  71. startOpts := t.StartOptions
  72. if t.GetStartOptions != nil {
  73. startOpts = t.GetStartOptions(req)
  74. }
  75. rt = &traceTransport{
  76. base: rt,
  77. format: format,
  78. startOptions: trace.StartOptions{
  79. Sampler: startOpts.Sampler,
  80. SpanKind: trace.SpanKindClient,
  81. },
  82. formatSpanName: spanNameFormatter,
  83. newClientTrace: t.NewClientTrace,
  84. }
  85. rt = statsTransport{base: rt}
  86. return rt.RoundTrip(req)
  87. }
  88. func (t *Transport) base() http.RoundTripper {
  89. if t.Base != nil {
  90. return t.Base
  91. }
  92. return http.DefaultTransport
  93. }
  94. // CancelRequest cancels an in-flight request by closing its connection.
  95. func (t *Transport) CancelRequest(req *http.Request) {
  96. type canceler interface {
  97. CancelRequest(*http.Request)
  98. }
  99. if cr, ok := t.base().(canceler); ok {
  100. cr.CancelRequest(req)
  101. }
  102. }