Client-side error reporting and "Script error"

How do you identify client-side errors that occur in scripts from other domains?

For clarity, suppose we have a medium-sized web application that uses several scripts hosted by other domains (e.g. Google Maps JS SDK).

And once you started getting Script errorerrors in your logs, which means that an error has occurred in the third-party code.

But how would you find the exact method in your code that called third-party code that eventually failed?

PS: the error is not reproduced by developers and is rarely found on client machines quite rarely.

PPS: for errors above window.onerror DO NOT provide call stack, correct error message, file name and line number. Thus, it provides literally nothing useful but an error message Script error.

PPPS:

A third party script is included using tags <script src="http://..."></script>and executed usingsomeFunctionFromTheThirdPartyScript();

+4
source share
1 answer

I had a similar problem 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 a more sophisticated approach, you will need to use some of the tricks I put into my debugging project: https://github.com/luke80/JavaScript-DebugTools-Luke

EDIT: Well, I will collect from this project the important bits that are relevant 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
    }
}

callerData ( , ), , .

, ( ), - ..

. , , . , .:)

, .

+1

All Articles