195 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			195 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Package request ...
 | 
						|
//
 | 
						|
// Description : request ...
 | 
						|
//
 | 
						|
// Author : go_developer@163.com<白茶清欢>
 | 
						|
//
 | 
						|
// Date : 2025-02-28 11:45
 | 
						|
package request
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	networkUtil "git.zhangdeman.cn/zhangdeman/network/util"
 | 
						|
	"git.zhangdeman.cn/zhangdeman/wrapper"
 | 
						|
	"github.com/gin-gonic/gin"
 | 
						|
	"git.zhangdeman.cn/zhangdeman/trace"
 | 
						|
	"os"
 | 
						|
	"strings"
 | 
						|
	"sync"
 | 
						|
	"time"
 | 
						|
)
 | 
						|
 | 
						|
// getTraceID 生成traceID
 | 
						|
//
 | 
						|
// Author : go_developer@163.com<白茶清欢>
 | 
						|
//
 | 
						|
// Date : 23:12 2022/6/25
 | 
						|
func getTraceID(ctx *gin.Context) string {
 | 
						|
	hostname, _ := os.Hostname()
 | 
						|
	if hostname != "" {
 | 
						|
		hostname = "unknown"
 | 
						|
	}
 | 
						|
	return fmt.Sprintf(
 | 
						|
		"%v-%v-%v-%v-%v",
 | 
						|
		time.Now().UnixNano()/1e6,
 | 
						|
		strings.ReplaceAll(networkUtil.IP.GetHostIP(), ".", ""),
 | 
						|
		strings.ReplaceAll(hostname, ".", ""),
 | 
						|
		strings.ReplaceAll(networkUtil.IP.GetRemoteIP(ctx.Request), ".", ""),
 | 
						|
		wrapper.StringFromRandom(32, "").Md5().Value,
 | 
						|
	)
 | 
						|
}
 | 
						|
 | 
						|
// getRequestID 生成requestID
 | 
						|
//
 | 
						|
// Author : go_developer@163.com<白茶清欢>
 | 
						|
//
 | 
						|
// Date : 23:12 2022/6/25
 | 
						|
func getRequestID(ctx *gin.Context, traceID string) string {
 | 
						|
	requestID := ctx.GetHeader("X-Forward-Request-Id")
 | 
						|
	if len(requestID) > 0 {
 | 
						|
		return requestID
 | 
						|
	}
 | 
						|
	if len(traceID) > 0 {
 | 
						|
		return traceID
 | 
						|
	}
 | 
						|
	return getTraceID(ctx)
 | 
						|
}
 | 
						|
 | 
						|
// NewContext 获取context实例
 | 
						|
//
 | 
						|
// Author : go_developer@163.com<白茶清欢>
 | 
						|
//
 | 
						|
// Date : 12:01 2025/2/28
 | 
						|
