Created
July 1, 2019 08:34
-
-
Save eyecatchup/d0e1fb062343d45fbb5800dd0dc3d4d9 to your computer and use it in GitHub Desktop.
JavaScript global error handling
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var sendError = function (err) { | |
console.log('Caught JS client error:'); | |
console.dir(err); | |
var xhr = new XMLHttpRequest(); | |
xhr.open('POST', '/api/error/add', true); | |
xhr.setRequestHeader('Content-type', 'application/json; charset=utf-8'); | |
xhr.send(JSON.stringify(err)); | |
}; | |
/** | |
* Chrome and Opera fully support the HTML 5 draft spec for ErrorEvent and window.onerror. | |
* In both of these browsers you can use window.onerror to get a full stacktrace: | |
*/ | |
var processError = function (msg, url, lineNo, columnNo, error) { | |
var log = {}; | |
// Handle error objects (/w stack trace) | |
if (msg && msg.message) { | |
log.err = { | |
'msg': msg.message, | |
'file': !!msg.fileName ? msg.fileName : false, | |
'ln': !!msg.lineNumber ? msg.lineNumber : !!lineNo ? lineNo : false, | |
'col': !!msg.columnNumber ? msg.columnNumber : !!columnNo ? columnNo : false, | |
'stacktrace': !!msg.stack ? msg.stack : false, | |
'cause': !!url ? JSON.stringify(url) : false, | |
'errorObj': !!error ? error : false | |
}; | |
} else { | |
log.err = { | |
'msg': msg | |
}; | |
if (!!url) { | |
log.err.file = url; | |
} | |
} | |
log.url = window.location.href; | |
log.userAgent = window.navigator.userAgent; | |
sendError(log); | |
}; | |
window.onerror = function (exception, url, lineNo, columnNo, error) { | |
processError(exception, url); | |
return true; // surpress error alerts in old IEs | |
}; | |
/** | |
* Unfortunately Firefox, Safari and IE are still around and we have to support them too. | |
* As the stacktrace is not available in window.onerror we have to do a little bit more work: | |
* It turns out that the only thing we can do to get stacktraces from errors is to wrap all | |
* of our code in a `try{ }catch(e){ }` block and then look at `e.stack`. | |
*/ | |
function wrap(func) { | |
// Ensure we only wrap the function once. | |
if (!func._wrapped) { | |
func._wrapped = function () { | |
try{ | |
func.apply(this, arguments); | |
} catch(e) { | |
var log = {}; | |
if (e && e.message) { | |
log.err = { | |
'msg': e.message, | |
'stacktrace': !!e.stack ? e.stack : false | |
}; | |
sendError(log); | |
} | |
throw e; | |
} | |
} | |
} | |
return func._wrapped; | |
}; | |
/** | |
* By changing the global definition of addEventListener so that it automatically wraps | |
* the callback we can automatically insert `try{ }catch(e){ }` around most code. | |
*/ | |
var addEventListener = window.EventTarget.prototype.addEventListener; | |
window.EventTarget.prototype.addEventListener = function (event, callback, bubble) { | |
addEventListener.call(this, event, wrap(callback), bubble); | |
} | |
/** | |
* We also need to make sure that removeEventListener keeps working. Because the argument | |
* to addEventListener is changed, it won't. Again we only need to fix this on the prototype object: | |
*/ | |
var removeEventListener = window.EventTarget.prototype.removeEventListener; | |
window.EventTarget.prototype.removeEventListener = function (event, callback, bubble) { | |
removeEventListener.call(this, event, callback._wrapped || callback, bubble); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment