Skip to content
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

Try catching JS errors and sending them to the API #1949

Merged
merged 7 commits into from
Feb 3, 2016

Conversation

scruffian
Copy link
Member

This will catch JS errors in production and send them to the API.

TODOs

  • Disable it in the development environment
  • Restrict to only 1% of users.
  • Use uglifyjs to build the file.

To test, edit some code so it throws a JS error. You should see the API request happen in the Network tab.

To make sure you are included in logging add this to your local storage:
localStorage.setItem('log-errors', true);

props @drewblaisdell and @Tug.

@scruffian scruffian added [Type] Question [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. labels Dec 24, 2015
@scruffian scruffian self-assigned this Dec 24, 2015
@dmsnell
Copy link
Member

dmsnell commented Dec 24, 2015

On a related note, I just found http://yellerapp.com

// POST to the API
xhr.open( 'POST', 'https://public-api.wordpress.com/js-error', true );
xhr.setRequestHeader( 'Content-type', 'application/x-www-form-urlencoded' );
xhr.send( 'message=' + error.message + '&type=' + error.constructor && error.constructor.name + '&userAgent=' + navigator.userAgent + '&stack=' + error.stack );
Copy link
Contributor

Choose a reason for hiding this comment

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

should call encodeURIComponent on each of these parameters

Copy link
Member

Choose a reason for hiding this comment

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

would it not also make some sense to just send this all as structured data in the POST body? something like a JSON export or just the plain message from the exception?

@artpi
Copy link
Contributor

artpi commented Dec 29, 2015

Maybe we can try the service @dmsnell found? (also for 1%)
http://yellerapp.com/
Seems perfect for us!

@artpi
Copy link
Contributor

artpi commented Jan 5, 2016

Apparently there are other similar services:
https://trackjs.com/
https://errorception.com/
https://getsentry.com/for/javascript/

@artpi
Copy link
Contributor

artpi commented Jan 5, 2016

I made a PR connecting to one of these services.
It also tracks proper environment and user ID, so we know which users are affected:
#2107

@scruffian scruffian force-pushed the try/catch-js-errors-2 branch from d40c1e2 to 12847b7 Compare January 7, 2016 10:32
@scruffian scruffian removed their assignment Jan 13, 2016
@apeatling
Copy link
Member

@scruffian What's the status of this one?

@scruffian
Copy link
Member Author

@apeatling it's on my list for this week...

@apeatling
Copy link
Member

👌

@scruffian scruffian force-pushed the try/catch-js-errors-2 branch from 12847b7 to 3bffe59 Compare January 20, 2016 11:42
@scruffian
Copy link
Member Author

@blowery would appreciate your thoughts on this...

@@ -148,12 +149,15 @@ build: install build-$(CALYPSO_ENV)

build-css: public/style.css public/style-rtl.css public/style-debug.css public/editor.css

build-development: build-server $(CLIENT_CONFIG_FILE) server/devdocs/search-index.js build-css
build-inline-js:
@$(UGLIFYJS) -o public/catch-js-errors.js catch-js-errors.js
Copy link
Member

Choose a reason for hiding this comment

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

Do we need a separate build process for this one file? Can we fit into the current build process?

Copy link
Member Author

Choose a reason for hiding this comment

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

The current build process puts the files into one bundle. This needs to be a separate file for the reasons @blowery mentions here: #1868 (comment)

Copy link
Member

Choose a reason for hiding this comment

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

Even then, our current process supports building different chunks or we can make it build a separate file. The idea is to use the same process and tools like webpack, instead of using uglify on its own.

@nb
Copy link
Member

nb commented Jan 22, 2016

Have you looked at the Sentry client for inspiration and probably some tricks?

localStorage.setItem( 'log-errors', true );

// set up handler to POST errors
window.onerror = debounce( function( message, scriptUrl, lineNumber, columnNumber, error ) {
Copy link
Contributor

Choose a reason for hiding this comment

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

need to check to see if window.onerror was already set and call the previous version after doing our work

@Tug
Copy link
Contributor

Tug commented Jan 22, 2016

Yep this is golden https://github.com/getsentry/raven-js/blob/master/src/raven.js#L635

I have noticed that window.onerror returns very little information and almost always errors have no stacktrace :(

@blowery
Copy link
Contributor

blowery commented Jan 22, 2016

Yep this is golden

Wow. That's.... wow. Much wow. Such danger. The noise must be incredible.

To elaborate, that code is replacing methods on Host objects. I would not screw with host objects, as the behavior of host objects is entirely undefined. https://es5.github.io/ has a lot of good info on all the crazy things host objects are allowed to do.

TL;DR: They can do anything they want.

Though I guess it's working for Raven?

Just gives me the willies.

@rralian
Copy link
Contributor

rralian commented Jan 28, 2016

One other thing we would want, but it can come separately if it doesn't make sense here, is some frequency of error events. I understand the extended mobile endpoint will do some throttling for us, so we would get a skewed reporting for frequency. But can we also hook into the analytics module somehow?

xhr.open( 'POST', 'https://public-api.wordpress.com/rest/v1.1/js-error?http_envelope=1', true );
xhr.setRequestHeader( 'Content-type', 'application/x-www-form-urlencoded' );

params = 'client_id=39911&client_secret=cOaYKdrkgXz8xY7aysv4fU6wL6sK5J8a6ojReEIAPwggsznj4Cb6mW0nffTxtYT8&error=' + stringifyErrorForUrlParams( error );
Copy link
Member Author

Choose a reason for hiding this comment

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

It would be good to be able to get these from the config.

Copy link
Member

Choose a reason for hiding this comment

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

@tyxla does that in #47003, 4.5 years later 🥇

@blowery
Copy link
Contributor

blowery commented Feb 1, 2016

I'm confused. My understanding of what the code does is that if you have localStorage.getItem( 'log-errors' ) ==='true' then you'll fire the onerror event. Otherwise, if you are in the 1% then you'll get the localStorage item set an also fire the onerror event. This will only load once per session, which means that at first only 1% of users will have that local storage key set, but in time that will scale up, as we get more sessions, until eventually all users are in the bucket.

Ah, sure. When you do the set, you should set the value to either true or false, depending on which way the 1% falls. When you come back in, if it's already set, you don't bother recalculating it. That way it isn't a 1% chance per visit and it doesn't walk up.

var now = Date.now();

if ( ( now - lastCall ) < delay ) {
return;
Copy link
Contributor

Choose a reason for hiding this comment

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

probably want to stash the error we would have logged in an array or stack so we don't lose errors to the debouncer.

Copy link
Member Author

Choose a reason for hiding this comment

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

It would be nice to do this, but I'd like to get this PR merged. Can we handle this better in the future if we find we need it?

Copy link
Contributor

Choose a reason for hiding this comment

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

How will we know we're missing events? :)

@scruffian scruffian force-pushed the try/catch-js-errors-2 branch from 3d880f9 to 992f49a Compare February 1, 2016 18:41
@scruffian scruffian self-assigned this Feb 2, 2016
@scruffian
Copy link
Member Author

When you come back in, if it's already set, you don't bother recalculating it. That way it isn't a 1% chance per visit and it doesn't walk up.

This is what I did, but I did like the idea of it walking up over time, so that we catch more and more errors. I agree that it's better to control that ourselves though.

@Tug
Copy link
Contributor

Tug commented Feb 2, 2016

Maybe we could run this for all users on the wpcalypso/horizon environment first?

@gravityrail
Copy link
Contributor

LGTM, 👍 for enabling only in horizon/staging first.

@blowery
Copy link
Contributor

blowery commented Feb 2, 2016

I'm happy to get this out the door to staging as is

@scruffian
Copy link
Member Author

Thanks, I added a commit to exclude from production. Good to 🚢 ?

@Tug
Copy link
Contributor

Tug commented Feb 3, 2016

🚢

@Tug Tug added [Status] Ready to Merge and removed [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. labels Feb 3, 2016
scruffian and others added 7 commits February 3, 2016 10:00
This required a change in how the module entries are built.
Before that, webpack module system was included into the `vendor` module.
Since we want to load `catch-js-errors` first, we need to load the module system before that
so it is now extracted into a `common.js` file.

For the next changes, I think it would be probably better to exclude this file from webpack's build
and simply include it like third party services (olark...) in the page.
@scruffian scruffian force-pushed the try/catch-js-errors-2 branch from 3170866 to 644553c Compare February 3, 2016 10:00
scruffian added a commit that referenced this pull request Feb 3, 2016
Try catching JS errors and sending them to the API
@scruffian scruffian merged commit 4b41631 into master Feb 3, 2016
@scruffian scruffian deleted the try/catch-js-errors-2 branch February 3, 2016 10:22
@blowery
Copy link
Contributor

blowery commented Feb 4, 2016

🎉 👍 💯

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.

10 participants