中间件中的 grpc 连接时间指标

grpc connection time metric in the middleware

这是我之前的问题grpc middleware(interceptors) for metric

我想使用中间件。这就是我现在所拥有的。

func RequestTimeStream(mtr *metrics.Metrics) grpc.StreamServerInterceptor {
    return grpc.StreamServerInterceptor(func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo,
        handler grpc.StreamHandler) error {
        beginTime := time.Now()
        label, err := getLabel(info.FullMethod)
        if err != nil {
            return errors.Errorf("Unknown method name: %s", info.FullMethod)
        }
        defer mtr.RequestTime.With(metrics.MakeLabels(label)).Observe(time.Since(beginTime).Seconds())
        if err := handler(srv, stream); err != nil {
            return err
        }
        return nil
    })
}

正在创建 grpc 服务器

    streamInterceptors := grpc_middleware.ChainStreamServer(
        middleware.RecoveryStream(logger, metrics.InternalGRPCPanicErrors),
        identifyMdw.IdentifyStream,
        middleware.AuthenticateStream(logger, metrics, authService),
        middleware.LimitStream(logger, metrics, limiters),
        middleware.RequestTimeStream(metrics),
    )

    opts := []grpc.ServerOption{grpc.UnaryInterceptor(unaryInterceptors), grpc.StreamInterceptor(streamInterceptors)}

    grpcServer, err := ggrpc.NewServer(cfg.ServerConfig, opts...)

我的代码无法正常工作。指标太小了~30,000 纳秒。

假设我正确理解了您的问题,我认为问题在于:

defer mtr.RequestTime.With(metrics.MakeLabels(label)).Observe(time.Since(beginTime).Seconds())

您似乎希望在函数退出时它是 运行 并计算当时经过的时间。但是根据 language spec:

Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked.

因此,当 defer 语句执行 NOT 时周围函数退出(以及延迟函数 运行s)时,将对参数求值。这可以用 simple program:

来证明
beginTime := time.Now()
defer fmt.Println("defer", time.Since(beginTime).Seconds())
time.Sleep(2 * time.Second)
fmt.Println("non-defer", time.Since(beginTime).Seconds())

这将输出如下内容:

non-defer 2
defer 0

有几个可能的解决方案;最简单的可能是使用 closure 例如

defer func() { fmt.Println("defer", time.Since(beginTime).Seconds()) }()

或者您的情况:

defer func() { mtr.RequestTime.With(metrics.MakeLabels(label)).Observe(time.Since(beginTime).Seconds())}()