我正在开发一个现有的应用程序,它是用Go编写的,使用的是gin、中间件等框架。此应用程序使用https://pkg.go.dev/log进行日志记录。
我正在尝试为API调用跟踪向日志添加一个请求id。
main.go
// Creates a router without any middleware by default
r := gin.New()
r.Use(middleware.RequestID())middleware.go
func (m *Middleware) CheckApiToken(allowWithoutAccessKey bool, validateTonce ...bool) gin.HandlerFunc {
return func(c *gin.Context) {
// Validate
.....
.....
logger.InitializeContext(c)
c.Next()
}
}
}
//RequestID is a middleware that injects a 'RequestID' into the context and header of each request.
func (m *Middleware) RequestID() gin.HandlerFunc {
return func(c *gin.Context) {
xRequestID := uuid.NewV4().String()
c.Request.Header.Set(logger.XRequestIDKey, xRequestID)
fmt.Printf("[GIN-debug] %s [%s] - \"%s %s\"\n", time.Now().Format(time.RFC3339), xRequestID, c.Request.Method, c.Request.URL.Path)
c.Next()
}
}logger.go
const (
XRequestIDKey = "X-Request-ID"
)
var (
infoLogger *log.Logger
errorLogger *log.Logger
context *gin.Context
)
func init() {
infoLogger = log.New(os.Stdout, "", 0)
errorLogger = log.New(os.Stderr, "", 0)
}
// InitializeContext initialize golbal gin context to logger
func InitializeContext(c *gin.Context) {
context = c
}
//Check if the request id present in the context.
func getRequestID() interface{} {
if context != nil {
if context.Request != nil {
requestID := context.Request.Header.Get(XRequestIDKey)
if requestID != "" {
return requestID
}
}
}
return ""
}
func Info(entry Input) {
infoLogger.Println(getJSON(getRequestID(), msg))
}这在多线程环境中不起作用。如何在多线程环境中修复此解决方案?
发布于 2022-04-12 04:16:24
不能将上下文保存在全局变量中。根据定义,上下文是该执行的本地内容,并且在任何给定的时刻,都会有多个上下文。
您可以将生成的ID存储在gin上下文中:
func (m *Middleware) RequestID() gin.HandlerFunc {
return func(c *gin.Context) {
xRequestID := uuid.NewV4().String()
c.Set("requestId",xRequestID)
fmt.Printf("[GIN-debug] %s [%s] - \"%s %s\"\n", time.Now().Format(time.RFC3339), xRequestID, c.Request.Method, c.Request.URL.Path)
c.Next()
}
}然后,您可以使用存储在上下文中的ID和自定义日志格式化程序:
router.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
return fmt.Sprintf("%s ...",
param.Keys["requestId"],
...
)
}))或者,如果您需要使用不同的日志库,可以编写一个包装器:
func LogInfo(ctx *gin.Context,msg string) {
id:=ctx.Get("requestId")
// Log msg with ID
}许多日志库提供了一些方法来获取已经设置了一些参数的记录器。例如,如果使用zerolog:
logger:=log.Info().With().Str("requestId",ctx.Get("requestId")).Logger()
logger.Info().Msg("This log msg will contain the request id")https://stackoverflow.com/questions/71836926
复制相似问题