func NewContext(ginContext *gin.Context) *Context {
 | 
						|
	// 生成traceID
 | 
						|
	traceID := getRequestID(ginContext, "")
 | 
						|
	return &Context{
 | 
						|
		Context:              ginContext,
 | 
						|
		StartRequestTime:     time.Now(),
 | 
						|
		FinishRequestTime:    time.Time(int64(0)),
 | 
						|
		HandlerAfterResponse: make([]gin.HandlerFunc, 0),
 | 
						|
		CustomData:           make(map[string]any),
 | 
						|
		lock:                 &sync.RWMutex{},
 | 
						|
		TraceID:              traceID,
 | 
						|
		Trace:                trace.NewRuntime(traceID, 0),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Context 请求上下文信息, 对 ctx *gin.Context的二次包装
 | 
						|
//
 | 
						|
// Author : go_developer@163.com<白茶清欢>
 | 
						|
//
 | 
						|
// Date : 11:45 2025/2/28
 | 
						|
type Context struct {
 | 
						|
	*gin.Context         `json:"-"`
 | 
						|
	StartRequestTime     time.Time // 开始请求时间(全局)
 | 
						|
	FinishRequestTime    time.Time // 结束请求时间(全局)
 | 
						|
	TraceID              string            `json:"trace_id"`        // 请求trace_id
 | 
						|
	ParentAppName        string            `json:"parent_app_name"` // 父级应用名称
 | 
						|
	HandlerAfterResponse []gin.HandlerFunc `json:"-"`               // 响应数据之后需要执行的逻辑
 | 
						|
	CustomData           map[string]any    // 业务上下文自定义数据, 可以合 ginCtx.Value 作区分
 | 
						|
	lock                 *sync.RWMutex
 | 
						|
	Trace                *trace.Runtime `json:"-"` // 追踪实例
 | 
						|
}
 | 
						|
 | 
						|
// SetCustom 设置数据
 | 
						|
//
 | 
						|
// Author : go_developer@163.com<白茶清欢>
 | 
						|
//
 | 
						|
// Date : 11:58 2025/2/28
 | 
						|
func (ctx *Context) SetCustom(key string, val any) {
 | 
						|
	ctx.lock.Lock()
 | 
						|
	defer ctx.lock.Unlock()
 | 
						|
	if nil == ctx.CustomData {
 | 
						|
		ctx.CustomData = make(map[string]any)
 | 
						|
	}
 | 
						|
	ctx.CustomData[key] = val
 | 
						|
}
 | 
						|
 | 
						|
// CustomDataValue 获取customData
 | 
						|
//
 | 
						|
// Author : go_developer@163.com<白茶清欢>
 | 
						|
//
 | 
						|
// Date : 12:03 2025/2/28
 | 
						|
func (ctx *Context) CustomDataValue(key string) any {
 | 
						|
	ctx.lock.RLock()
 | 
						|
	defer ctx.lock.RUnlock()
 | 
						|
	if val, exist := ctx.CustomData[key]; exist {
 | 
						|
		return val
 | 
						|
	} else {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// CustomDataExist 判断
 | 
						|
//
 | 
						|
// Author : go_developer@163.com<白茶清欢>
 | 
						|
//
 | 
						|
// Date : 12:04 2025/2/28
 | 
						|
func (ctx *Context) CustomDataExist(key string) any {
 | 
						|
	ctx.lock.RLock()
 | 
						|
	defer ctx.lock.RUnlock()
 | 
						|
	_, exist := ctx.CustomData[key]
 | 
						|
	return exist
 | 
						|
}
 | 
						|
 | 
						|
// CustomDataAppend 向数组数据中追加元素
 | 
						|
//
 | 
						|
// Author : go_developer@163.com<白茶清欢>
 | 
						|
//
 | 
						|
// Date : 12:07 2025/2/28
 | 
						|
func (ctx *Context) CustomDataAppend(key string, appendValue any) {
 | 
						|
	ctx.lock.Lock()
 | 
						|
	defer ctx.lock.Unlock()
 | 
						|
	val, exist := ctx.CustomData[key]
 | 
						|
	if !exist || nil == val {
 | 
						|
		ctx.CustomData[key] = []any{appendValue}
 | 
						|
		return
 | 
						|
	}
 | 
						|
	if valArr, ok := val.([]any); ok {
 | 
						|
		valArr = append(valArr, appendValue)
 | 
						|
		ctx.CustomData[key] = valArr
 | 
						|
	}
 | 
						|
	// 非数组, 忽略追加行为
 | 
						|
}
 | 
						|
 | 
						|
// CustomDataAppendProperty 向一个map中追加/更新属性
 | 
						|
//
 | 
						|
// Author : go_developer@163.com<白茶清欢>
 | 
						|
//
 | 
						|
// Date : 12:11 2025/2/28
 | 
						|
func (ctx *Context) CustomDataAppendProperty(key string, appendKey string, appendValue any) {
 | 
						|
	ctx.lock.Lock()
 | 
						|
	defer ctx.lock.Unlock()
 | 
						|
	val, exist := ctx.CustomData[key]
 | 
						|
	if !exist || nil == val {
 | 
						|
		ctx.CustomData[key] = map[string]any{
 | 
						|
			appendKey: appendValue,
 | 
						|
		}
 | 
						|
		return
 | 
						|
	}
 | 
						|
	if valMap, ok := val.(map[string]any); ok {
 | 
						|
		valMap[appendKey] = appendValue
 | 
						|
		ctx.CustomData[key] = valMap
 | 
						|
	}
 | 
						|
	// 非map, 忽略追加行为
 | 
						|
}
 | 
						|
 | 
						|
// TraceStart 开始监控
 | 
						|
//
 | 
						|
// Author : go_developer@163.com<白茶清欢>
 | 
						|
//
 | 
						|
// Date : 12:24 2025/2/28
 | 
						|
func (ctx *Context) TraceStart(action string, actionData map[string]any) int {
 | 
						|
	return ctx.Trace.StartBehavior(action, actionData)
 | 
						|
}
 | 
						|
 | 
						|
// TraceEnd 完成监控
 | 
						|
//
 | 
						|
// Author : go_developer@163.com<白茶清欢>
 | 
						|
//
 | 
						|
// Date : 12:24 2025/2/28
 | 
						|
func (ctx *Context) TraceEnd(behaviorID int, endData map[string]any) {
 | 
						|
	ctx.Trace.FinishBehavior(behaviorID, endData)
 | 
						|
}
 |