-
Notifications
You must be signed in to change notification settings - Fork 33
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
feat: Support serializing primitives within Error causes (#158) #159
base: master
Are you sure you want to change the base?
Conversation
test/err.test.js
Outdated
// ["an", "array"], | ||
// { an: "object" }, |
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'm not sure what the desired output would be for the string message for err. As is, output would be
foo: an,array
foo: [object: Object]
Neither are great, but if acceptable, I can add these back
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.
Open to alternative suggestions
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 is still the most challenging part. For example how to output ['nested', [new Error('bar', { cause: 'baz'})]]
if this is set as a cause. The same for an object.
err-with-cause
is much easier in this regard because it isn't opinionated in how to format the error.
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.
Find prior art and do what the prior art does – node.js and browsers all have support for logging error causes and if Pino are to handle non-error causes then it should not deviate from them in how it does so
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.
Well it appears that for this particular serializer (err.js
), it is actually quite opinionated on the (message) output style, which is why this question remains unanswered. The only prior art of this style that I am aware of is within this library, for example with;
throw new Error("error a", { cause new Error("error b") })
The message
string output is;
error a: error b
So basically; ${error.message}: ${cause.message}
. Since it only deals with errors, there is no style for how to handle non error objects.
Since nothing was defined, I investigated an approach which mainly uses JSON.stringify
along with handling some edge cases, but the complexity really jumped, and I still wasn't sure how to display nested errors. For example, if the cause is a string, number, object, array, null or symbol, this can be somewhat neatly output;
error a: "string"
error a: 123
error a: {"nested":{"object":"value"}}
error a: [["string"],123]
error a: Symbol(symbol)
error a: null
But what about an error nested within an array or object? The err.js
serializer compacts the error format to something like ${error.message}: ${cause.message}
so continuing with that style yields something like;
error a: {"object": error b: error c}
It isn't really intuitive since it looks like the object is malformed, and isn't entirely obvious you are even looking at a nested error unless the error messages actually contain the word Error or equivalent within.
This is not how err-with-cause.test.js
outputs errors, which is in line with what NodeJS and Browsers output, and as such doesn't really suffer from any of this.
@@ -75,6 +75,22 @@ test('keeps non-error cause', () => { | |||
assert.strictEqual(serialized.cause, 'abc') | |||
}) | |||
|
|||
test('keeps non-error cause from constructor', () => { |
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 think this test hints at why supporting non-Error objects is probably not a great idea. What should be done if someone threw?:
{
cause: {
foo: 'foo',
cause: {
bar: 'bar',
cause: {
baz: 'baz'
}
}
}
}
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.
If cause is not an error then it should be serialized as a non error value would be.
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.
But the point of this PR is to serialize non-error objects as error objects, right?
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 guess an additional test is needed to vizualize the output, but really the point of this PR was to serialize non-error objects and display them as is, not to serialize them as Error objects specifically.
So if an object with nested objects was passed as a cause, regardless if its nested properties were named cause
or something else, the entire object and its nested properties and values would be output.
2edbd8c
to
e8c0871
Compare
An alternative that I looked into some years ago was to align with what Node.js itself does when it serializes: voxpelli/pony-cause#23 Would be kind of nice to fix this "upstream" in |
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.
lgtm
ping @jsumners |
// ['an', 'array'], | ||
// ['a', ['nested', 'array']], | ||
// { an: 'object' }, | ||
// { a: { nested: 'object' } }, |
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.
Are these commented out because String({ an: 'object' })
returns [object Object]
?
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.
Originally, yes. I commented about a WIP approach I have locally in this comment.
Allow primitives to be returned as error causes when passed via the ErrorOptions object in an Error object constructor.