-
Notifications
You must be signed in to change notification settings - Fork 77
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
front_end_error_logging #237
Conversation
One issue is that react doesn't appear to be able to catch errors that happen in handlers, only in lifecycle functions: facebook/react#11409. These kinds of errors will end up being type 2 and 3 instead. For testing this, you should throw your error during the |
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.
Error logging flow in general looks good. Nice job following the existing conventions for constants and post methods! Next up is going to be polishing and dealing with the global case in a way that allows users to decide if something major broke.
It might be worth some kind of heuristic on global errors, like setting a timeout when they occur, and then seeing if the user is still interacting with the app and making progress (which would imply that the error was actually minor). Any thoughts on what a good practice would be for this @pringshia?
errorInfo: errorInfo | ||
}) | ||
// alert Mephisto worker of a component error | ||
alert("error from a component" + 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.
We'll probably want to update this message once everything else is fully hashed out!
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.
Yes. It was an indication for me that the error was raised from ErrorBoundary
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 actually don't see a difference between type 2 and type 3 (global) errors. I had to place the window.eventListener('error'..)
definition after the useMephistoTask
as it uses handleFatalError
. And even placing an error at the beginning of MainApp
wouldn't fire the window.eventListener('error', ..)
nor window.onerror
callback as the error is place before defining any of them. So I don't know how to produce a global error that might happen right after defining the MainApp
unless useMephistoTask
should handle that type inside it, is that 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.
Hmm, I wonder why this is happening, as <script src="wrap_crowd_source.js"></script>
is defined in the <head>
tag. Let me experiment a bit with this and get back to you.
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.
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.
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.
Yes I am able to see them in the console but do you get them back in the backend? there should be a logging INFO for the error sent back to the backend
packages/mephisto-task/src/index.js
Outdated
(data) => { | ||
console.log('inside handleFatalError ...') | ||
postErrorLog(state.agentId, data) | ||
// handleSubmit(data) |
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 may want to consider a distinction as to whether or not the error is actually fatal - in the cases where it is, that's when we should trigger a submit. This will allow us to surface something to the user when global errors happen, without necessarily forcing them to submit?
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.
How can I categorize the fatal errors from non fatal ones?
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.
as a temporary step you can trigger a confirm()
dialog and allow the user to choose? i don't like this because it can be a jarring experience for users, especially in the case of false positives, but it can be a good stopgap for now
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 already did this for type 2 errors. Thansk
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.
Do you mean do the confirm()
inside componentDidCatch()
? because I already do confirm()
in the window.onerror
event.
onClick={() => onSubmit({ rating: "good" })} | ||
// Test for type 2 errors | ||
onClick={()=> {throw new Error("test error event_handler");}} | ||
// onClick={() => onSubmit({ rating: "good" })} |
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 reminder to revert this when we're ready to merge
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.
to echo Jack, these errors in the callback may actually be caught as type 3 errors, instead of 2
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 event handlers errors which can't be caught by React's ErrorBoundary
are caught by the window.onerror
event handler and those which can be caught by both the window.onerror
event handler and ErrorBoundary
are caught twice but this should be the case for mode=development
and once the mode=production
it should be caught only once in the ErrorBoundary
[according to StackOverFlow]
console.log("You pressed Cancel!"); | ||
} | ||
return true; | ||
}) |
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.
once this seems to be working correctly, let's move it into wrap_crowd_source.js
so all tasks automatically inherit this functionality
@@ -11,19 +11,76 @@ import ReactDOM from "react-dom"; | |||
import { BaseFrontend, LoadingScreen } from "./components/core_components.jsx"; | |||
import { useMephistoTask } from "mephisto-task"; | |||
|
|||
class ErrorBoundary extends React.Component { |
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.
great first step in implementing this. the next step would be to move this component into mephisto-task
and import it into this project from there. this will allow us to have a reusable mephisto component we can use from other tasks
As Jack mentioned |
6caa1c4
to
3395550
Compare
I've polished the debugging logs and script, and re-located the error handling components ( I tried to add |
Are you still planning on adding a const to the top of wrap_crowd_source.js to flag between the two different behaviors we discussed? (i.e. auto-submit on error vs. prompt to submit on error). |
@@ -15,6 +15,7 @@ for both to be able to register them with the backend database. | |||
Returning None for the assignment_id means that the task is being | |||
previewed by the given worker. | |||
\------------------------------------------*/ | |||
auto_submit = false |
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.
looks good, I would make this ALL_CAPS as such and declare it as a const
} | ||
} | ||
else { | ||
console.log("sending to email address: ####") |
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 can wire up this portion to the /log_error
endpoint you created?
prompt('send the following error to the email address: '+ | ||
'[email address]', JSON.stringify(event.error.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.
Sorry a bit out of context here - why are we asking for an email address?
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.
Pratik told me there should be a choice whether for the user to auto submit the error (wiring up /log_error
) or show them an email and a copy-enabled version of the error message to send that error by themselves to an email address.
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.
Understood - generally we may have a case where we want the submit to be optional but not explicitly state the contact info (for a case where people may not want to expose their actual email, but instead get contacted through the site). So really there should be three options:
- Auto-submit. Display the message "An error has occurred. This has been logged to the requester automatically."
- Don't auto-submit. Display the message. "We think an error has occurred. If the task is broken, please send this context to the requester.
- Don't auto-submit. Same message as the above, but with an email instead of "to the requester"
Edit: I'm realizing this is attached to a specific wrap_crowd_source.js
file, meaning the scenario here is fixed.
@@ -53,3 +54,22 @@ function handleSubmitToProvider(task_data) { | |||
alert("The task has been submitted! Data: " + JSON.stringify(task_data)) | |||
return true; | |||
} | |||
|
|||
// Adding event listener instead of using window.onerror prevents the error to be caught twice | |||
window.addEventListener('error', function (event) { |
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.
@pringshia is there a reason this listener is defined in wrap_crowd_source.js
and not as a part of mephisto-task
?
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 first place I put it inside mephisto-task
but Pratik said it's better to be inside each provider separately but I didn't find it convenience because we will need to put it in each Provider's wrap_crowd_source.js
, @pringshia could you elaborate why is this better?
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.
@JackUrb - The reason for putting this in wrap_crowd_source.js
as opposed to mephisto-task
is so that this global catch-all error handling (list as #3
here: #231) can also apply to:
- Errors in static HTML tasks
- Errors that may occur at the React library level, before the application code has had a chance to run (maybe related due to a build linking / webpack error?)
Hi @saraebrahim! Thank you for your pull request. We require contributors to sign our Contributor License Agreement, and yours needs attention. You currently have a record in our system, but we do not have a signature on file. In order for us to review and merge your code, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA. If you have received this in error or have any questions, please contact us at [email protected]. Thanks! |
Changes in here are all included in #343, so I'm closing this version. |
Hello all,
I'm running into an issue, here is the detailed explanation:
For the front end error message:
ErrorBoundary
component insidestatic_react_task/webapp/app.jsx
temporarily (once I correct the behavior of the issue I have I'll move it tomephisto-task/utils
componentDidCatch
insideErrorBoundary
component is not called, I've tried toconsole.log()
some messages inside that method with nothing showing up in the console. Am I missing something or it's real thatErrorBoundary
could be not triggered in that test case as stated here and I just need to try a different test case?For propagating the error from the front to the backend:
handleFatalError
same ashandleSubmit
inuseMephistoTask
with just callinghandleSubmit
with a different data dictionary.ErrorBoundary
calledhandleError
which is triggered incomponentDidCatch
(which is not called properly as I explained in the first part)componentDidCatch
not being triggered or do I miss something important here?