英文:
Reuse log client in interceptor for Golang grpc server method
问题
我正在使用Go构建一个gRPC服务器。目前,该服务器提供了三种方法:
- SubmitJob
- CancelJob
- GetJobStatus
我正在使用Datadog记录一些指标,例如请求计数、持续时间等。SubmitJob方法的代码如下:
func (s *myServer) submitJob(ctx context.Context, request *submitJobRequest) (*submitJobResponse, error) {
s.dd_client.LogRequestCount("SubmitJob")
start_time := time.Now()
defer s.dd_client.LogRequestDuration("SubmitJob", time.Since(start_time))
resp := someFunc()
return resp, nil
}
这些日志记录代码在这三个不同的服务器方法中几乎相同。因此,我想知道如何避免这种重复。
我注意到golang的gRPC有拦截器的概念。基本上,我可以定义一个拦截器函数,并在服务器方法调用的前后进行预处理和后处理。
根据文档,我编写了一个拦截器,如下所示:
func unaryInterceptor(ctx context.Context,
req interface{},
info *grpc.UnaryServerInfo,
handler grpc.UnaryHandler,
) (interface{}, error) {
dd_client := NewDatadogClient()
defer dd_client.Close()
dd_client.LogRequestCount(info.FullMethod)
start_time := time.Now()
resp, err := handler(ctx, req)
dd_client.LogRequestDuration(info.FullMethod, time.Since(start_time))
return resp, err
}
问题是,每次调用拦截器时,它都会创建和销毁一个新的Datadog客户端。我觉得这是不必要的。但由于unaryInterceptor只是一个方法而不是一个类,我看不到一种方法可以创建Datadog客户端一次并在以后重用它。有没有办法实现我所需的功能?
英文:
I am building a grpc server in Go. Right now the server provides three methods:
- SubmitJob
- CancelJob
- GetJobStatus
I am using Datadog to log few metrics e.g. request count, duration etc. The SubmitJob method looks like:
func (s *myServer) submitJob(ctx context.Context, request *submitJobRequest) (*submitJobResponse, error) {
s.dd_client.LogRequestCount("SubmitJob")
start_time := time.Now()
defer s.dd_client.LogRequestDuration("SubmitJob", time.Since(start_time))
resp := someFunc()
return resp, nil
}
The logging code is pretty much the same among those three different server methods. Thus, I wonder how to avoid such duplication.
I noticed that golang grpc has the concept ofinterceptor. Basically I can define a interceptor function, and use that to do pre/post processing of server method call.
Follow the documentation, I wrote an interceptor like:
func unaryInterceptor(ctx context.Context,
req interface{},
info *grpc.UnaryServerInfo,
handler grpc.UnaryHandler,
) (interface{}, error) {
dd_client := NewDatadogClient()
defer dd_client.Close()
dd_client.LogRequestCount(info.FullMethod)
start_time := time.Now()
resp, err := handler(ctx, req)
dd_client.LogRequestDuration(info.FullMethod, time.Since(start_time))
return resp, err
}
The problem is that, everytime when the interceptor is called, it will create and destory a new Datadog client. I feel this is unnecessary. But since unaryInterceptor is just a method instead of a class, I do not see a way to create the Datadog client once and reuse it later? Is there a way to fulfill what I need?
答案1
得分: 1
是的,将其从现场创建移动到另一个文件/包中,我们称之为DataDog.go。
在其中,您需要将其声明为单例,以便在所有用法中只有一个指针,类似于以下方式...
(我使用类型“DataDogType”来引用函数“NewDatadogClient”返回的数据类型,请指定包和版本以提供更精确的示例代码)
// 你的包代码...
var dataDog DataDogType
// 通过包装器访问它,包装器将在第一次初始化变量时进行初始化,
// 剩下的时间将重复使用
func GetDataDog() *DataDogType {
if dataDog == nil {
dataDog = NewDatadogClient()
}
return dataDog
}
根据您的用例,如果您将其作为指针返回并关闭它,您将关闭所有用法,因此返回指针本身并省略关闭部分,或者返回值,使其成为原始副本。
顺便问一下,您能分享一下您使用的DataDog版本和具体的包吗?
英文:
Yes, instead of creating it on spot, move that to a different file / package, lets call it DataDog.go
On it you need to declar it as a singleton so it's only 1 pointer across all usages something like....
(im using the type 'DataDogType' to refer the data type return by the function 'NewDatadogClient', pls specify the package and version to give a more precise sample code)
//your package code....
var dataDog DataDogType
//access it through a wrapper, the wrapper will init the var the first time,
//the remaining times it will be reused
func GetDataDog()(*DataDogType) {
if dataDog == nil {
dataDog = NewDatadogClient()
}
return dataDog
}
Now depending of your use case, if you return it as a pointer and close it you will close it for all usages, so return the pointer it self and omit the part of closing it, or return the value so its a copy of the original
btw could you share the dataDog version and specific package that you are using?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论