Skip to content

Tweaked captured error log slightly based on feedback #8785

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

Merged
merged 3 commits into from
Jan 17, 2017

Conversation

bvaughn
Copy link
Contributor

@bvaughn bvaughn commented Jan 14, 2017

Before

screen shot 2017-01-13 at 4 19 17 pm

After

Chrome

screen shot 2017-01-14 at 9 32 15 am

Firefox

screen shot 2017-01-14 at 9 31 58 am

Safari

screen shot 2017-01-14 at 9 31 47 am

Internet Explorer

screen shot 2017-01-14 at 9 40 18 am

Edge

screen shot 2017-01-17 at 10 00 49 am

@gaearon
Copy link
Collaborator

gaearon commented Jan 14, 2017

What concerns me here is it's easy to miss the error message. Could we put it above component stack, but leave the function stack below?

@acdlite
Copy link
Collaborator

acdlite commented Jan 14, 2017

I agree with Dan. Error message, then component stack, then JS stack

@bvaughn
Copy link
Contributor Author

bvaughn commented Jan 14, 2017

Right-o. Will do.

@bvaughn bvaughn force-pushed the captured-error-log-bikeshedding branch from 5467a66 to 7b2914c Compare January 14, 2017 00:34
@bvaughn
Copy link
Contributor Author

bvaughn commented Jan 14, 2017

Ok. New screenshot.

@acdlite
Copy link
Collaborator

acdlite commented Jan 14, 2017

Can we remove the second error message and just show the stack? Like

JS stack:
  at alsdjfaksdlj.js 999
  at alsdfjaklsdfkj.js 999

@gaearon
Copy link
Collaborator

gaearon commented Jan 14, 2017

Was also about to suggest this. I'd use "The error was thrown at:" instead of "JS Stack:" though.

@bvaughn
Copy link
Contributor Author

bvaughn commented Jan 14, 2017

Sure, I can remove the redundant error message.

"The error was thrown at" seems awful similar to "The error was thrown in the following location". How about "The error is located at" for the component stack and "The error was thrown at" for the call stack?

@@ -33,6 +33,9 @@ function logCapturedError(capturedError : CapturedError) : void {
? `React caught an error thrown by ${componentName}.`
: 'React caught an error thrown by one of your components.';

const callStack = error.stack;
const trimmedCallStack = callStack.substring(callStack.indexOf('\n'));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not consistent between browsers.
For example Firefox or Safari don’t seem to put the message in stack.

I suggest checking if the first line of the stack ends with error message. If it does, cut it out, otherwise keep it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had no idea. Thanks for the catch. I'll push up a small fix shortly.

@@ -33,6 +33,9 @@ function logCapturedError(capturedError : CapturedError) : void {
? `React caught an error thrown by ${componentName}.`
: 'React caught an error thrown by one of your components.';

const callStack = error.stack;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On line 29, I think you should use error.name instead of "Error" because it might be a TypeError or something custom.

@bvaughn
Copy link
Contributor Author

bvaughn commented Jan 14, 2017

Okay! Error stack format has been tidied up for consistency across browsers. Screenshots have been added for each. 😄

Thanks for the catch @gaearon!

@bvaughn
Copy link
Contributor Author

bvaughn commented Jan 14, 2017

PS Chrome's formatting of errors is head and shoulders above 🙇

Firefox's is not so great. Yellow text on a red background. ☹️

} = error;

const errorSummary = message
? `${name}: ${message}\n\n`
: '';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to include the name even if there's no message?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, yes I suppose it would be. 😄

const callStack = error.stack;
const trimmedCallStack = callStack.substring(callStack.indexOf('\n'));
// Error stack varies by browser; normalize it for our logging.
let formattedCallStack = stack.indexOf(message) >= 0
Copy link
Collaborator

@gaearon gaearon Jan 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be safer to split the first line first. Then check the first line for matching the message.
Otherwise this code behave in a weird way if the message was not on the first line.

Now that I think of it, messages could also be multiline. So maybe it's best to check for a very specific pattern that Chrome does (and cut it out based on where the message ends), and not touch it in any other case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Hadn't considered the multiline case. Shouldn't code before ☕️ 😁

I think this version (just pushed) is more robust. Tested various browsers with single-line message, multi-line message, and no message.

@bvaughn bvaughn force-pushed the captured-error-log-bikeshedding branch from 015f82b to 937d13a Compare January 14, 2017 20:38
const componentNameMessage = componentName
? `React caught an error thrown by ${componentName}.`
: 'React caught an error thrown by one of your components.';

// Error stack varies by browser; normalize it for our logging.
const formattedCallStack = stack.replace(new RegExp(`^${errorSummary}\n`), '')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would need to be escaped in case it includes regex metachars. How about just:

if (stack.slice(0, errorSummary.length) === errorSummary) {
  stack = stack.slice(errorSummary.length);
}
if (stack.charAt(0) === '\n') {
  stack = stack.slice(1);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing that out Ben.

The latest commit has been tested with single-line message, multi-line message, no message, and messages containing special regex chars.

Browsers tested: Chrome, Firefox, Safari, IE

`The error was thrown in the following location: ${componentStack}`
`${errorSummary}\n\n` +
`The error is located at: ${componentStack}\n\n` +
`The error was thrown at: ${formattedCallStack}`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you could also get away with just showing the call stack without any intro line before it.

Copy link
Contributor Author

@bvaughn bvaughn Jan 15, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edge-case in message content and browser formatting differences are why I initially just logged error.stack by itself. The "thrown at" header and stripping the redundant error message (in the case of Chrome) were suggestions from others (above).

Though FWIW I think the stack, by itself, is not as intuitive without the header and formatting for certain browsers.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(y) I'm good with this or just "Call stack:" then.

@bvaughn bvaughn force-pushed the captured-error-log-bikeshedding branch from 937d13a to 7902e81 Compare January 15, 2017 01:07
@bvaughn
Copy link
Contributor Author

bvaughn commented Jan 17, 2017

Hey @gaearon 😄 Thanks again for the review. Any other changes you want to see on this PR?

Copy link
Collaborator

@sophiebits sophiebits left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

`The error was thrown in the following location: ${componentStack}`
`${errorSummary}\n\n` +
`The error is located at: ${componentStack}\n\n` +
`The error was thrown at: ${formattedCallStack}`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(y) I'm good with this or just "Call stack:" then.

@bvaughn
Copy link
Contributor Author

bvaughn commented Jan 17, 2017

I think Dan's out for the week on vacation now. Since this has 2 approvals, and no remaining requested changes from him, I'm going to go ahead and merge it. 😄 Can always tweak it further in the future.

@bvaughn bvaughn merged commit 16abcef into facebook:master Jan 17, 2017
@bvaughn bvaughn deleted the captured-error-log-bikeshedding branch January 17, 2017 22:32
@sophiebits
Copy link
Collaborator

sophiebits commented Jan 17, 2017

Dan approved it, you know. :)

image

@bvaughn
Copy link
Contributor Author

bvaughn commented Jan 17, 2017

Weird. Maybe that Github lag thing he was mentioning. My Github did not show Dan as approving it at the time I left that comment. 😁

@gaearon
Copy link
Collaborator

gaearon commented Jan 18, 2017

GitHub loves caching. I Cmd+R it all the time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants