Golang 请求 ID 日志记录

8

我正在使用golang编写Web应用程序,对这种语言还不太熟悉。 我正在尝试找出在golang webapp中记录请求ID的最佳方法。 我已经决定使用go的log库(https://golang.org/pkg/log/)或logrus (https://github.com/sirupsen/logrus)之一。但看起来它们都没有提供与requestId日志记录相关的内容。 因此,为了生成requestId并在整个API流程中使用它,我目前采用以下方法:

使用此处列出的任何一个uid生成库(https://golanglibs.com/search?q=id+generator&sort=top)来生成requestid。 并在处理请求的开头使用http.Handler包装器将其设置到上下文(https://golang.org/pkg/context/)中,并在所有需要进行日志记录的地方使用此上下文。

但要实现这一点,我需要将上下文对象传递给所有需要记录日志的函数。这听起来不太好,因为我涉及了所有函数的原型(即添加上下文参数)。 有没有更好的方法来做到这一点?例如ThreadLocal对象。可以从线程中的任何位置访问它,并使用它在需要时获取请求ID吗?


2
不,Go语言中没有线程本地的无聊操作,现在和以后都别想了。你必须通过上下文、显式参数或其他方式(例如自己的HTTP头)将请求ID传递到调用堆栈中。 - Volker
@Volker 谢谢。 - Shanmugam Sundaram
@ShanmugamSundaram 请查看 https://violetear.org/post/requestid/ 的实现方式,可能会给您一些关于如何创建/使用自定义日志记录器的想法 https://violetear.org/post/structured-logging/。 - nbari
2个回答

9
Go故意不支持线程本地存储的等价物,因为它们经常被滥用和错误使用。代码不应该依赖于执行它的goroutine。这也会限制函数启动进一步goroutine(或者设置特定于goroutine的上下文也会使事情复杂)。
相反,如果您的函数需要额外的信息(例如记录器),则必须显式地将额外的信息传递给它们。
当然,一个函数可能需要很多额外的信息,并且所需的东西可能会随着时间的推移而“增长”,因此最好为这样的额外信息创建一个包装器,并传递这个单个额外的包装器值。如果您需要另一个信息(例如已登录的用户ID或数据库连接或其他任何内容),则可以将其简单地添加到包装器中,而无需更改任何签名。
无论这个包装器是参数,还是你将你的函数作为包装器的方法(因此包装器将是接收器),完全取决于你,这只是一个实现细节。
参见相关问题: 为什么goroutine没有身份

Go语言中是否有类似于Java的ThreadLocal?


-1

我不喜欢有些人一直告诉我这个:

  • ThreadLocal不好/危险/被滥用 的。
  • Golang 不需要 goroutine 本地变量。
  • 你可以/应该使用 Context

我只想像以前几年在 C++/Java/... 中那样使用 Golang

因此,我创建了一个新的库,将 ThreadLocal 引入了 Golang

了解更多:https://github.com/go-eden/routine


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接