propagation.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // Copyright 2022 The OpenZipkin 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 zipkintracer
  15. import (
  16. "net/http"
  17. "strings"
  18. opentracing "github.com/opentracing/opentracing-go"
  19. "github.com/openzipkin/zipkin-go/model"
  20. "github.com/openzipkin/zipkin-go/propagation"
  21. "github.com/openzipkin/zipkin-go/propagation/b3"
  22. )
  23. // DelegatingCarrier is a flexible carrier interface which can be implemented
  24. // by types which have a means of storing the trace metadata and already know
  25. // how to serialize themselves
  26. type DelegatingCarrier interface {
  27. State() (model.SpanContext, error)
  28. SetState(model.SpanContext) error
  29. }
  30. type textMapPropagator struct {
  31. tracer *tracerImpl
  32. }
  33. func (p *textMapPropagator) Inject(
  34. spanContext opentracing.SpanContext,
  35. opaqueCarrier interface{},
  36. ) error {
  37. sc, ok := spanContext.(SpanContext)
  38. if !ok {
  39. return opentracing.ErrInvalidSpanContext
  40. }
  41. // native zipkin-go injector
  42. if injector, ok := opaqueCarrier.(propagation.Injector); ok {
  43. return injector(model.SpanContext(sc))
  44. }
  45. // fallback to support native opentracing http carrier
  46. if httpCarrier, ok := opaqueCarrier.(opentracing.HTTPHeadersCarrier); ok {
  47. req := &http.Request{Header: http.Header(httpCarrier)}
  48. switch p.tracer.opts.b3InjectOpt {
  49. case B3InjectSingle:
  50. return b3.InjectHTTP(req, b3.WithSingleHeaderOnly())(model.SpanContext(sc))
  51. case B3InjectBoth:
  52. return b3.InjectHTTP(req, b3.WithSingleAndMultiHeader())(model.SpanContext(sc))
  53. default:
  54. return b3.InjectHTTP(req)(model.SpanContext(sc))
  55. }
  56. }
  57. // fallback to support native opentracing textmap writer
  58. if carrier, ok := opaqueCarrier.(opentracing.TextMapWriter); ok {
  59. var (
  60. err error
  61. m = make(b3.Map)
  62. )
  63. switch p.tracer.opts.b3InjectOpt {
  64. case B3InjectSingle:
  65. err = m.Inject(b3.WithSingleHeaderOnly())(model.SpanContext(sc))
  66. case B3InjectBoth:
  67. err = m.Inject(b3.WithSingleAndMultiHeader())(model.SpanContext(sc))
  68. default:
  69. err = m.Inject()(model.SpanContext(sc))
  70. }
  71. if err != nil {
  72. return err
  73. }
  74. for k, v := range m {
  75. carrier.Set(k, v)
  76. }
  77. return nil
  78. }
  79. return opentracing.ErrInvalidCarrier
  80. }
  81. func (p *textMapPropagator) Extract(
  82. opaqueCarrier interface{},
  83. ) (opentracing.SpanContext, error) {
  84. if extractor, ok := opaqueCarrier.(propagation.Extractor); ok {
  85. sc, err := extractor()
  86. if sc != nil {
  87. return SpanContext(*sc), err
  88. }
  89. return SpanContext{}, err
  90. }
  91. if httpCarrier, ok := opaqueCarrier.(opentracing.HTTPHeadersCarrier); ok {
  92. req := &http.Request{Header: http.Header(httpCarrier)}
  93. sc, err := b3.ExtractHTTP(req)()
  94. if sc != nil {
  95. return SpanContext(*sc), err
  96. }
  97. return SpanContext{}, err
  98. }
  99. if carrier, ok := opaqueCarrier.(opentracing.TextMapReader); ok {
  100. m := make(b3.Map)
  101. carrier.ForeachKey(func(key string, val string) error {
  102. // no matter the format of the B3 headers, they will be retrieved
  103. // using the standard lowercase format e.g. x-b3-traceid. See
  104. // https://github.com/openzipkin/zipkin-go/blob/master/propagation/b3/shared.go
  105. m[strings.ToLower(key)] = val
  106. return nil
  107. })
  108. sc, err := m.Extract()
  109. if sc != nil {
  110. return SpanContext(*sc), err
  111. }
  112. return SpanContext{}, err
  113. }
  114. return nil, opentracing.ErrUnsupportedFormat
  115. }
  116. type accessorPropagator struct {
  117. tracer *tracerImpl
  118. }
  119. func (p *accessorPropagator) Inject(
  120. spanContext opentracing.SpanContext,
  121. opaqueCarrier interface{},
  122. ) error {
  123. dc, ok := opaqueCarrier.(DelegatingCarrier)
  124. if !ok || dc == nil {
  125. return opentracing.ErrInvalidCarrier
  126. }
  127. sc, ok := spanContext.(SpanContext)
  128. if !ok {
  129. return opentracing.ErrInvalidSpanContext
  130. }
  131. return dc.SetState(model.SpanContext(sc))
  132. }
  133. func (p *accessorPropagator) Extract(
  134. opaqueCarrier interface{},
  135. ) (opentracing.SpanContext, error) {
  136. dc, ok := opaqueCarrier.(DelegatingCarrier)
  137. if !ok || dc == nil {
  138. return nil, opentracing.ErrInvalidCarrier
  139. }
  140. sc, err := dc.State()
  141. return SpanContext(sc), err
  142. }