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  }