Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Logging Go在Gorilla处理程序中记录线程id_Logging_Go_Gorilla - Fatal编程技术网

Logging Go在Gorilla处理程序中记录线程id

Logging Go在Gorilla处理程序中记录线程id,logging,go,gorilla,Logging,Go,Gorilla,我们如何获取线程id或处理程序在登录到Gorilla处理程序中处理的http请求的任何其他唯一id? 在Java中,当Tomcat或其他容器处理多个http请求时,线程id有助于跟踪各个http请求处理的所有日志消息。 在Go中的等价物是什么?给定一个使用Gorilla库开发的RESTAPI,如何在处理程序中跟踪特定http请求的所有日志语句?默认情况下,该库不提供这样做的方法:那里的日志函数以Apache格式记录,而Apache格式不提供这种方法 还要记住,“线程ID”在这里没有意义-您需

我们如何获取
线程id
或处理程序在登录到
Gorilla处理程序中处理的http请求的任何其他唯一id?

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

默认情况下,该库不提供这样做的方法:那里的日志函数以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 ""
}
请记住,上面的代码没有经过测试。在操场上写下了我的头顶,所以如果有虫子请告诉我

改进,你可以考虑超越这个基本的例子:

  • 在ID前面加上主机名-如果要聚合来自多个进程/机器的日志,这将非常有用)
  • 提供时间戳或递增整数作为最终ID的一部分,以帮助随时间跟踪请求
  • 对其进行基准测试
请注意,在极高的负载下(例如,数以万计的req/s-每天数千万次点击),这可能无法实现,但不太可能成为99%以上用户的瓶颈

PS:我可能会考虑在gorilla/handlers库中提供一个
handlers.RequestID
实现——如果你想看到它,就在回购协议上提出一个问题,我会看看我是否有时间实现更完整的上述内容。

基于$20http$20thread/golang nuts/vDNEH3_vMXQ/uyqGEwdchzgJ,
ThreadLocal
概念不适用于Go

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

因此,在需要记录的每个地方,我们都需要传递请求实例来检索ID。这很痛苦。从处理程序中,我们可以调用许多函数,这些函数可能是实用程序函数/数据库方法等。所有这些方法都可以修改以接受请求实例。不要再使用gorilla/context,它早在context之前就诞生了。context存在,不能很好地处理http.Request.WithContext对请求的浅层复制(添加到net/http Go 1.7之后)执行。