span.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. package trace
  2. import (
  3. "fmt"
  4. "strconv"
  5. "time"
  6. protogen "go-common/library/net/trace/proto"
  7. )
  8. const (
  9. _maxChilds = 1024
  10. _maxTags = 128
  11. _maxLogs = 256
  12. )
  13. var _ Trace = &span{}
  14. type span struct {
  15. dapper *dapper
  16. context spanContext
  17. operationName string
  18. startTime time.Time
  19. duration time.Duration
  20. tags []Tag
  21. logs []*protogen.Log
  22. childs int
  23. }
  24. func (s *span) Fork(serviceName, operationName string) Trace {
  25. if s.childs > _maxChilds {
  26. // if child span more than max childs set return noopspan
  27. return noopspan{}
  28. }
  29. s.childs++
  30. // 为了兼容临时为 New 的 Span 设置 span.kind
  31. return s.dapper.newSpanWithContext(operationName, s.context).SetTag(TagString(TagSpanKind, "client"))
  32. }
  33. func (s *span) Follow(serviceName, operationName string) Trace {
  34. return s.Fork(serviceName, operationName).SetTag(TagString(TagSpanKind, "producer"))
  35. }
  36. func (s *span) Finish(perr *error) {
  37. s.duration = time.Since(s.startTime)
  38. if perr != nil && *perr != nil {
  39. err := *perr
  40. s.SetTag(TagBool(TagError, true))
  41. s.SetLog(Log(LogMessage, err.Error()))
  42. if err, ok := err.(stackTracer); ok {
  43. s.SetLog(Log(LogStack, fmt.Sprintf("%+v", err.StackTrace())))
  44. }
  45. }
  46. s.dapper.report(s)
  47. }
  48. func (s *span) SetTag(tags ...Tag) Trace {
  49. if !s.context.isSampled() && !s.context.isDebug() {
  50. return s
  51. }
  52. if len(s.tags) < _maxTags {
  53. s.tags = append(s.tags, tags...)
  54. }
  55. if len(s.tags) == _maxTags {
  56. s.tags = append(s.tags, Tag{Key: "trace.error", Value: "too many tags"})
  57. }
  58. return s
  59. }
  60. // LogFields is an efficient and type-checked way to record key:value
  61. // NOTE current unsupport
  62. func (s *span) SetLog(logs ...LogField) Trace {
  63. if !s.context.isSampled() && !s.context.isDebug() {
  64. return s
  65. }
  66. if len(s.logs) < _maxLogs {
  67. s.setLog(logs...)
  68. }
  69. if len(s.logs) == _maxLogs {
  70. s.setLog(LogField{Key: "trace.error", Value: "too many logs"})
  71. }
  72. return s
  73. }
  74. func (s *span) setLog(logs ...LogField) Trace {
  75. protoLog := &protogen.Log{
  76. Timestamp: time.Now().UnixNano(),
  77. Fields: make([]*protogen.Field, len(logs)),
  78. }
  79. for i := range logs {
  80. protoLog.Fields[i] = &protogen.Field{Key: logs[i].Key, Value: []byte(logs[i].Value)}
  81. }
  82. s.logs = append(s.logs, protoLog)
  83. return s
  84. }
  85. // Visit visits the k-v pair in trace, calling fn for each.
  86. func (s *span) Visit(fn func(k, v string)) {
  87. // NOTE: Deprecated key: delete in future
  88. fn(KeyTraceID, strconv.FormatUint(s.context.traceID, 10))
  89. fn(KeyTraceSpanID, strconv.FormatUint(s.context.spanID, 10))
  90. fn(KeyTraceParentID, strconv.FormatUint(s.context.parentID, 10))
  91. fn(KeyTraceSampled, strconv.FormatBool(s.context.isSampled()))
  92. fn(KeyTraceCaller, s.dapper.serviceName)
  93. fn(BiliTraceID, s.context.String())
  94. }
  95. // SetTitle reset trace title
  96. func (s *span) SetTitle(operationName string) {
  97. s.operationName = operationName
  98. }
  99. func (s *span) String() string {
  100. return s.context.String()
  101. }