span.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. package trace
  2. import (
  3. "context"
  4. "fmt"
  5. "strconv"
  6. "strings"
  7. "time"
  8. "github.com/tal-tech/go-zero/core/stringx"
  9. "github.com/tal-tech/go-zero/core/timex"
  10. "github.com/tal-tech/go-zero/core/trace/tracespec"
  11. )
  12. const (
  13. initSpanId = "0"
  14. clientFlag = "client"
  15. serverFlag = "server"
  16. spanSepRune = '.'
  17. )
  18. var spanSep = string([]byte{spanSepRune})
  19. type Span struct {
  20. ctx spanContext
  21. serviceName string
  22. operationName string
  23. startTime time.Time
  24. flag string
  25. children int
  26. }
  27. func newServerSpan(carrier Carrier, serviceName, operationName string) tracespec.Trace {
  28. traceId := stringx.TakeWithPriority(func() string {
  29. if carrier != nil {
  30. return carrier.Get(traceIdKey)
  31. }
  32. return ""
  33. }, stringx.RandId)
  34. spanId := stringx.TakeWithPriority(func() string {
  35. if carrier != nil {
  36. return carrier.Get(spanIdKey)
  37. }
  38. return ""
  39. }, func() string {
  40. return initSpanId
  41. })
  42. return &Span{
  43. ctx: spanContext{
  44. traceId: traceId,
  45. spanId: spanId,
  46. },
  47. serviceName: serviceName,
  48. operationName: operationName,
  49. startTime: timex.Time(),
  50. flag: serverFlag,
  51. }
  52. }
  53. func (s *Span) Finish() {
  54. }
  55. func (s *Span) Follow(ctx context.Context, serviceName, operationName string) (context.Context, tracespec.Trace) {
  56. span := &Span{
  57. ctx: spanContext{
  58. traceId: s.ctx.traceId,
  59. spanId: s.followSpanId(),
  60. },
  61. serviceName: serviceName,
  62. operationName: operationName,
  63. startTime: timex.Time(),
  64. flag: s.flag,
  65. }
  66. return context.WithValue(ctx, tracespec.TracingKey, span), span
  67. }
  68. func (s *Span) Fork(ctx context.Context, serviceName, operationName string) (context.Context, tracespec.Trace) {
  69. span := &Span{
  70. ctx: spanContext{
  71. traceId: s.ctx.traceId,
  72. spanId: s.forkSpanId(),
  73. },
  74. serviceName: serviceName,
  75. operationName: operationName,
  76. startTime: timex.Time(),
  77. flag: clientFlag,
  78. }
  79. return context.WithValue(ctx, tracespec.TracingKey, span), span
  80. }
  81. func (s *Span) SpanId() string {
  82. return s.ctx.SpanId()
  83. }
  84. func (s *Span) TraceId() string {
  85. return s.ctx.TraceId()
  86. }
  87. func (s *Span) Visit(fn func(key, val string) bool) {
  88. s.ctx.Visit(fn)
  89. }
  90. func (s *Span) forkSpanId() string {
  91. s.children++
  92. return fmt.Sprintf("%s.%d", s.ctx.spanId, s.children)
  93. }
  94. func (s *Span) followSpanId() string {
  95. fields := strings.FieldsFunc(s.ctx.spanId, func(r rune) bool {
  96. return r == spanSepRune
  97. })
  98. if len(fields) == 0 {
  99. return s.ctx.spanId
  100. }
  101. last := fields[len(fields)-1]
  102. val, err := strconv.Atoi(last)
  103. if err != nil {
  104. return s.ctx.spanId
  105. }
  106. last = strconv.Itoa(val + 1)
  107. fields[len(fields)-1] = last
  108. return strings.Join(fields, spanSep)
  109. }
  110. func StartClientSpan(ctx context.Context, serviceName, operationName string) (context.Context, tracespec.Trace) {
  111. if span, ok := ctx.Value(tracespec.TracingKey).(*Span); ok {
  112. return span.Fork(ctx, serviceName, operationName)
  113. }
  114. return ctx, emptyNoopSpan
  115. }
  116. func StartServerSpan(ctx context.Context, carrier Carrier, serviceName, operationName string) (
  117. context.Context, tracespec.Trace) {
  118. span := newServerSpan(carrier, serviceName, operationName)
  119. return context.WithValue(ctx, tracespec.TracingKey, span), span
  120. }