Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 617
Hari Prasanth Avatar asked Dec 09 '25 08:12

Hari Prasanth


1 Answers

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) {
  ...
}
```
like image 86
boyvinall Avatar answered Dec 12 '25 00:12

boyvinall



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!