Reputation: 15785
I am writing a method to do metrics that can wrap any method. Something like:
func DoAndMonitor(f func() error, simpleKey string) {
metrics.IncrCounter("activity."+simpleKey+".cnt", 1)
if err := f(); err != nil {
metrics.IncrCounter("activity."+simpleKey+".fail", 1)
} else {
metrics.IncrCounter("activity."+simpleKey+".fail", 1)
}
}
This works for some cases. But it is not easy to use, say I have any functions below,
myMethod() (val1 string , val2 string , err error)
myMethod()2 (val string , err error)
myMethod()3 ( err error)
myMethod()4 (val int64, err error)
When I use myMethod()
, I may write something like:
ret1, ret2, err := myMethod()
if err :=nil {
//log
return nil, err;
} else {
//do something...
return something,nil
}
But when I use DoAndMonitor
, I hope the DoAndMonitor
function can return the same type as myMethod
like :
ret1, ret2, err := DoAndMonitor(func(){
return myMethod()
},"mykey");// this is what i hope, but i can't do this now
if err :=nil {
//log
return nil, err;
} else {
//do something...
return something,nil
}
How can I achieve this?
Upvotes: 0
Views: 1077
Reputation: 129
The closest you can get to this is by using type parameters and making a few variations of the same function.
func DoAndMonitor(f func() error, simpleKey string) { ... }
func DoAndMonitor1[T any](f func() (T, error), simpleKey string) T {
x, err := f()
if err != nil {
metrics.IncrCounter("activity."+simpleKey+".fail", 1)
} else {
metrics.IncrCounter("activity."+simpleKey+".success", 1)
}
return x
}
// and so on...
You could then invoke your function like so:
x := DoAndMonitor1[int](func() (int, error) { return 42, nil }, "foo")
A quick playground link to demonstrate this, but with panics instead of your nice metrics. :) https://go.dev/play/p/SMAhUCoIYcj
Upvotes: 1