span.go 3.2 KB

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