map.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  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 b3
  15. import (
  16. "github.com/openzipkin/zipkin-go/model"
  17. "github.com/openzipkin/zipkin-go/propagation"
  18. )
  19. // Map allows serialization and deserialization of SpanContext into a standard Go map.
  20. type Map map[string]string
  21. // Extract implements Extractor
  22. func (m *Map) Extract() (*model.SpanContext, error) {
  23. var (
  24. traceIDHeader = (*m)[TraceID]
  25. spanIDHeader = (*m)[SpanID]
  26. parentSpanIDHeader = (*m)[ParentSpanID]
  27. sampledHeader = (*m)[Sampled]
  28. flagsHeader = (*m)[Flags]
  29. singleHeader = (*m)[Context]
  30. )
  31. var (
  32. sc *model.SpanContext
  33. sErr error
  34. mErr error
  35. )
  36. if singleHeader != "" {
  37. sc, sErr = ParseSingleHeader(singleHeader)
  38. if sErr == nil {
  39. return sc, nil
  40. }
  41. }
  42. sc, mErr = ParseHeaders(
  43. traceIDHeader, spanIDHeader, parentSpanIDHeader,
  44. sampledHeader, flagsHeader,
  45. )
  46. if mErr != nil && sErr != nil {
  47. return nil, sErr
  48. }
  49. return sc, mErr
  50. }
  51. // Inject implements Injector
  52. func (m *Map) Inject(opts ...InjectOption) propagation.Injector {
  53. options := InjectOptions{shouldInjectMultiHeader: true}
  54. for _, opt := range opts {
  55. opt(&options)
  56. }
  57. return func(sc model.SpanContext) error {
  58. if (model.SpanContext{}) == sc {
  59. return ErrEmptyContext
  60. }
  61. if options.shouldInjectMultiHeader {
  62. if sc.Debug {
  63. (*m)[Flags] = "1"
  64. } else if sc.Sampled != nil {
  65. // Debug is encoded as X-B3-Flags: 1. Since Debug implies Sampled,
  66. // so don't also send "X-B3-Sampled: 1".
  67. if *sc.Sampled {
  68. (*m)[Sampled] = "1"
  69. } else {
  70. (*m)[Sampled] = "0"
  71. }
  72. }
  73. if !sc.TraceID.Empty() && sc.ID > 0 {
  74. (*m)[TraceID] = sc.TraceID.String()
  75. (*m)[SpanID] = sc.ID.String()
  76. if sc.ParentID != nil {
  77. (*m)[ParentSpanID] = sc.ParentID.String()
  78. }
  79. }
  80. }
  81. if options.shouldInjectSingleHeader {
  82. (*m)[Context] = BuildSingleHeader(sc)
  83. }
  84. return nil
  85. }
  86. }