为了账号安全,请及时绑定邮箱和手机立即绑定

在 Gorilla Handler 中记录线程 ID

在 Gorilla Handler 中记录线程 ID

Go
浮云间 2021-11-22 19:41:58
我们如何thread id在内部登录时获取处理程序正在处理的 http 请求的唯一 ID 或任何其他唯一 ID Gorilla Handlers?在 Java 中,当 Tomcat 或其他容器处理多个 http 请求时,线程 ID 有助于跟踪各个 http 请求处理的所有日志消息。中的等价物是Go什么?鉴于使用Gorilla库开发的 Rest API ,如何在处理程序处理中跟踪特定 http 请求的所有日志语句?
查看完整描述

2 回答

?
拉丁的传说

TA贡献1789条经验 获得超8个赞

默认情况下,gorilla/handlers库不提供执行此操作的方法:那里的日志记录功能以 Apache 格式登录,而 Apache 格式不提供此功能。


也请记住,“线程ID”没有意义在这里-你想有一个请求,即与相关的ID *http.Request。


您可以编写自己的 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 ""

}

请记住,上面的代码没有经过测试。在操场上写下了我的头顶,所以如果有错误,请告诉我。


除了这个基本示例之外,您还可以考虑改进:

  • 用主机名前缀 ID - 如果您从多个进程/机器聚合日志很有帮助)

  • 提供时间戳或递增整数作为最终 ID 的一部分,以帮助跟踪一段时间内的请求

  • 对其进行基准测试。

请注意,在极高的负载下(例如,数以万计的请求/秒 - 每天数以百万计的点击),这可能不是高性能的,但不太可能成为 > 99% 用户的瓶颈。

PS:我可能会考虑在某个时候handlers.RequestID在 gorilla/handlers 库中提供一个实现——如果你想看到它,在 repo 上提出一个问题,我会看看我是否能找到时间来实现一个更完整的实现在上面。


查看完整回答
反对 回复 2021-11-22
?
蛊毒传说

TA贡献1895条经验 获得超3个赞

基于https://groups.google.com/forum/#!searchin/golang-nuts/Logging $20http$20thread/golang-nuts/vDNEH3_vMXQ/uyqGEwdchzgJ,ThreadLocalGo 无法实现概念。

每个需要记录的地方,都需要传入 httpRequest实例,以便可以检索与请求关联的上下文,并且可以从该上下文中获取请求的唯一 ID。但是将 Request 实例传递给所有层/方法是不切实际的。

查看完整回答
反对 回复 2021-11-22
  • 2 回答
  • 0 关注
  • 188 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信