【问题标题】:How to pass a logger as an argument to a chain of middleware functions?如何将记录器作为参数传递给中间件函数链?
【发布时间】:2022-01-09 10:20:22
【问题描述】:

我是 Go 新手,请多多包涵。

我正在尝试使用 Uber 的 Zap 日志记录包。我翻阅了文档并查看了许多示例,但我正在努力寻找如何最好地使用它。他们的常见问题解答部分说要避免将 Zap 用作全局记录器,所以我试图将在 server.go(紧接在下面)中初始化的内容传递给其他函数。

// Initialize logger
logger, err := zap.NewProduction()
if err != nil {
    log.Fatalf("Failed to initialize zap logger: %v", err)
}
defer logger.Sync()
sugar := logger.Sugar()
sugar.Info("Server is starting...")

router := http.NewServeMux()

server := &http.Server{
    Addr:         addr,
    Handler:      middleware.Middleware{middleware.RequestIdentifier, middleware.RequestLogger}.Apply(router),
    // ...other fields
}

Middleware 在另一个文件中定义为

type Middleware []func(http.Handler) http.Handler

// Apply() builds the middleware array into a handler chain
func (midware Middleware) Apply(handler http.Handler) http.Handler {
    if len(midware) == 0 {
        return handler
    }
    return midware[:len(midware)-1].Apply(midware[len(midware)-1](handler))
}

然后在另一个文件中 (request_identifier.go)。

func RequestIdentifier(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        //
        // ...stuff, and use Zap here
        //
        next.ServeHTTP(w, r)
    })
}

对于其他中间件功能也是如此。

我尝试包装 RequestIdentifier 并尝试使用中间件的可接受函数签名,但我似乎无法弄清楚如何在不让 IDE 对我大喊大叫的情况下通过 sugar

我想要的是这样的:

Handler: middleware.Middleware{middleware.RequestIdentifier(sugar), middleware.RequestLogger(sugar)}.Apply(router)

然后在我的中间件函数中,以某种方式访问​​可用的记录器,如下所示:

func RequestIdentifier(next http.Handler, s *zap.SugaredLogger) http.Handler { ... }

【问题讨论】:

    标签: go logging gorilla


    【解决方案1】:

    你需要多加一层闭包:

    func RequestIdentifier(s *zap.SugaredLogger) func(http.Handler) http.Handler {
        return func(next http.Handler) http.Handler {
            return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
                //
                // ...stuff, and use Zap here
                //
                next.ServeHTTP(w, r)
            })
        }
    }
    
    
    Handler: middleware.Middleware{middleware.RequestIdentifier(sugar), middleware.RequestLogger(sugar)}.Apply(router),
    

    【讨论】:

    • 你在第一行有两个函数...返回类型是func(http.Handler) http.Handler吗?
    • 我试了一下并将sugar 传递给RequestIdentifier 作为参数:middleware.RequestIdentifier(sugar),但后来我得到了:cannot use sugar (variable of type *zap.SugaredLogger) as *invalid type value in argument to middleware.RequestIdentifiercompilerIncompatibleAssign
    • 你必须描述中间件的整个签名,从参数到闭包的执行结果。 func RequestIdentifier(s *zap.SugaredLogger) func(http.Handler) http.Handler {func(http.Handler) http.Handler - 是结果类型。添加了如何使用带有双闭包的中间件的示例
    猜你喜欢
    • 2015-03-17
    • 2017-06-09
    • 2013-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-04
    • 2021-09-09
    • 2020-12-18
    相关资源
    最近更新 更多