英文:
grpc connection time metric in the middleware
问题
这是我之前的问题https://stackoverflow.com/questions/70240557/grpc-middlewareinterceptors-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("未知的方法名:%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纳秒。
英文:
This is my previous question https://stackoverflow.com/questions/70240557/grpc-middlewareinterceptors-for-metric
I want to use middleware. That's what I have now.
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
})
}
Creating grpc server
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...)
My code is not working properly. The metrics are too small ~30,000 nanoseconds.
答案1
得分: 1
假设我正确理解了你的问题,我认为问题出在以下代码中:
defer mtr.RequestTime.With(metrics.MakeLabels(label)).Observe(time.Since(beginTime).Seconds())
你似乎期望这段代码在函数退出时运行,并计算此时经过的时间。然而根据语言规范:
>每次执行“defer”语句时,函数值和调用的参数都会像平常一样进行求值并保存,但实际的函数不会被调用。
因此,参数在defer语句执行时进行求值,而不是在包围函数退出时(延迟函数运行时)进行求值。可以通过一个简单的程序来证明这一点:
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
有几种可能的解决方案;最简单的可能是使用一个闭包,例如:
defer func() { fmt.Println("defer", time.Since(beginTime).Seconds()) }()
或者在你的情况下:
defer func() { mtr.RequestTime.With(metrics.MakeLabels(label)).Observe(time.Since(beginTime).Seconds())}()
英文:
Assuming I'm understanding your issue correctly I believe the problem is with:
defer mtr.RequestTime.With(metrics.MakeLabels(label)).Observe(time.Since(beginTime).Seconds())
It appears that you expect this to be run at the time the function exits and calculate the time elapsed as at that time. However as per the 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.
So the parameters are evaluated when the defer statement executes NOT when the surrounding function exits (and the deferred function runs). This can be demonstrated with a 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())
This will output something like:
non-defer 2
defer 0
There are a few possible solutions; the simplest is probably to use a closure e.g.
defer func() { fmt.Println("defer", time.Since(beginTime).Seconds()) }()
or in your case:
defer func() { mtr.RequestTime.With(metrics.MakeLabels(label)).Observe(time.Since(beginTime).Seconds())}()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论