-
Notifications
You must be signed in to change notification settings - Fork 212
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
support logging "duck typed" Error objects #915
base: master
Are you sure you want to change the base?
support logging "duck typed" Error objects #915
Conversation
71196eb
to
55d07ae
Compare
src/utility.js
Outdated
if (arg instanceof Error || (typeof DOMException !== 'undefined' && arg instanceof DOMException)) { | ||
if (arg instanceof Error | ||
|| (typeof DOMException !== 'undefined' && arg instanceof DOMException) | ||
|| (typ === 'object' && arg.name && arg.message)) { |
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.
This expression is long enough it probably merits being extracted into a function, especially since it appears twice.
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 noticed there was an isError
function and I modified that instead.
55d07ae
to
087acf9
Compare
@@ -410,7 +412,7 @@ function createItem(args, logger, notifier, requestKeys, lambdaContext) { | |||
break; | |||
case 'object': | |||
case 'array': | |||
if (arg instanceof Error || (typeof DOMException !== 'undefined' && arg instanceof DOMException)) { |
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.
in my browser DOMException
is a subclass of Error
so the case 'domexception':
should catch it already, but isError
now catches it because a DOMException
also has a name
and a message
.
In TypeScript Error objects might be implemented instead of extended (i.e. HttpErrorResponse [1]). This causes the `instanceof` check in createItem to fail to recognize the argument as an error, and this change fixes that. [1]: https://github.com/angular/angular/blob/9a5ac47331faf0f6030bff75ad8ef8dab2f8d2d9/packages/common/http/src/response.ts#L319
087acf9
to
b3bc106
Compare
One thing to call out the class Test {
[Symbol.toStringTag] = 'Test'
}
// "OK", but not in the set of expected return values
({}).toString.call(new Test()).match(/\s([a-zA-Z]+)/)[1].toLowerCase() // 'test'
class Test2 {
[Symbol.toStringTag] = 'Test words'
}
// Regex doesn't capture everything
({}).toString.call(new Test2()).match(/\s([a-zA-Z]+)/)[1].toLowerCase() // 'test' This is mostly not going to be an issue, but it may break when the default is expected to be |
// Detect Error, Firefox Exception type and error like object | ||
return (isType(e, 'error') | ||
|| isType(e, 'exception') | ||
|| (typeof e === 'object' && e && e.name && e.message)); |
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 did not save the typeName
and move the comparisons inline because of this #915 (comment)
I'm concerned that the duck typing is so broad it will affect other users of Rollbar.js. While I understand I also have concerns about the Angular example. My interpretation is that I would be more in favor of a solution where the caller finds or creates a valid error object, or where the type that gets inferred is more certain. For example, this precise situation, passing a |
Well the problem is that Rollbar.js is too "magical" and there is not a good way to force this object to be interpreted as an error. I agree with the concerns about potentially breaking existing behavior and why I suggested there at least be a This issue was a result of the following documentation: https://docs.rollbar.com/docs/angular I am asking for this to be reported as an error While it is true that the example I give is also an HTTP response it declares it is also an
While it may contain an Error object, it may also contain the JSON/body returned by the server . Stumbling across an Angular example while finding that ^^^ I also see their example suggests logging the HttpErrorResponse as an error: https://github.com/angular/angular/blob/69385f7df4e678bbd8a04825b4ea2020f66190bc/aio/content/examples/http/src/app/http-error-handler.service.ts#L33-L34 I agree that might not be strong reasoning, but I think the stronger reasoning is that I'm calling |
The custom data can have any structure, One way forward would be a config option specifying types that should be treated as errors. Something like:
Then the utility function could compare against this list if present, instead of the duck type. This has a few advantages:
|
How do you imagine this working with strings? I would think it would need to be a callable and I'm not sure what it would be acting upon. Would it need to be applied to all arguments passed to // base classes
config.additionalErrorTypes = [HttpErrorResponse]
// callable
config.additionalErrorTypes = (e) => e instanceof HttpErrorResponse |
I had two reasons for suggesting using strings in the config.
It's hard to imagine taking a major change to how type matching is performed. That said, my comment wasn't meant to be prescriptive. |
Hi @waltjones sorry I couldn't follow up sooner, but while I understand your suggestion and why you suggested it. I'm not sure how it would work. The function typeName(x) {
return ({}).toString.call(x).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
}
typeName(new Error); // 'error'
class SubError extends Error {}
typeName(new SubError); // 'error'
class CustomError {}
typeName(new CustomError); // 'object'
class Thing {}
typeName(new Thing); // 'object' As a result I think either allowing a user to supply a predicate function or passing classes to the config will be the only thing that works. For the array of classes approach the downside is the classes would have to be resolved at the time the config is set. For the predicate function this would at least allow the user some flexibility and it could possibly be extended to return a promise. With the predicate function the classes could be globally stored on For me this detail does not matter because I will be configuring rollbar during Angular's module initialization and I can import the classes I need and passing them as an array or a predicate function is pretty much the same. A promise might be taking things too far since if the promise doesn't resolve by the time an error occurs (or breaks when resolving) it might complicate how things should be handled. Anyways, some input on what might get merged would be appreciated. |
Description of the change
In TypeScript Error objects might be implemented instead of extended (i.e. HttpErrorResponse). This causes the
instanceof
check to fail, and this allows more wiggle room. I checked the codebase and I didn't see any other uses ofinstanceof
on theitem.err
so I imagine this should be not an issue.Type of change
Development
Code review