trace.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. package blademaster
  2. import (
  3. "io"
  4. "net/http"
  5. "net/http/httptrace"
  6. "strconv"
  7. "go-common/library/net/metadata"
  8. "go-common/library/net/trace"
  9. )
  10. const _defaultComponentName = "net/http"
  11. // Trace is trace middleware
  12. func Trace() HandlerFunc {
  13. return func(c *Context) {
  14. // handle http request
  15. // get derived trace from http request header
  16. t, err := trace.Extract(trace.HTTPFormat, c.Request.Header)
  17. if err != nil {
  18. var opts []trace.Option
  19. if ok, _ := strconv.ParseBool(trace.BiliTraceDebug); ok {
  20. opts = append(opts, trace.EnableDebug())
  21. }
  22. t = trace.New(c.Request.URL.Path, opts...)
  23. }
  24. t.SetTitle(c.Request.URL.Path)
  25. t.SetTag(trace.String(trace.TagComponent, _defaultComponentName))
  26. t.SetTag(trace.String(trace.TagHTTPMethod, c.Request.Method))
  27. t.SetTag(trace.String(trace.TagHTTPURL, c.Request.URL.String()))
  28. t.SetTag(trace.String(trace.TagSpanKind, "server"))
  29. t.SetTag(trace.String("caller", metadata.String(c.Context, metadata.Caller)))
  30. c.Context = trace.NewContext(c.Context, t)
  31. c.Next()
  32. t.Finish(&c.Error)
  33. }
  34. }
  35. type closeTracker struct {
  36. io.ReadCloser
  37. tr trace.Trace
  38. }
  39. func (c *closeTracker) Close() error {
  40. err := c.ReadCloser.Close()
  41. c.tr.SetLog(trace.Log(trace.LogEvent, "ClosedBody"))
  42. c.tr.Finish(&err)
  43. return err
  44. }
  45. // NewTraceTracesport NewTraceTracesport
  46. func NewTraceTracesport(rt http.RoundTripper, peerService string, internalTags ...trace.Tag) *TraceTransport {
  47. return &TraceTransport{RoundTripper: rt, peerService: peerService, internalTags: internalTags}
  48. }
  49. // TraceTransport wraps a RoundTripper. If a request is being traced with
  50. // Tracer, Transport will inject the current span into the headers,
  51. // and set HTTP related tags on the span.
  52. type TraceTransport struct {
  53. peerService string
  54. internalTags []trace.Tag
  55. // The actual RoundTripper to use for the request. A nil
  56. // RoundTripper defaults to http.DefaultTransport.
  57. http.RoundTripper
  58. }
  59. // RoundTrip implements the RoundTripper interface
  60. func (t *TraceTransport) RoundTrip(req *http.Request) (*http.Response, error) {
  61. rt := t.RoundTripper
  62. if rt == nil {
  63. rt = http.DefaultTransport
  64. }
  65. tr, ok := trace.FromContext(req.Context())
  66. if !ok {
  67. return rt.RoundTrip(req)
  68. }
  69. operationName := "HTTP:" + req.Method
  70. // fork new trace
  71. tr = tr.Fork("", operationName)
  72. tr.SetTag(trace.TagString(trace.TagComponent, _defaultComponentName))
  73. tr.SetTag(trace.TagString(trace.TagHTTPMethod, req.Method))
  74. tr.SetTag(trace.TagString(trace.TagHTTPURL, req.URL.String()))
  75. tr.SetTag(trace.TagString(trace.TagSpanKind, "client"))
  76. if t.peerService != "" {
  77. tr.SetTag(trace.TagString(trace.TagPeerService, t.peerService))
  78. }
  79. tr.SetTag(t.internalTags...)
  80. // inject trace to http header
  81. trace.Inject(tr, trace.HTTPFormat, req.Header)
  82. // FIXME: uncomment after trace sdk is goroutinue safe
  83. // ct := clientTracer{tr: tr}
  84. // req = req.WithContext(httptrace.WithClientTrace(req.Context(), ct.clientTrace()))
  85. resp, err := rt.RoundTrip(req)
  86. if err != nil {
  87. tr.SetTag(trace.TagBool(trace.TagError, true))
  88. tr.Finish(&err)
  89. return resp, err
  90. }
  91. // TODO: get ecode
  92. tr.SetTag(trace.TagInt64(trace.TagHTTPStatusCode, int64(resp.StatusCode)))
  93. if req.Method == "HEAD" {
  94. tr.Finish(nil)
  95. } else {
  96. resp.Body = &closeTracker{resp.Body, tr}
  97. }
  98. return resp, err
  99. }
  100. type clientTracer struct {
  101. tr trace.Trace
  102. }
  103. func (h *clientTracer) clientTrace() *httptrace.ClientTrace {
  104. return &httptrace.ClientTrace{
  105. GetConn: h.getConn,
  106. GotConn: h.gotConn,
  107. PutIdleConn: h.putIdleConn,
  108. GotFirstResponseByte: h.gotFirstResponseByte,
  109. Got100Continue: h.got100Continue,
  110. DNSStart: h.dnsStart,
  111. DNSDone: h.dnsDone,
  112. ConnectStart: h.connectStart,
  113. ConnectDone: h.connectDone,
  114. WroteHeaders: h.wroteHeaders,
  115. Wait100Continue: h.wait100Continue,
  116. WroteRequest: h.wroteRequest,
  117. }
  118. }
  119. func (h *clientTracer) getConn(hostPort string) {
  120. // ext.HTTPUrl.Set(h.sp, hostPort)
  121. h.tr.SetLog(trace.Log(trace.LogEvent, "GetConn"))
  122. }
  123. func (h *clientTracer) gotConn(info httptrace.GotConnInfo) {
  124. h.tr.SetTag(trace.TagBool("net/http.reused", info.Reused))
  125. h.tr.SetTag(trace.TagBool("net/http.was_idle", info.WasIdle))
  126. h.tr.SetLog(trace.Log(trace.LogEvent, "GotConn"))
  127. }
  128. func (h *clientTracer) putIdleConn(error) {
  129. h.tr.SetLog(trace.Log(trace.LogEvent, "PutIdleConn"))
  130. }
  131. func (h *clientTracer) gotFirstResponseByte() {
  132. h.tr.SetLog(trace.Log(trace.LogEvent, "GotFirstResponseByte"))
  133. }
  134. func (h *clientTracer) got100Continue() {
  135. h.tr.SetLog(trace.Log(trace.LogEvent, "Got100Continue"))
  136. }
  137. func (h *clientTracer) dnsStart(info httptrace.DNSStartInfo) {
  138. h.tr.SetLog(
  139. trace.Log(trace.LogEvent, "DNSStart"),
  140. trace.Log("host", info.Host),
  141. )
  142. }
  143. func (h *clientTracer) dnsDone(info httptrace.DNSDoneInfo) {
  144. fields := []trace.LogField{trace.Log(trace.LogEvent, "DNSDone")}
  145. for _, addr := range info.Addrs {
  146. fields = append(fields, trace.Log("addr", addr.String()))
  147. }
  148. if info.Err != nil {
  149. // TODO: support log error object
  150. fields = append(fields, trace.Log(trace.LogErrorObject, info.Err.Error()))
  151. }
  152. h.tr.SetLog(fields...)
  153. }
  154. func (h *clientTracer) connectStart(network, addr string) {
  155. h.tr.SetLog(
  156. trace.Log(trace.LogEvent, "ConnectStart"),
  157. trace.Log("network", network),
  158. trace.Log("addr", addr),
  159. )
  160. }
  161. func (h *clientTracer) connectDone(network, addr string, err error) {
  162. if err != nil {
  163. h.tr.SetLog(
  164. trace.Log("message", "ConnectDone"),
  165. trace.Log("network", network),
  166. trace.Log("addr", addr),
  167. trace.Log(trace.LogEvent, "error"),
  168. // TODO: support log error object
  169. trace.Log(trace.LogErrorObject, err.Error()),
  170. )
  171. } else {
  172. h.tr.SetLog(
  173. trace.Log(trace.LogEvent, "ConnectDone"),
  174. trace.Log("network", network),
  175. trace.Log("addr", addr),
  176. )
  177. }
  178. }
  179. func (h *clientTracer) wroteHeaders() {
  180. h.tr.SetLog(trace.Log("event", "WroteHeaders"))
  181. }
  182. func (h *clientTracer) wait100Continue() {
  183. h.tr.SetLog(trace.Log("event", "Wait100Continue"))
  184. }
  185. func (h *clientTracer) wroteRequest(info httptrace.WroteRequestInfo) {
  186. if info.Err != nil {
  187. h.tr.SetLog(
  188. trace.Log("message", "WroteRequest"),
  189. trace.Log("event", "error"),
  190. // TODO: support log error object
  191. trace.Log(trace.LogErrorObject, info.Err.Error()),
  192. )
  193. h.tr.SetTag(trace.TagBool(trace.TagError, true))
  194. } else {
  195. h.tr.SetLog(trace.Log("event", "WroteRequest"))
  196. }
  197. }