在Golang中将来自标头的traceId添加到发送到Loki服务器的日志中。

huangapple go评论78阅读模式
英文:

Adding traceId from header to logs sent to Loki server in Golang

问题

我有一个名为LokiLogs的函数,它将日志发送到Loki服务器。我想在每个API调用中将一个名为traceId的标识符作为头部X-Trace-ID传递给日志。以下是我目前的代码:

type StdoutLogger struct {
  io.Writer
}

func (l *StdoutLogger) Print(v ...interface{}) {
  vv := LogFormatter(v...)  //这个函数只是美化日志字符串,不会影响功能
  log.Println(vv)

  if len(vv.Message) > 0 {
    slice := vv.Message[0]
    LokiLogs(slice.Sql + " " + slice.SqlMessage)
  }
}

func main() {
   router := gin.Default()
   .
   .
   db.LogMode(true)
   db.SetLogger(&StdoutLogger{os.Stdout})
}

func LokiLogs(msg string) {
  v := strconv.FormatInt(time.Now().UnixNano(), 10)

  msg = msg + " " + "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)
}

我已经使用一个日志中间件为每个API调用设置了一个名为traceId的头部,类似于c.Request.Header.Set("X-Trace-ID", traceID)。如何将这个traceId值传递给LokiLogs函数,以便它可以连接到msg字符串中,类似于traceId=Some UUID

英文:

I have a function called LokiLogs which sends logs to the Loki server. I want to add a traceId to the logs that gets passed as a header X-Trace-ID in every API call. Here's the code I have so far:

type StdoutLogger struct {
  io.Writer
}

func (l *StdoutLogger) Print(v ...interface{}) {
  vv := LogFormatter(v...)  //This function is just beautify the log string, it will not affect the functionality
  log.Println(vv)

  if len(vv.Message) > 0 {
    slice := vv.Message[0]
    LokiLogs(slice.Sql + " " + slice.SqlMessage)
  }
}

func main() {
   router := gin.Default()
   .
   .
   db.LogMode(true)
   db.SetLogger(&StdoutLogger{os.Stdout})
}

func LokiLogs(msg string) {
  v := strconv.FormatInt(time.Now().UnixNano(), 10)

  msg = msg + " " + "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)
}

I have set a traceId header for every API call like this c.Request.Header.Set("X-Trace-ID", traceID) using a log middleware. How can I pass this traceId value to the LokiLogs function so that it can be concatenated to the msg string like this traceId=Some UUID?

答案1

得分: 1

看起来你的db.SetLogger可能来自jinzhu/gorm。那里的Logger接口实际上不允许你通过除了日志记录器实例之外的方式传递额外的细节,所以我认为你需要像这样的东西:

type StdoutLogger struct {
  io.Writer
  TraceID string
}

然后你的gin HandlerFunc需要使用gin.Context中的GetHeader从头部提取信息,并使用该信息构建一个特定于该请求的日志记录器实例,类似于这样:

func (s *mystruct) MyHandler(c *gin.Context) {
  thisTraceID := c.GetHeader("X-Trace-ID")
  ...
  db.SetLogger(&StdoutLogger{Writer: os.Stdout, TraceID: thisTraceID})
  // db.Find/Exec/Save/...
}

然后是

func (l *StdoutLogger) Print(v ...interface{}) {
  vv := LogFormatter(v...)  //这个函数只是美化日志字符串,不会影响功能
  log.Println(vv)

  if len(vv.Message) > 0 {
    slice := vv.Message[0]
    LokiLogs(l.TraceID, slice.Sql + " " + slice.SqlMessage)
  }
}

func LokiLogs(traceID, msg string) {
  ...
}
英文:

It looks like your db.SetLogger is probably from jinzhu/gorm. The Logger interface there doesn't really allow you to pass additional details except through the logger instance, so I think you'd need something a bit like:

type StdoutLogger struct {
  io.Writer
  TraceID string
}

Then your gin HandlerFunc would need to extract the header from gin.Context using GetHeader, and use that to construct a logger instance specific to that request, something like:

func (s *mystruct) MyHandler(c *gin.Context) {
  thisTraceID := c.GetHeader("X-Trace-ID")
  ...
  db.SetLogger(&StdoutLogger{Writer: os.Stdout, TraceID: thisTraceID})
  // db.Find/Exec/Save/...
}

and then


func (l *StdoutLogger) Print(v ...interface{}) {
  vv := LogFormatter(v...)  //This function is just beautify the log string, it will not affect the functionality
  log.Println(vv)

  if len(vv.Message) > 0 {
    slice := vv.Message[0]
    LokiLogs(l.TraceID, slice.Sql + " " + slice.SqlMessage)
  }
}

func LokiLogs(traceID, msg string) {
  ...
}
```

</details>



huangapple
  • 本文由 发表于 2023年4月25日 13:39:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/76097905.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定