Golang中如何将请求头X-Trace-ID传入LokiLogs添加至日志
如何将API请求的X-Trace-ID传递给Loki日志函数
要实现把每个API请求的X-Trace-ID头值传递给LokiLogs函数,核心是通过**请求上下文(context)**在Gin请求链路、数据库操作、日志打印之间传递traceId,具体步骤如下:
1. 在Gin中间件中把traceId存入请求context
除了设置请求头,还要将traceId存入请求的context,这样后续数据库操作和日志打印就能获取到:
import ( "context" "github.com/gin-gonic/gin" "github.com/google/uuid" ) func TraceIdMiddleware() gin.HandlerFunc { return func(c *gin.Context) { traceID := uuid.NewString() // 替换成你实际生成traceId的逻辑 c.Request.Header.Set("X-Trace-ID", traceID) // 将traceId存入请求context ctx := context.WithValue(c.Request.Context(), "traceId", traceID) c.Request = c.Request.WithContext(ctx) c.Next() } } // 在main中注册中间件 func main() { router := gin.Default() router.Use(TraceIdMiddleware()) // ...其他路由注册 db.LogMode(true) db.SetLogger(&StdoutLogger{os.Stdout}) router.Run() }
2. 修改StdoutLogger的Print方法,提取context中的traceId
GORM在执行带context的数据库操作时,会把context作为第一个参数传入Logger的Print方法,我们可以从中提取traceId:
import "context" type StdoutLogger struct { io.Writer } func (l *StdoutLogger) Print(v ...interface{}) { traceId := "" // 尝试从参数中获取context并提取traceId if len(v) > 0 { if ctx, ok := v[0].(context.Context); ok { if tid, ok := ctx.Value("traceId").(string); ok { traceId = tid } } } vv := LogFormatter(v...) log.Println(vv) if len(vv.Message) > 0 { slice := vv.Message[0] logMsg := slice.Sql + " " + slice.SqlMessage // 把traceId传递给LokiLogs LokiLogs(logMsg, traceId) } }
3. 更新LokiLogs函数,接收并拼接traceId
修改LokiLogs的函数签名,新增traceId参数,将其拼接到日志消息中:
func LokiLogs(msg string, traceId string) { v := strconv.FormatInt(time.Now().UnixNano(), 10) // 仅当traceId不为空时拼接 if traceId != "" { msg = msg + " traceId=" + traceId } Lokijson := map[string]interface{}{ "streams": []interface{}{ map[string]interface{}{ "stream": map[string]interface{}{ "message": msg, "client_ip": GetOutboundIP(), "level": "info", "job": "Test", }, "values": []interface{}{ []interface{}{ string(v), msg, }, }, }, }, } jsonValue, _ := json.Marshal(Lokijson) url := os.Getenv("LOKI_URL") resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonValue)) fmt.Println(resp, err) }
4. 确保数据库操作使用带traceId的context
在Gin的请求处理函数中,执行数据库操作时必须传入请求的context,这样GORM才会把context传递给Logger:
router.GET("/users/:id", func(c *gin.Context) { var user User // 使用c.Request.Context(),包含traceId的上下文 err := db.WithContext(c.Request.Context()).First(&user, c.Param("id")).Error if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, user) })
内容的提问来源于stack exchange,提问作者Hari Prasanth
相关产品推荐
相关产品推荐

