我们如何在thread id
内登录时获取处理程序处理的http请求的Gorilla Handlers
或任何其他唯一ID?
在Java中,当Tomcat或其他容器处理多个http请求时,线程ID有助于跟踪各个http请求处理的所有日志消息。
Go
中的等价物是什么?给定使用Gorilla
库开发的Rest API,如何在处理程序处理中跟踪特定http请求的所有日志语句?
答案 0 :(得分:2)
gorilla/handlers库默认情况下没有提供这样做的方法:日志记录功能以Apache格式登录,但不提供此功能。
还要记住一个"线程ID"这里没有意义 - 你想要一个与*http.Request
相关联的请求 ID。
您可以编写自己的RequestID中间件来创建ID并在请求上下文中存储其他中间件/处理程序以根据需要进行检索:
package main
import (
"crypto/rand"
"encoding/base64"
"net/http"
"github.com/gorilla/context"
)
const ReqID string = "gorilla.RequestID"
// RequestID wraps handlers and makes a unique (32-byte) request ID available in
// the request context.
// Example:
// http.Handle("/", RequestID(LoggingHandler(YourHandler)))
//
// func LoggingHandler(h http.Handler) http.Handler {
// fn := func(w http.ResponseWriter, r *http.Request) {
// h.ServeHTTP(w, r)
//
// id := GetRequestID(r)
// log.Printf("%s | %s", id, r.RemoteAddr)
// }
//
// return http.HandlerFunc(fn)
// }
func RequestID(h http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
b := make([]byte, 8)
_, err = rand.Read(&b)
if err != nil {
http.Error(w, http.StatusText(500), 500)
return
}
base64ID := base64.URLEncoding.EncodeToString(b)
context.Set(r, ReqID, base64ID)
h.ServeHTTP(w, r)
// Clear the context at the end of the request lifetime
context.Clear(r)
}
return http.HandlerFunc(fn)
}
func GetRequestID(r *http.Request) string {
if v, ok := context.GetOK(r, ReqID); ok {
if id, ok := v.(string); ok {
return id
}
}
return ""
}
请注意,上述代码未经过测试。在游乐场写下我的头顶,所以如果有错误,请告诉我。
除了这个基本示例之外,您可以考虑改进:
请注意,在极高负载下(例如每天数万次req / s - 数千万次点击),这可能无法实现,但不太可能成为>的瓶颈。 99%的用户。
PS:我可能会在某些时候在大猩猩/处理程序库中提供handlers.RequestID
实现 - 如果您想看到它,请在回购中提出问题并且我会看看我是否能抽出时间对上述内容进行更全面的了解。
答案 1 :(得分:0)
基于https://groups.google.com/forum/#!searchin/golang-nuts/Logging $ 20http $ 20thread / golang-nuts / vDNEH3_vMXQ / uyqGEwdchzgJ,Go无法实现ThreadLocal
概念。
每当你需要记录的地方,它需要传入http Request
实例,以便可以检索与请求相关联的上下文,并且可以从该上下文中获取请求的唯一ID 。
但是将Request实例传递给所有层/方法是不切实际的。