繁体   English   中英

如何在 go 微服务中为每个日志添加跟踪 ID

[英]How to add trace id to each logs in go micro service

我想将跟踪 id 添加到对微服务的每个请求的日志记录中。我希望这与 springboot 应用程序类似,我们可以在 MDC 中设置跟踪 id 并获取它并在记录时使用它。

我做了一些研究,发现 go lang 中的 MDC 等效项是上下文。 所以,我已经在我的上下文中设置了跟踪 ID。 现在的问题是我必须使用跟踪 id 登录的地方,我需要将上下文传递给 function,这是非常丑陋的方式。 我正在为这个问题寻找更好的解决方案。

func HandlerFunction(f gin.HandlerFunc) gin.HandlerFunc{
    return func(cxt *gin.Context) {
        reqraceId := cxt.Request.Header.Get("trace-id")
        requid , _ := uuid.NewRandom()

        if reqTraceId == "" {
            c.Request.Header.Set("trace-id", requid.String())
        }

        f(c)
    }
}

可能值得阅读context.Context尤其是这篇文章,其中有一节说:

在 Google,我们要求 Go 程序员将 Context 参数作为第一个参数传递给传入和传出请求之间的调用路径上的每个 function。

TL;DR - 传递上下文很好,但最好的方法是什么?

有两种主要模式

  1. 询问上下文给你一个记录器
  2. 为记录器提供上下文

上下文可用于存储值:

context.WithValue(ctx, someKey, someValue)

这意味着我们可以这样做:

somepackage.Log(ctx).Info("hello world")
// or
sompackage.Info(ctx, "hello world")

这两个示例 API 的实现可以与上下文交互以检索所需的值,而无需担心任何日志调用站点的 MDC 中可能存在的额外信息。

这个问题也可以使用依赖注入容器来解决。

我们可以实现“请求范围”注入,因此,对于每个请求,我们将重新创建所有使用请求范围依赖的依赖树(记录器、错误报告器、通过上下文传播向另一个服务发送请求的客户端)。

但据我了解,在 go 中使用依赖注入容器不是最佳实践,也不是“惯用”方式。

此外,这种方法可能有一些性能和 memory 问题,因为我们将为每个请求重新创建对象。

从我的角度来看,我发现使用默认日志 package 我们可以将前缀设置为log.SetPrefix(traceId) ,这样做,日志将打印跟踪 id 作为实际和子函数/结构中的前缀。

import (
    "log"
    "github.com/google/uuid"
)

func (hdl *HTTPHandler) example() {
    var traceId string = uuid.NewString()
    log.SetPrefix(traceId + " - ")
    log.SetFlags(log.LstdFlags)
    // ...
    // ...
    log.Println("......")
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM