logging - 在 Gorilla Handler 中记录线程 ID

标签 logging go gorilla

我们如何在 Gorilla Handlers 的日志记录中获取线程 ID 或由处理程序处理的 http 请求的任何其他唯一 ID?
在 Java 中,当 Tomcat 或其他容器处理多个 http 请求时,线程 id 有助于跟踪各个 http 请求处理的所有日志消息。
Go 中的等价物是什么?给定使用 Gorilla 库开发的 Rest API,如何跟踪处理程序处理中特定 http 请求的所有日志语句?

最佳答案

gorilla/handlers默认情况下,库不提供执行此操作的方法:那里的日志记录函数以 Apache 格式记录,而 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 ""
}

请记住,上面的代码未经测试。这是我在 Playground 中凭空写出来的,所以如果有错误请告诉我。

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

  • 在 ID 中添加主机名前缀 - 如果您要聚合来自多个进程/计算机的日志,这会很有帮助)
  • 提供时间戳或递​​增整数作为最终 ID 的一部分,以帮助跟踪一段时间内的请求
  • 对其进行基准测试。

请注意,在极高的负载下(例如数万个请求/秒 - 每天数千万次点击),这可能性能不佳,但不太可能成为超过 99% 的用户的瓶颈。

PS:我可能会考虑在某个时候在 gorilla/handlers 库中提供 handlers.RequestID 实现 - 如果您想看到它,请在存储库上提出问题,我会'我会看看我是否能找到时间对上述内容进行更完整的实现。

关于logging - 在 Gorilla Handler 中记录线程 ID,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33947545/

相关文章:

session - golang go-endpoints Session 使用 gorilla-toolkit

multithreading - 实现线程安全日志记录

logging - 运行 cargo test 时如何设置日志级别?

go - 默认服务器 mux 如何匹配 url 模式

谷歌存储签名 url 公开阅读

Gorilla Mux 不处理我的路径

python - 我刚刚记录的最差级别的日志是什么?

c# - C# 库的可选日志记录依赖项?

Go SSH key 不能与 crypto/ssh 一起使用,但可以手动使用

http - 使用 rs.cors 时返回 http 状态码