Many websites rely on significant amounts of code executing in the browser. This client-side code is written with javascript and typically uses javascript libraries. Recently Angular (by Google), React (by Facebook) and Ember (various), are challenging JQuery to become the dominant client-side library. In this post I describe how to attach your own custom function to javascript’s global error handler and use this custom function to report errors back to you for debugging.
window.onerror
The global object in a browser is ‘window’. If you’re server-side with Node.js you’ll use ‘global’ instead of ‘window’, the rest applies the same.
You can attach a function to the global error handler as follows:
window.onerror = reportUnhandledJavascriptErrors;
Note that you don’t use brackets here. Adding brackets would cause the function to execute, which is not what you want. What we are doing in the above statement is telling window.onerror that it should point to the function we will define below. If you’re concerned about how it is able to attach a function that isn’t yet defined then you can read an excellent article on hoisting here.
Defining the handler
Next we need to define the function we just attached. It is important to give it the correct signature so that you can get all the information possible, although you should be aware that different browsers do handle this slightly differently.
function reportUnhandledJavascriptErrors(message, url, line, column, error){ // do actual reporting here, not alert('an error occurred'); };
Let me explain each of the parameters to this function briefly:
message
Contains text with a generated description of the error
“Syntax error, unrecognized expression: unsupported pseudo: matches”
Pro-tip: use encodeURIComponent(message) to escape any characters that could break the JSON object we will build from the message, url, and error.stack.
url
Contains the full address of the page where the error occurred. It includes the full address including the protocol, the domain, and the url stem.
“http://localhost:64482/assets/js/jquery-1.10.2.min.js”
line & column
These are integers giving the line and column where the error occurred.
error
Error is an object which has a most interesting property of stack, which is a stack trace.
Reporting unhandled exceptions
The final step is to replace the body of the function above with a call to a reporting web service, like this:
var args = "{'message':'" + encodeURIComponent(message); if (url) args += "','url':'" + encodeURIComponent(url); if (line) args += "','line':" + line; if (column) args += ",'col':" + column; if (error && error.stack) { args += ",'stack':'"; args += encodeURIComponent(error.stack) + "'}"; } else { args += " }"; } callService(args);
As you can see in the above implementation, we are assured to receive a message from the browser. Sometimes this will contain the stack trace and other information, and so we always want to report that. When the other parameters are present, we report that information also.
Of course building a web service to consume this call is beyond the scope of this post, but you get the idea 😉