github.com/zooyer/miskit@v1.0.71/trace/trace.go (about) 1 package trace 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/hex" 7 "encoding/json" 8 "fmt" 9 "math/rand" 10 "net" 11 "net/http" 12 "os" 13 "sync" 14 "time" 15 16 "github.com/gin-gonic/gin" 17 ) 18 19 type Trace struct { 20 Callee string `json:"callee,omitempty"` 21 Caller string `json:"caller,omitempty"` 22 TraceID string `json:"trace_id,omitempty"` 23 SpanID string `json:"span_id,omitempty"` 24 ChildID string `json:"child_id,omitempty"` 25 Lang string `json:"lang,omitempty"` 26 Tag string `json:"tag,omitempty"` 27 Content json.RawMessage `json:"content,omitempty"` 28 Request *http.Request `json:"-"` 29 } 30 31 const ( 32 httpHeaderKeyTraceID = "Z-TraceID" 33 httpHeaderKeySpanID = "Z-SpanID" 34 httpHeaderKeyLang = "Z-Lang" 35 httpHeaderKeyTag = "Z-Tag" 36 httpHeaderKeyCaller = "Z-Caller" 37 httpHeaderKeyContent = "Z-Content" 38 ) 39 40 const ( 41 contextKey = "z-context" 42 ) 43 44 var ( 45 pool = sync.Pool{ 46 New: func() interface{} { 47 return &bytes.Buffer{} 48 }, 49 } 50 ) 51 52 func New(req *http.Request, callee string) *Trace { 53 var trace = new(Trace) 54 55 trace.Callee = callee 56 57 if req != nil { 58 trace.TraceID = req.Header.Get(httpHeaderKeyTraceID) 59 trace.Caller = req.Header.Get(httpHeaderKeyCaller) 60 trace.SpanID = req.Header.Get(httpHeaderKeySpanID) 61 trace.Lang = req.Header.Get(httpHeaderKeyLang) 62 trace.Tag = req.Header.Get(httpHeaderKeyTag) 63 trace.Content = []byte(req.Header.Get(httpHeaderKeyContent)) 64 trace.Request = req 65 } 66 67 if trace.TraceID == "" { 68 trace.TraceID = genTraceID() 69 } 70 71 return trace 72 } 73 74 func Set(ctx context.Context, trace *Trace) context.Context { 75 if trace == nil { 76 return ctx 77 } 78 79 switch ctx := ctx.(type) { 80 case *gin.Context: 81 ctx.Set(contextKey, trace) 82 default: 83 return context.WithValue(ctx, contextKey, trace) 84 } 85 86 return ctx 87 } 88 89 func Get(ctx context.Context) *Trace { 90 var trace *Trace 91 switch ctx := ctx.(type) { 92 case *gin.Context: 93 if value, exists := ctx.Get(contextKey); exists { 94 trace, _ = value.(*Trace) 95 } 96 default: 97 trace, _ = ctx.Value(contextKey).(*Trace) 98 } 99 return trace 100 } 101 102 // SetHeader 设置到请求头 103 func (t *Trace) SetHeader(header http.Header) { 104 if t == nil { 105 return 106 } 107 108 if t.TraceID != "" { 109 header.Set(httpHeaderKeyTraceID, t.TraceID) 110 } else { 111 header.Set(httpHeaderKeyTraceID, genTraceID()) 112 } 113 header.Set(httpHeaderKeySpanID, genSpanID()) 114 if t.Lang != "" { 115 header.Set(httpHeaderKeyLang, t.Lang) 116 } 117 if t.Tag != "" { 118 header.Set(httpHeaderKeyTag, t.Tag) 119 } 120 if t.Callee != "" { 121 header.Set(httpHeaderKeyCaller, t.Callee) 122 } 123 if len(t.Content) > 0 { 124 header.Set(httpHeaderKeyContent, string(t.Content)) 125 } 126 } 127 128 // GenChild 生成子trace 129 func (t *Trace) GenChild() *Trace { 130 if t == nil { 131 return nil 132 } 133 134 var trace Trace 135 136 trace = *t 137 trace.Content = make(json.RawMessage, len(t.Content)) 138 copy(trace.Content, t.Content) 139 trace.SpanID = genSpanID() 140 141 return &trace 142 } 143 144 // Clone 深度拷贝克隆 145 func (t *Trace) Clone() *Trace { 146 if t == nil { 147 return nil 148 } 149 150 var trace Trace 151 152 trace = *t 153 trace.Content = make(json.RawMessage, len(t.Content)) 154 copy(trace.Content, t.Content) 155 156 return &trace 157 } 158 159 // String 序列化成字符串 160 func (t *Trace) String() string { 161 data, _ := json.Marshal(t) 162 return string(data) 163 } 164 165 // genTraceID 生成trace id 166 func genTraceID() string { 167 pid := os.Getegid() 168 now := time.Now() 169 unix := now.Unix() 170 nano := now.UnixNano() 171 172 var buf = pool.Get().(*bytes.Buffer) 173 defer pool.Put(buf) 174 defer buf.Reset() 175 176 buf.WriteString(hex.EncodeToString(net.ParseIP(getLocalIP()).To4())) 177 buf.WriteString(fmt.Sprintf("%x", unix&0xffffffff)) 178 buf.WriteString(fmt.Sprintf("%04x", nano&0xffff)) 179 buf.WriteString(fmt.Sprintf("%04x", pid&0xffff)) 180 buf.WriteString(fmt.Sprintf("%06x", rand.Int31n(1<<24))) 181 buf.WriteString("5a") 182 183 return buf.String() 184 } 185 186 // genSpanID 生成 187 func genSpanID() string { 188 return fmt.Sprintf("%x", rand.Int63()) 189 } 190 191 // getLocalIP 获取本机IP地址 192 func getLocalIP() string { 193 addr, err := net.InterfaceAddrs() 194 if err != nil { 195 return "0.0.0.0" 196 } 197 198 for _, addr := range addr { 199 if ip, ok := addr.(*net.IPNet); ok && ip.IP.IsGlobalUnicast() { 200 return ip.IP.String() 201 } 202 } 203 204 return "127.0.0.1" 205 }