util.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. package model
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. "math"
  6. "strconv"
  7. "time"
  8. "github.com/golang/protobuf/ptypes/duration"
  9. "github.com/golang/protobuf/ptypes/timestamp"
  10. protogen "go-common/library/net/trace/proto"
  11. )
  12. const protoVersion2 int32 = 2
  13. // FromProtoSpan convert protogen.Span to model.Span
  14. func FromProtoSpan(protoSpan *ProtoSpan, parseLog bool) (*Span, error) {
  15. var span *Span
  16. var err error
  17. if protoSpan.Version != protoVersion2 {
  18. span, err = fromProtoSpanLeagcy(protoSpan, parseLog)
  19. } else {
  20. span, err = fromProtoSpanInternal(protoSpan, parseLog)
  21. }
  22. if err == nil {
  23. // NOTE: !!
  24. span.ProtoSpan = protoSpan
  25. }
  26. return span, err
  27. }
  28. func convertLeagcyTag(protoTag *protogen.Tag) Tag {
  29. tag := Tag{Key: protoTag.Key}
  30. switch protoTag.Kind {
  31. case protogen.Tag_STRING:
  32. tag.Kind = TagString
  33. tag.Value = string(protoTag.Value)
  34. case protogen.Tag_INT:
  35. tag.Kind = TagInt
  36. tag.Value, _ = strconv.ParseInt(string(protoTag.Value), 10, 64)
  37. case protogen.Tag_BOOL:
  38. tag.Kind = TagBool
  39. tag.Value, _ = strconv.ParseBool(string(protoTag.Value))
  40. case protogen.Tag_FLOAT:
  41. tag.Kind = TagFloat
  42. tag.Value, _ = strconv.ParseFloat(string(protoTag.Value), 64)
  43. }
  44. return tag
  45. }
  46. func convertLeagcyLog(protoLog *protogen.Log) Log {
  47. log := Log{Timestamp: protoLog.Timestamp}
  48. log.Fields = []Field{{Key: protoLog.Key, Value: protoLog.Value}}
  49. return log
  50. }
  51. func fromProtoSpanLeagcy(protoSpan *ProtoSpan, parseLog bool) (*Span, error) {
  52. span := &Span{
  53. ServiceName: protoSpan.ServiceName,
  54. OperationName: protoSpan.OperationName,
  55. TraceID: protoSpan.TraceId,
  56. SpanID: protoSpan.SpanId,
  57. Env: protoSpan.Env,
  58. ParentID: protoSpan.ParentId,
  59. }
  60. span.StartTime = time.Unix(protoSpan.StartAt/int64(time.Second), protoSpan.StartAt%int64(time.Second))
  61. span.Duration = time.Duration(protoSpan.FinishAt - protoSpan.StartAt)
  62. span.References = []SpanRef{{
  63. RefType: RefTypeChildOf,
  64. TraceID: protoSpan.TraceId,
  65. SpanID: protoSpan.ParentId,
  66. }}
  67. span.Tags = make(map[string]interface{})
  68. for _, tag := range protoSpan.Tags {
  69. newTag := convertLeagcyTag(tag)
  70. span.Tags[newTag.Key] = newTag.Value
  71. }
  72. if !parseLog {
  73. return span, nil
  74. }
  75. span.Logs = make([]Log, 0, len(protoSpan.Logs))
  76. for _, log := range protoSpan.Logs {
  77. span.Logs = append(span.Logs, convertLeagcyLog(log))
  78. }
  79. return span, nil
  80. }
  81. func timeFromTimestamp(t *timestamp.Timestamp) time.Time {
  82. return time.Unix(t.Seconds, int64(t.Nanos))
  83. }
  84. func durationFromDuration(d *duration.Duration) time.Duration {
  85. return time.Duration(d.Seconds*int64(time.Second) + int64(d.Nanos))
  86. }
  87. func convertSpanRef(protoRef *protogen.SpanRef) SpanRef {
  88. ref := SpanRef{
  89. TraceID: protoRef.TraceId,
  90. SpanID: protoRef.SpanId,
  91. }
  92. switch protoRef.RefType {
  93. case protogen.SpanRef_CHILD_OF:
  94. ref.RefType = RefTypeChildOf
  95. case protogen.SpanRef_FOLLOWS_FROM:
  96. ref.RefType = RefTypeFollowsFrom
  97. }
  98. return ref
  99. }
  100. func unSerializeInt64(data []byte) int64 {
  101. return int64(binary.BigEndian.Uint64(data))
  102. }
  103. func unSerializeBool(data []byte) bool {
  104. return data[0] == byte(1)
  105. }
  106. func unSerializeFloat64(data []byte) float64 {
  107. value := binary.BigEndian.Uint64(data)
  108. return math.Float64frombits(value)
  109. }
  110. func convertTag(protoTag *protogen.Tag) Tag {
  111. tag := Tag{Key: protoTag.Key}
  112. switch protoTag.Kind {
  113. case protogen.Tag_STRING:
  114. tag.Kind = TagString
  115. tag.Value = string(protoTag.Value)
  116. case protogen.Tag_INT:
  117. tag.Kind = TagInt
  118. tag.Value = unSerializeInt64(protoTag.Value)
  119. case protogen.Tag_BOOL:
  120. tag.Kind = TagBool
  121. tag.Value = unSerializeBool(protoTag.Value)
  122. case protogen.Tag_FLOAT:
  123. tag.Kind = TagFloat
  124. tag.Value = unSerializeFloat64(protoTag.Value)
  125. }
  126. return tag
  127. }
  128. func convertLog(protoLog *protogen.Log) Log {
  129. log := Log{Timestamp: protoLog.Timestamp}
  130. log.Fields = make([]Field, 0, len(protoLog.Fields))
  131. for _, protoFiled := range protoLog.Fields {
  132. log.Fields = append(log.Fields, Field{Key: protoFiled.Key, Value: protoFiled.Value})
  133. }
  134. return log
  135. }
  136. func fromProtoSpanInternal(protoSpan *ProtoSpan, parseLog bool) (*Span, error) {
  137. span := &Span{
  138. ServiceName: protoSpan.ServiceName,
  139. OperationName: protoSpan.OperationName,
  140. TraceID: protoSpan.TraceId,
  141. SpanID: protoSpan.SpanId,
  142. ParentID: protoSpan.ParentId,
  143. Env: protoSpan.Env,
  144. StartTime: timeFromTimestamp(protoSpan.StartTime),
  145. Duration: durationFromDuration(protoSpan.Duration),
  146. }
  147. span.References = make([]SpanRef, 0, len(protoSpan.References))
  148. for _, ref := range protoSpan.References {
  149. span.References = append(span.References, convertSpanRef(ref))
  150. }
  151. span.Tags = make(map[string]interface{})
  152. for _, tag := range protoSpan.Tags {
  153. newTag := convertTag(tag)
  154. span.Tags[newTag.Key] = newTag.Value
  155. }
  156. if !parseLog {
  157. return span, nil
  158. }
  159. span.Logs = make([]Log, 0, len(protoSpan.Logs))
  160. for _, log := range protoSpan.Logs {
  161. span.Logs = append(span.Logs, convertLog(log))
  162. }
  163. return span, nil
  164. }
  165. // ParseProtoSpanTag tag
  166. func ParseProtoSpanTag(protoSpan *protogen.Span) map[string]interface{} {
  167. tagMap := make(map[string]interface{})
  168. var convertFn func(*protogen.Tag) Tag
  169. if protoSpan.Version == protoVersion2 {
  170. convertFn = convertTag
  171. } else {
  172. convertFn = convertLeagcyTag
  173. }
  174. for _, protoTag := range protoSpan.Tags {
  175. tag := convertFn(protoTag)
  176. tagMap[tag.Key] = tag.Value
  177. }
  178. return tagMap
  179. }
  180. func serializeInt64(v int64) []byte {
  181. data := make([]byte, 8)
  182. binary.BigEndian.PutUint64(data, uint64(v))
  183. return data
  184. }
  185. func serializeFloat64(v float64) []byte {
  186. data := make([]byte, 8)
  187. binary.BigEndian.PutUint64(data, math.Float64bits(v))
  188. return data
  189. }
  190. func serializeBool(v bool) []byte {
  191. data := make([]byte, 1)
  192. if v {
  193. data[0] = byte(1)
  194. } else {
  195. data[0] = byte(0)
  196. }
  197. return data
  198. }
  199. func toProtoTag(key string, value interface{}) (*protogen.Tag, error) {
  200. ptag := &protogen.Tag{Key: key}
  201. switch value := value.(type) {
  202. case string:
  203. ptag.Kind = protogen.Tag_STRING
  204. ptag.Value = []byte(value)
  205. case int:
  206. ptag.Kind = protogen.Tag_INT
  207. ptag.Value = serializeInt64(int64(value))
  208. case int32:
  209. ptag.Kind = protogen.Tag_INT
  210. ptag.Value = serializeInt64(int64(value))
  211. case int64:
  212. ptag.Kind = protogen.Tag_INT
  213. ptag.Value = serializeInt64(value)
  214. case bool:
  215. ptag.Kind = protogen.Tag_BOOL
  216. ptag.Value = serializeBool(value)
  217. case float32:
  218. ptag.Kind = protogen.Tag_BOOL
  219. ptag.Value = serializeFloat64(float64(value))
  220. case float64:
  221. ptag.Kind = protogen.Tag_BOOL
  222. ptag.Value = serializeFloat64(value)
  223. default:
  224. return nil, fmt.Errorf("invalid tag type %T", value)
  225. }
  226. return ptag, nil
  227. }