marshal.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package trace
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. "math"
  6. "strconv"
  7. "time"
  8. "github.com/golang/protobuf/proto"
  9. "github.com/golang/protobuf/ptypes/duration"
  10. "github.com/golang/protobuf/ptypes/timestamp"
  11. protogen "go-common/library/net/trace/proto"
  12. )
  13. const protoVersion2 int32 = 2
  14. func marshalSpan(sp *span, version int32) ([]byte, error) {
  15. if version == protoVersion2 {
  16. return marshalSpanV2(sp)
  17. }
  18. return marshalSpanV1(sp)
  19. }
  20. func marshalSpanV2(sp *span) ([]byte, error) {
  21. protoSpan := new(protogen.Span)
  22. protoSpan.Version = protoVersion2
  23. protoSpan.ServiceName = sp.dapper.serviceName
  24. protoSpan.OperationName = sp.operationName
  25. protoSpan.TraceId = sp.context.traceID
  26. protoSpan.SpanId = sp.context.spanID
  27. protoSpan.ParentId = sp.context.parentID
  28. protoSpan.SamplingProbability = sp.context.probability
  29. protoSpan.StartTime = &timestamp.Timestamp{
  30. Seconds: sp.startTime.Unix(),
  31. Nanos: int32(sp.startTime.Nanosecond()),
  32. }
  33. protoSpan.Duration = &duration.Duration{
  34. Seconds: int64(sp.duration / time.Second),
  35. Nanos: int32(sp.duration % time.Second),
  36. }
  37. protoSpan.Tags = make([]*protogen.Tag, len(sp.tags))
  38. for i := range sp.tags {
  39. protoSpan.Tags[i] = toProtoTag(sp.tags[i])
  40. }
  41. protoSpan.Logs = sp.logs
  42. return proto.Marshal(protoSpan)
  43. }
  44. func toLeagcyTag(tag Tag) *protogen.Tag {
  45. ptag := &protogen.Tag{Key: tag.Key}
  46. switch value := tag.Value.(type) {
  47. case string:
  48. ptag.Kind = protogen.Tag_STRING
  49. ptag.Value = []byte(value)
  50. case int:
  51. ptag.Kind = protogen.Tag_INT
  52. ptag.Value = []byte(strconv.FormatInt(int64(value), 10))
  53. case int32:
  54. ptag.Kind = protogen.Tag_INT
  55. ptag.Value = []byte(strconv.FormatInt(int64(value), 10))
  56. case int64:
  57. ptag.Kind = protogen.Tag_INT
  58. ptag.Value = []byte(strconv.FormatInt(value, 10))
  59. case bool:
  60. ptag.Kind = protogen.Tag_BOOL
  61. ptag.Value = []byte(strconv.FormatBool(value))
  62. case float32:
  63. ptag.Kind = protogen.Tag_BOOL
  64. ptag.Value = []byte(strconv.FormatFloat(float64(value), 'E', -1, 64))
  65. case float64:
  66. ptag.Kind = protogen.Tag_BOOL
  67. ptag.Value = []byte(strconv.FormatFloat(value, 'E', -1, 64))
  68. default:
  69. ptag.Kind = protogen.Tag_STRING
  70. ptag.Value = []byte((fmt.Sprintf("%v", tag.Value)))
  71. }
  72. return ptag
  73. }
  74. func toLeagcyLog(logs []*protogen.Log) []*protogen.Log {
  75. for _, log := range logs {
  76. if len(log.Fields) == 0 {
  77. continue
  78. }
  79. log.Key = log.Fields[0].Key
  80. log.Value = log.Fields[0].Value
  81. }
  82. return logs
  83. }
  84. func marshalSpanV1(sp *span) ([]byte, error) {
  85. protoSpan := new(protogen.Span)
  86. protoSpan.ServiceName = sp.dapper.serviceName
  87. protoSpan.OperationName = sp.operationName
  88. protoSpan.TraceId = sp.context.traceID
  89. protoSpan.SpanId = sp.context.spanID
  90. protoSpan.ParentId = sp.context.parentID
  91. protoSpan.SamplingProbability = sp.context.probability
  92. protoSpan.StartAt = sp.startTime.UnixNano()
  93. protoSpan.FinishAt = sp.startTime.UnixNano() + int64(sp.duration)
  94. protoSpan.Tags = make([]*protogen.Tag, len(sp.tags))
  95. for i := range sp.tags {
  96. protoSpan.Tags[i] = toLeagcyTag(sp.tags[i])
  97. }
  98. protoSpan.Logs = toLeagcyLog(sp.logs)
  99. return proto.Marshal(protoSpan)
  100. }
  101. func serializeInt64(v int64) []byte {
  102. data := make([]byte, 8)
  103. binary.BigEndian.PutUint64(data, uint64(v))
  104. return data
  105. }
  106. func serializeFloat64(v float64) []byte {
  107. data := make([]byte, 8)
  108. binary.BigEndian.PutUint64(data, math.Float64bits(v))
  109. return data
  110. }
  111. func serializeBool(v bool) []byte {
  112. data := make([]byte, 1)
  113. if v {
  114. data[0] = byte(1)
  115. } else {
  116. data[0] = byte(0)
  117. }
  118. return data
  119. }
  120. func toProtoTag(tag Tag) *protogen.Tag {
  121. ptag := &protogen.Tag{Key: tag.Key}
  122. switch value := tag.Value.(type) {
  123. case string:
  124. ptag.Kind = protogen.Tag_STRING
  125. ptag.Value = []byte(value)
  126. case int:
  127. ptag.Kind = protogen.Tag_INT
  128. ptag.Value = serializeInt64(int64(value))
  129. case int32:
  130. ptag.Kind = protogen.Tag_INT
  131. ptag.Value = serializeInt64(int64(value))
  132. case int64:
  133. ptag.Kind = protogen.Tag_INT
  134. ptag.Value = serializeInt64(value)
  135. case bool:
  136. ptag.Kind = protogen.Tag_BOOL
  137. ptag.Value = serializeBool(value)
  138. case float32:
  139. ptag.Kind = protogen.Tag_BOOL
  140. ptag.Value = serializeFloat64(float64(value))
  141. case float64:
  142. ptag.Kind = protogen.Tag_BOOL
  143. ptag.Value = serializeFloat64(value)
  144. default:
  145. ptag.Kind = protogen.Tag_STRING
  146. ptag.Value = []byte((fmt.Sprintf("%v", tag.Value)))
  147. }
  148. return ptag
  149. }