-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Limit normalize
edge nodes
#4687
Conversation
@@ -390,7 +389,7 @@ export function normalize(input: any, depth?: number): any { | |||
* eg. `Non-error exception captured with keys: foo, bar, baz` | |||
*/ | |||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types | |||
export function extractExceptionKeysForMessage(exception: any, maxLength: number = 40): string { | |||
export function extractExceptionKeysForMessage(exception: unknown, maxLength: number = 40): string { |
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.
Unrelated change, let's move into another PR?
return serializeValue(value); | ||
} | ||
// If value implements `toJSON` method, call it and return early | ||
if (typeof value?.toJSON === 'function') { |
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.
unfortunately optional chaining is less bundle size efficient.
if (typeof value?.toJSON === 'function') { | |
if (value != null && typeof value.toJSON === 'function') { |
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.
Could we just early return if value is undefined/null?
// Create source that we will use for the next iteration. It will either be an objectified error object (`Error` type | ||
// with extracted key:value pairs) or the input itself. | ||
const source = getWalkSource(value); | ||
// Create an accumulator that will act as a parent for all future itterations of that branch |
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.
// Create an accumulator that will act as a parent for all future itterations of that branch | |
// Create an accumulator that will act as a parent for all future iterations of that branch |
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types | ||
export function walk(key: string, value: any, depth: number = +Infinity, memo: MemoFunc = memoBuilder()): any { | ||
const [memoize, unmemoize] = memo; | ||
export function normalize(input: unknown, maxDepth: number = +Infinity, maxEdges: number = 10_000): any { |
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.
wait 10_000
works :0
Does it get transpiled properly?
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.
We'll probably have to make maxEdges
configurable like maxDepth
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.
Yep, all gets transpiled by tsc.
Make maxEdges
configurable, or remove the default value?
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.
we should keep the default, but add an option similar to
normalizeDepth?: number; |
Also I wonder if this change will be disruptive to existing customers in any way. Any reason to choose 10_000
?
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.
10k is just a rough guestimate for what will likely not be noticed by customers but still limit crazy large objects.
I think the alternative of limiting number of properties/elements per object/array might be less disruptive and output more useful serialised output. The issue I see with this edges approach is that it's hard to pick a maxEdges
value and when that number is reached, nothing more is outputted. This includes skipping properties further up the object tree.
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.
The issue I see with this edges approach is that it's hard to pick a maxEdges value and when that number is reached, nothing more is outputted
Yeah good observation. I think limiting number of properties/elements per object/array
is also much more intuitive to understand - and adjusting it will be much more obvious.
if (!Object.prototype.hasOwnProperty.call(source, innerKey)) { | ||
continue; | ||
if (edges >= maxEdges) { | ||
acc[innerKey] = '[Max Edges Reached...]'; |
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.
Maybe lets call this [MaxEdges ~]
to make it consistent with [Circular ~]
?
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.
Just a small nitpick, but other than that looks good
Closing in favour of #4689 |
I have been reviewing
normalize
andwalk
as part of #4579.Looking through the recent PRs from @lobsterkatie it looks like most of the issues have already been sorted!
The last remaining thing I wanted to improve was limiting the overall work normalisation/serialisation has to do if users inadvertently log large objects. The existing implementation only considers depth but this can still result in huge output.
For example, the following will result in a huge serialised event, even with a normalisation depth set to 3:
This PR moves
walk
insidenormalize
which allows counting enge nodes and bailing out when the limit is reached.This means this:
now becomes:
Alternatives
This PR halts object/array properties output when the limit is reached which favours properties that are encountered earlier and this may not be desirable.
An alternative would be to limit individual objects/arrays to a maximum number of properties/elements.