I had a similar problem once and my solution was...
// The parameters are automatically passed to the window.onerror handler...
function myErrorFunction(message, url, linenumber) {
$.post(
"https://host.and/path/to/script/that/stores/entries",
{
"url":url, // URL of the page where the error occured
"lineNumber":linenumber, // Line number where the error occer
"message":message //error message
},
function(){
//callback function for the $.post()
if(console)
if(console.log)
console.log("Error reported.");
}
);
}
window.onerror = myErrorFunction; //adds function "myErrorFunction" to the onError Event
To get more sophisticated you will need to utilize some tricks I have put into my debug project at:
https://github.com/luke80/JavaScript-DebugTools-Luke
EDIT:
Ok, I'll gather out of that project the important bits that apply to your problem:
/*
String prototype .hashCode()
From: http://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript-jquery
*/
if(typeof String['hashCode'] == "undefined") {
String.prototype.hashCode = function(){
var hash = 0, i, char;
if (this.length == 0) return hash;
for (i = 0, l = this.length; i < l; i++) {
char = this.charCodeAt(i);
hash = ((hash<<5)-hash)+char;
hash |= 0; // Convert to 32bit integer
}
return hash;
};
// Start of vars
var _LOG_CALLERARGS_ON = true,
getCallerHash = function(funcString) {
return callerFunc.toString().hashCode();
},
getCallerArgs = function(obj) {
return JSON.stringify(Array.prototype.slice.call(obj),this._detectCircularity(Array.prototype.slice.call(obj))).replace(/^\[/,"(").replace(/\]$/,")");
},
detectCircularity = function(obj) { // From: http://stackoverflow.com/questions/4816099/chrome-sendrequest-error-typeerror-converting-circular-structure-to-json
return (function() {
var i = 0;
return function(key, value) {
if(i !== 0 && typeof(obj) === 'object' && typeof(value) == 'object' && obj == value) return '[Circular]';
if(i >= 29) return '[Too deep, not mined]';
++i;
return value;
}
})(detectCircularity);
},
caller = this.o.caller || arguments.callee.caller || "top";
// End of vars
if(typeof caller != "string") {
if(caller) {
var callerData = ((caller.name)?caller.name:"Unnamed Caller:"+getCallerHash(caller))+((_LOG_CALLERARGS_ON)?getCallerArgs(caller.arguments):"");
// Since this loop could easily become problematic (infinite loop, anyone?) lets impose a limit.
var maxLoops = 64;
var loopCounter = 0;
// Now we gather all (or 64 of them) the caller names (and optionally their parameters)
while(caller.caller && loopCounter < maxLoops) { // <--- there was an error here that I fixed on Oct 15, 2013 @ 11:55AM
callerData += " <- "+((caller.caller.name)?caller.caller.name:"Unnamed Caller:"+getCallerHash(caller.caller))+((_LOG_CALLERARGS_ON)?getCallerArgs(caller.caller.arguments):"")
caller = caller.caller;
loopCounter++;
}
// callerData is now populated with your stack trace.
} else {
// Can't get errors from a non-existent caller
}
}
The callerData
variable should be populated with a string of function names (or a hash of the function contents so you can semi-identify them) optionally with the parameters the functions were called with.
While you can't always get the function names, the contents of those functions can be identified (as they should stay the same) and you can still get useful-ish debug information from the parameters that were passed, etc.
NOTE: I didn't actually test that code above, but it should be mostly the same as the code from my repo. If it doesn't work, please refer to the repo and re-factor the code there to your needs. :)
I hope that helps.