拉丁的传说
默认情况下,gorilla/handlers库不提供执行此操作的方法:那里的日志记录功能以 Apache 格式登录,而 Apache 格式不提供此功能。也请记住,“线程ID”没有意义在这里-你想有一个请求,即与相关的ID *http.Request。您可以编写自己的 RequestID 中间件,该中间件创建一个 ID 并将其存储在请求上下文中,以便其他中间件/处理程序根据需要检索:package mainimport ( "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 ""}请记住,上面的代码没有经过测试。在操场上写下了我的头顶,所以如果有错误,请告诉我。除了这个基本示例之外,您还可以考虑改进:用主机名前缀 ID - 如果您从多个进程/机器聚合日志很有帮助)提供时间戳或递增整数作为最终 ID 的一部分,以帮助跟踪一段时间内的请求对其进行基准测试。请注意,在极高的负载下(例如,数以万计的请求/秒 - 每天数以百万计的点击),这可能不是高性能的,但不太可能成为 > 99% 用户的瓶颈。PS:我可能会考虑在某个时候handlers.RequestID在 gorilla/handlers 库中提供一个实现——如果你想看到它,在 repo 上提出一个问题,我会看看我是否能找到时间来实现一个更完整的实现在上面。