github.com/weedge/lib@v0.0.0-20230424045628-a36dcc1d90e4/log/tapper/trace_ctx.go (about)

     1  package tapper
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"strconv"
     8  	"sync"
     9  
    10  	hack "github.com/weedge/lib/strings"
    11  
    12  	"github.com/gin-gonic/gin"
    13  	jsoniter "github.com/json-iterator/go"
    14  	"go.uber.org/atomic"
    15  )
    16  
    17  const (
    18  	TRACECTX = "TRACECTX"
    19  	TRACELOG = "TRACELOG"
    20  )
    21  
    22  type Trace struct {
    23  	data map[string]interface{}
    24  	mu   sync.Mutex
    25  }
    26  
    27  func (trace *Trace) Marshal() string {
    28  	trace.mu.Lock()
    29  	defer trace.mu.Unlock()
    30  
    31  	b, _ := jsoniter.MarshalToString(trace.data)
    32  	return b
    33  }
    34  func (trace *Trace) Push(args ...interface{}) *Trace {
    35  	trace.mu.Lock()
    36  	defer trace.mu.Unlock()
    37  
    38  	for i := 0; i < len(args)-1; i += 2 {
    39  		switch args[i+1].(type) {
    40  		case string, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
    41  			trace.data[fmt.Sprintf("%v", args[i])] = args[i+1]
    42  		default:
    43  			if b, e := jsoniter.Marshal(args[i+1]); e == nil {
    44  				trace.data[fmt.Sprintf("%v", args[i])] = hack.String(b)
    45  			}
    46  		}
    47  	}
    48  	return trace
    49  }
    50  
    51  func GetTraceFromContext(ctx context.Context) (context.Context, *Trace) {
    52  	switch c := ctx.(type) {
    53  	case *gin.Context:
    54  		if trace, ok := c.Get(TRACECTX); ok && trace != nil {
    55  			if trace, ok := trace.(*Trace); ok && trace != nil {
    56  				return ctx, trace
    57  			}
    58  		}
    59  
    60  		trace := &Trace{data: map[string]interface{}{}}
    61  		c.Set(TRACECTX, trace)
    62  		return ctx, trace
    63  
    64  	case nil:
    65  	default:
    66  	}
    67  
    68  	trace := &Trace{data: map[string]interface{}{}}
    69  	return ctx, trace
    70  }
    71  
    72  // 参数args: [key value]...
    73  func PushTrace(ctx context.Context, args ...interface{}) {
    74  	ctx, trace := GetTraceFromContext(ctx)
    75  	trace.Push(args...)
    76  }
    77  
    78  type TraceLog struct {
    79  	SpanNum atomic.Int64 //用于计算本地spanId自增拼接
    80  	LogId   string
    81  	SpanId  string
    82  	UniqId  string
    83  
    84  	UserIP  string
    85  	Product string
    86  
    87  	Caller string
    88  	Refer  string
    89  	Path   string // 当前请求的地址,用作请求下游时,设置成refer
    90  
    91  	MqTransId string //mq tranId 比如mq push模式 push uri地址参数中会有带上事务id
    92  }
    93  
    94  func (tl *TraceLog) FormatTraceString() string {
    95  	spidSuffixNum := tl.SpanNum.Inc()
    96  	bf := bytes.Buffer{}
    97  	bf.WriteString(" [logId:")
    98  	bf.WriteString(tl.LogId)
    99  	bf.WriteString("] [module:")
   100  	bf.WriteString(tl.Caller)
   101  	bf.WriteString("] [spanId:")
   102  	spanId := ""
   103  	if len(tl.SpanId) > 0 {
   104  		spanId = tl.SpanId + "." + strconv.FormatInt(spidSuffixNum, 10)
   105  	} else {
   106  		spanId = strconv.FormatInt(spidSuffixNum, 10)
   107  	}
   108  	bf.WriteString(spanId)
   109  	if len(tl.MqTransId) > 0 {
   110  		bf.WriteString("] [mq_transId:")
   111  		bf.WriteString(tl.MqTransId)
   112  	}
   113  	bf.WriteString("]")
   114  	return bf.String()
   115  }
   116  
   117  func (tl *TraceLog) GetCurrentSpanId() string {
   118  	if len(tl.SpanId) > 0 {
   119  		return tl.SpanId + "." + strconv.FormatInt(tl.SpanNum.Load(), 10)
   120  	}
   121  	return strconv.FormatInt(tl.SpanNum.Load(), 10)
   122  }
   123  
   124  var EmptyTraceLog = &TraceLog{}
   125  
   126  // 从context中获取span信息集合
   127  func GetTraceLogFromContext(ctx context.Context) (context.Context, *TraceLog) {
   128  	if span := ctx.Value(TRACELOG); span != nil {
   129  		traceLog, _ := span.(*TraceLog)
   130  		return ctx, traceLog
   131  	}
   132  
   133  	logId := GenLogId()
   134  	traceLog := &TraceLog{
   135  		LogId:  logId,
   136  		UniqId: "",
   137  		Caller: "",
   138  		Refer:  "",
   139  	}
   140  	ctx = context.WithValue(ctx, TRACELOG, traceLog)
   141  	return ctx, traceLog
   142  }
   143  
   144  // 从gin context中获取span信息集合
   145  func GetTraceLogFromGinContext(ctx context.Context) (*TraceLog, bool) {
   146  	var ok bool
   147  	var c *gin.Context
   148  
   149  	if c, ok = ctx.(*gin.Context); !ok {
   150  		return EmptyTraceLog, false
   151  	}
   152  
   153  	var traceLog *TraceLog
   154  	if value, exists := c.Get(TRACELOG); exists && value != nil {
   155  		if traceLog, ok = value.(*TraceLog); traceLog != nil && ok {
   156  			return traceLog, true
   157  		}
   158  	}
   159  
   160  	return TraceLogger.SetTraceLogFromGinHeader(c), true
   161  }
   162