trace.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package trace
  15. import (
  16. "fmt"
  17. "net/http"
  18. "strings"
  19. "time"
  20. "yunion.io/x/pkg/util/timeutils"
  21. "yunion.io/x/pkg/utils"
  22. )
  23. type TraceKind string
  24. const UNKNOWN_SERVICE_NAME string = "(unknown_service)"
  25. const (
  26. X_YUNION_PEER_SERVICE_NAME = "X-Yunion-Peer-Service-Name"
  27. // X_YUNION_SERVICE_NAME = "X-Yunion-Service-Name"
  28. X_YUNION_TRACE_ID = "X-Yunion-STrace-Id"
  29. X_YUNION_SPAN_NAME = "X-Yunion-Span-Name"
  30. X_YUNION_PARENT_ID = "X-Yunion-Parent-Id"
  31. X_YUNION_SPAN_ID = "X-Yunion-Span-Id"
  32. X_YUNION_TRACE_DEBUG = "X-Yunion-STrace-Debug"
  33. X_YUNION_REMOTE_ADDR = "X-Yunion-Remote-Addr"
  34. X_YUNION_TRACE_TAG = "X-Yunion-STrace-Tag-"
  35. )
  36. const (
  37. TRACE_KIND_CLIENT TraceKind = "CLIENT"
  38. TRACE_KIND_SERVER TraceKind = "SERVER"
  39. )
  40. type STraceEndpoint struct {
  41. ServiceName string
  42. Addr string
  43. Port int
  44. }
  45. type STrace struct {
  46. TraceId string
  47. Name string
  48. ParentId string
  49. Id string
  50. clientId int // valid for ServerTrace
  51. Kind TraceKind
  52. Timestamp time.Time
  53. Duration time.Duration
  54. Debug bool
  55. Shared bool
  56. LocalEndpoint STraceEndpoint
  57. RemoteEndpoint STraceEndpoint
  58. Tags map[string]string
  59. }
  60. func (tr *STrace) IsZero() bool {
  61. return len(tr.TraceId) == 0
  62. }
  63. func (tr *STrace) String() string {
  64. return fmt.Sprintf("[%s %s.%s] %s %s %fms", timeutils.ShortDate(tr.Timestamp), tr.TraceId, tr.Id,
  65. tr.Kind, tr.Name, tr.Duration.Seconds()*1000)
  66. }
  67. func StartServerTrace(w http.ResponseWriter, r *http.Request, localSpanName string, localServiceName string, srvTags map[string]string) *STrace {
  68. traceId := r.Header.Get(X_YUNION_TRACE_ID)
  69. var spanId string
  70. var spanName string
  71. var parentId string
  72. var peerSrvName string
  73. var debug bool
  74. var localAddr string
  75. var localPort int
  76. var isBorder bool
  77. if len(traceId) == 0 {
  78. isBorder = true
  79. traceId = utils.GenRequestId(4)
  80. spanId = "0"
  81. spanName = localSpanName
  82. parentId = ""
  83. peerSrvName = UNKNOWN_SERVICE_NAME
  84. debug = true
  85. localAddr = ""
  86. localPort = 0
  87. } else {
  88. remoteAddr := r.Header.Get(X_YUNION_REMOTE_ADDR)
  89. if len(remoteAddr) > 0 {
  90. addr, port := utils.GetAddrPort(remoteAddr)
  91. localAddr = addr
  92. localPort = port
  93. }
  94. spanId = r.Header.Get(X_YUNION_SPAN_ID)
  95. spanName = localSpanName
  96. if len(spanName) == 0 {
  97. spanName = r.Header.Get(X_YUNION_SPAN_NAME)
  98. }
  99. parentId = r.Header.Get(X_YUNION_PARENT_ID)
  100. peerSrvName = r.Header.Get(X_YUNION_PEER_SERVICE_NAME)
  101. if r.Header.Get(X_YUNION_TRACE_DEBUG) == "true" {
  102. debug = true
  103. } else {
  104. debug = false
  105. }
  106. }
  107. shared := false
  108. localEp := STraceEndpoint{ServiceName: localServiceName,
  109. Addr: localAddr, Port: localPort}
  110. remoteEp := STraceEndpoint{ServiceName: peerSrvName}
  111. if len(r.RemoteAddr) != 0 {
  112. addr, port := utils.GetAddrPort(r.RemoteAddr)
  113. remoteEp.Addr = addr
  114. remoteEp.Port = port
  115. }
  116. var tags map[string]string
  117. if srvTags != nil {
  118. tags = make(map[string]string)
  119. for k, v := range srvTags {
  120. tags[k] = v
  121. }
  122. }
  123. trace := STrace{TraceId: traceId,
  124. Name: spanName,
  125. ParentId: parentId,
  126. Id: spanId,
  127. clientId: 0, // valid for ServerTrace
  128. Kind: TRACE_KIND_SERVER,
  129. Timestamp: time.Now(),
  130. Duration: 0,
  131. Debug: debug,
  132. Shared: shared,
  133. LocalEndpoint: localEp,
  134. RemoteEndpoint: remoteEp,
  135. Tags: tags,
  136. }
  137. if !isBorder {
  138. // do not distribute trace info across border
  139. w.Header().Set(X_YUNION_SPAN_NAME, spanName)
  140. w.Header().Set(X_YUNION_PEER_SERVICE_NAME, localServiceName)
  141. w.Header().Set(X_YUNION_REMOTE_ADDR, r.RemoteAddr)
  142. if tags != nil {
  143. for k, v := range tags {
  144. w.Header().Set(X_YUNION_TRACE_TAG+k, v)
  145. }
  146. }
  147. }
  148. return &trace
  149. }
  150. func (tr *STrace) EndTrace() {
  151. tr.Duration = time.Now().Sub(tr.Timestamp)
  152. SubmitTrace(tr)
  153. }
  154. func StartClientTrace(ctxTrace *STrace, remoteAddr string, remotePort int, localServiceName string) *STrace {
  155. var traceId string
  156. var parentId string
  157. var spanId string
  158. var debug bool
  159. var share bool
  160. if ctxTrace != nil {
  161. traceId = ctxTrace.TraceId
  162. parentId = ctxTrace.Id
  163. spanId = fmt.Sprintf("%s.%d", ctxTrace.Id, ctxTrace.clientId)
  164. ctxTrace.clientId += 1
  165. debug = ctxTrace.Debug
  166. share = ctxTrace.Shared
  167. } else {
  168. traceId = utils.GenRequestId(4)
  169. parentId = ""
  170. spanId = "0"
  171. debug = true
  172. share = false
  173. }
  174. localEp := STraceEndpoint{ServiceName: localServiceName,
  175. Addr: "", Port: 0}
  176. remoteEp := STraceEndpoint{ServiceName: "",
  177. Addr: remoteAddr, Port: remotePort}
  178. trace := STrace{TraceId: traceId,
  179. Name: "",
  180. ParentId: parentId,
  181. Id: spanId,
  182. Kind: TRACE_KIND_CLIENT,
  183. Timestamp: time.Now(),
  184. Duration: 0,
  185. Debug: debug,
  186. Shared: share,
  187. LocalEndpoint: localEp,
  188. RemoteEndpoint: remoteEp,
  189. }
  190. return &trace
  191. }
  192. func (tr *STrace) EndClientTraceHeader(header http.Header) {
  193. spanName := header.Get(X_YUNION_SPAN_NAME)
  194. srvName := header.Get(X_YUNION_PEER_SERVICE_NAME)
  195. localAddr := header.Get(X_YUNION_REMOTE_ADDR)
  196. tags := make(map[string]string)
  197. for k, v := range header {
  198. if strings.HasPrefix(k, X_YUNION_TRACE_TAG) {
  199. tagName := k[:len(X_YUNION_TRACE_TAG)]
  200. tags[tagName] = v[0]
  201. }
  202. }
  203. tr.EndClientTrace(spanName, srvName, localAddr, tags)
  204. }
  205. func (tr *STrace) EndClientTrace(spanName, remoteServiceName, localAddr string, tags map[string]string) {
  206. tr.Name = spanName
  207. tr.RemoteEndpoint.ServiceName = remoteServiceName
  208. var addr string
  209. var port int
  210. if len(localAddr) > 0 {
  211. addr, port = utils.GetAddrPort(localAddr)
  212. } else {
  213. addr = fmt.Sprintf("%s", utils.GetOutboundIP())
  214. }
  215. tr.LocalEndpoint.Addr = addr
  216. tr.LocalEndpoint.Port = port
  217. if tags != nil {
  218. if tr.Tags == nil {
  219. tr.Tags = make(map[string]string)
  220. }
  221. for k, v := range tags {
  222. tr.Tags[k] = v
  223. }
  224. }
  225. tr.EndTrace()
  226. }
  227. func (tr *STrace) AddClientRequestHeader(header http.Header) {
  228. header.Set(X_YUNION_TRACE_ID, tr.TraceId)
  229. header.Set(X_YUNION_REMOTE_ADDR, fmt.Sprintf("%s:%d", tr.RemoteEndpoint.Addr, tr.RemoteEndpoint.Port))
  230. header.Set(X_YUNION_SPAN_ID, tr.Id)
  231. header.Set(X_YUNION_SPAN_NAME, tr.Name)
  232. header.Set(X_YUNION_PARENT_ID, tr.ParentId)
  233. header.Set(X_YUNION_PEER_SERVICE_NAME, tr.LocalEndpoint.ServiceName)
  234. if tr.Debug {
  235. header.Set(X_YUNION_TRACE_DEBUG, "true")
  236. }
  237. }
  238. func SubmitTrace(trace *STrace) {
  239. }