New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
contrib/google.golang.org/grpc: add WithErrorCheck
option
#2035
base: main
Are you sure you want to change the base?
Conversation
c39258b
to
057eaab
Compare
NonErrorFunc
option for interceptor
NonErrorFunc
option for interceptorNonErrorFunc
option
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @BIwashi, thank you for the contribution! I think it wouldn't hurt to add some unit tests covering the NonErrorFunc
option.
@dianashevchenko |
// NonErrorFunc sets a custom function to determine whether an error should not be considered as an error for tracing purposes. | ||
// This function is evaluated when an error occurs, and if it returns true, the error will not be recorded in the trace. | ||
// f: A function taking the gRPC method and error as arguments, returning a boolean to indicate if the error should be ignored. | ||
func NonErrorFunc(f func(method string, err error) bool) Option { | ||
return func(cfg *config) { | ||
cfg.nonErrorFunc = f | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest aligning naming with other Options in this package, for example 'WithErrorCheck' naming is widely used across other packages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have renamed the function name and config field names considering this comment as well. Thanks!
100083f
var ( | ||
rig *rig | ||
err error | ||
) | ||
if tt.nonErrorFunc == nil { | ||
rig, err = newRig(true) | ||
} else { | ||
rig, err = newRig(true, NonErrorFunc(tt.nonErrorFunc)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var ( | |
rig *rig | |
err error | |
) | |
if tt.nonErrorFunc == nil { | |
rig, err = newRig(true) | |
} else { | |
rig, err = newRig(true, NonErrorFunc(tt.nonErrorFunc)) | |
} | |
var opts []Option | |
if tt.nonErrorFunc != nil { | |
opts = append(opts, NonErrorFunc(tt.nonErrorFunc)) | |
} | |
rig, err := newRig(true, opts...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you so much!
I fixed it.
6a3227e
var ( | ||
rig *rig | ||
err error | ||
) | ||
if tt.nonErrorFunc == nil { | ||
rig, err = newRig(true) | ||
} else { | ||
rig, err = newRig(true, NonErrorFunc(tt.nonErrorFunc)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var ( | |
rig *rig | |
err error | |
) | |
if tt.nonErrorFunc == nil { | |
rig, err = newRig(true) | |
} else { | |
rig, err = newRig(true, NonErrorFunc(tt.nonErrorFunc)) | |
} | |
var opts []Option | |
if tt.nonErrorFunc != nil { | |
opts = append(opts, NonErrorFunc(tt.nonErrorFunc)) | |
} | |
rig, err := newRig(true, opts...) |
mt := mocktracer.Start() | ||
defer mt.Stop() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move the start of the mocktracer this into the test case run
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this the correct revision of your point?
4fca224
val := ctx.Value(fullMethodNameKey{}) | ||
if val == nil { | ||
return | ||
} | ||
fullMethod, ok := val.(string) | ||
if !ok { | ||
return | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Returning early here will result in finishWithError(span, v.Error, fullMethod, h.cfg)
not being called unless fullMethodNameKey
is set. Is this the expected behaviour?
val := ctx.Value(fullMethodNameKey{}) | |
if val == nil { | |
return | |
} | |
fullMethod, ok := val.(string) | |
if !ok { | |
return | |
} | |
method, _ := ctx.Value(fullMethodNameKey{}).(string) | |
if v, ok := rs.(*stats.End); ok { | |
finishWithError(span, v.Error, method, h.cfg) | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are correct, finishWithError needs to be called. I made a mistake. Thanks.
I fixed it.
val := ctx.Value(fullMethodNameKey{}) | ||
if val == nil { | ||
return | ||
} | ||
fullMethod, ok := val.(string) | ||
if !ok { | ||
return | ||
} | ||
finishWithError(span, rs.Error, fullMethod, h.cfg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, don't we want to run finishWithError
regardless?
val := ctx.Value(fullMethodNameKey{}) | |
if val == nil { | |
return | |
} | |
fullMethod, ok := val.(string) | |
if !ok { | |
return | |
} | |
finishWithError(span, rs.Error, fullMethod, h.cfg) | |
method, _ := ctx.Value(fullMethodNameKey{}).(string) | |
finishWithError(span, rs.Error, method, h.cfg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fixed it, too.
5b83467
noError := true | ||
for _, s := range spans { | ||
if s.Tag(ext.Error) != nil { | ||
noError = false | ||
break | ||
} | ||
} | ||
|
||
if tt.withError { | ||
assert.False(t, noError) | ||
} else { | ||
assert.True(t, noError) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
noError := true | |
for _, s := range spans { | |
if s.Tag(ext.Error) != nil { | |
noError = false | |
break | |
} | |
} | |
if tt.withError { | |
assert.False(t, noError) | |
} else { | |
assert.True(t, noError) | |
} | |
for _, s := range spans { | |
if s.Tag(ext.Error) != nil && !tt.withError { | |
assert.FailNow(t, "expected no error tag on the span") | |
} | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had not thought of this idea. Thank you so much!
I fixed it.
cff830c
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment on proposal here: #2043 (comment)
I apologize for the delay in making the corrections. It would be much appreciated if you could take the time to review the revisions again. Thanks. |
NonErrorFunc
optionWithErrorCheck
option
WithErrorCheck
optionWithErrorCheck
option
What does this PR do?
This PR adds a new option called
WithErrorCheck
which allows users to set a custom function to determine whether an error should not be considered as an error for tracing purposes before sending it to DataDog.Motivation
There are cases where an application produces errors, but they should not be sent to DataDog as errors. While the
WithErrorCheck
option allows for not treating specific gRPC status codes as errors, there are use cases where a more granular decision is needed based on the specific error, rather than just the status code.For example, a user might want to consider a NotFound error as non-error for a specific RPC.
example
Describe how to test/QA your changes
Unit tests are included.
Reviewer's Checklist