JavaScript: Using XMLHttpRequest to log JavaScript errors
If you've read our related article Recording Outbound Links using Ajax you'll be familiar with the concept of using Ajax to record user actions.
This article goes a step further letting you log any JavaScript errors that occur on your website to a text file that you can later view or download.
This can be very handy as many JavaScript errors are user-, browser- or platform-specific and it's not always feasible to test all possiblities yourself.
Defining a Custom Error Handler
The first step is to override or redirect the built in error handler window.onerror with our own function. This is a lot simpler than it sounds:
<script src="ajaxrequest.js"></script>
<script>
window.onerror = function(msg, url, line) {
if(encodeURIComponent) {
var req = new AjaxRequest();
var params = "msg=" + encodeURIComponent(msg) + '&url=' + encodeURIComponent(url) + "&line=" + line;
req.setMethod("POST");
return req.loadXMLDoc("/logerror.php", params);
}
return false;
};
</script>
If you return a value of true then only your function will be called and no message will be presented in the browser. If you instead return a value of false, your error handler will be called and then the browser will respond to the error in it's own way.
The function as presented will either make a successful call to the server-side script (see below) or let the browser display the error to the user as it sees fit. That way someone is always notified of the error.
The best place for this code is in the HEAD of your HTML document or in an included JavaScript file.
Upgraded code
The code here serves the same function has that already presented, but is using a new version of our Ajax class as well as the error event which is slightly different to the old onerror approach:
<script src="AjaxRequestXML.js"></script>
<script>
window.addEventListener("error", (e) => {
let params = {
msg: e.message,
url: e.filename,
line: e.lineno,
};
(new AjaxRequestXML).post("/logerror.php", params);
});
/*
throw "Deliberate Error!";
*/
</script>
The throw command shown in comments can be used for testing. It will append something like the following to the log file:
Uncaught Deliberate Error! in https://www.the-art-of-web.com/javascript/onclick-async-href/ on line XXX
So far all we've done is captured the JavaScript error and POSTed the details to /logerror.php. We still have to enable logging.
Logging errors to a text file
Here we see how a PHP script can be used as the target of the Ajax request in order to record the details of the error:
Source code for /logerror.php:
<?PHP
include "xmlresponse.php";
if($_POST && isset($_POST['msg'], $_POST['url'], $_POST['line'])) {
if($fp = fopen("{$_SERVER['DOCUMENT_ROOT']}/onerror.log", "a")) {
$logline = "[{_SERVER['REMOTE_ADDR']}]: {$_POST['msg']} in {$_POST['url']} on line {$_POST['line']}";
fwrite($fp, date("M d H:i:s") . " {$logline}\n");
fclose($fp);
}
}
$xml = new \Chirp\xmlResponse();
$xml->start();
$xml->end();
exit;
When it receives a POST request with values for msg, url and line then a line containing that information is added to the file onerror.log.
The XML header and empty response tag are necessary only to prevent a JavaScript error in the processReqChange - essential in this case as you don't want to create an infinite loop.
The onerror.log file needs to be writable by the webserver. The best way to enable this is to first touch the file so that it exists, then chgrp the file to the webserver user and finally chmod 664 to make it writable.
Unfortunately the Safari and Opera web browsers no
longer support the setting of an onerror event handler, so this
script is less useful than it might have been.
Possible additions to the script
If you're going to use this on a live website then you might want to consider:
- checking that the Referer is actually your own website;
- modifying the fwrite message to include the User Agent string so you can see which browser encountered the error; and
- monitoring the log file using a CRON script to make sure it's not growing out of control.
The code presented here works in Internet Explorer (Win) and Firefox,
but not so well in Safari which seems to have it's own way of handling
errors. Some Mozilla browsers also don't pass a value for url
to the error handling function.
Related Articles - Ajax
- JavaScript Making an asynchronous request before following an href
- JavaScript Form Validation using Ajax
- JavaScript Using a Promise to make sequential Ajax requests
- JavaScript Avoiding the Race Condition with Ajax
- JavaScript Using XMLHttpRequest to log JavaScript errors
- JavaScript Making a HEAD request via an Ajax script
- JavaScript Recording Outbound Links using Ajax
- JavaScript Making sure form values are unique using Ajax
- PHP Generating an XML Response for Ajax Applications
- PHP Ajax script for making cURL HEAD requests
- JavaScript Web Services using XMLHttpRequest (Ajax)
Matt Perdeck 31 October, 2013
A similar client side / server side open source solution for ASP.NET or MVC is JSNLog (jsnlog.com).
This is a small (1.5kb) but feature rich JavaScript logging library plus a server side dll that receives your client side log messages and passes them on to your server side logging library (NLog, etc.) for logging.
It also let you configure loggers in your web.config, so there is no need to change your code to switch on a logger.
Dumitru Glavan 27 May, 2013
Nice article!
We recently launched jslogger.com . It takes care of your browser and mobile devices errors. It's also possible to use it in backend and log the exceptons coming from a NodeJS app.
Worth to give it a try.
Allan Ebdrup 13 November, 2011
Great stuff, people should be just as vigilant about logging javascript-errors, as they are about logging php/dotNet/Java errors on their backend. JavaScript errors can be just as bad as a website that is down.
There is a drawback the the method described here using onerror. Errors are not logged on iPhones, iPads, Safari and some other browsers.
If you wan to log on those browsers, you need to insert try catch around all eventhandlers and xhr-requests too. This will also give you a chance to get more information about the error.
-----
We're a startup. We've solved a lot of this problem, while still having a solution that simply installs by copying a script to your page (Like Google Analytics)
Currently we are in private beta (free). muscula.com/
offbeatmammal 23 September, 2011
we've put together a free, open source version that includes the javascript client side stuff and also a sample AppEngine project to receive error logs and report them back to the developer.
would love thoughts, feedback and maybe some improvements over at jsErrLog.appspot.com (which links through to the GitHub repository as well).
Very nice
Carro DF Brasilia 22 July, 2008
Thanks for the function, a use them to build a prototype version:
function js_err_logger(msg, url, line)
{
if(encodeURIComponent) {
var params = 'msg=' + encodeURIComponent(msg) + '&url=' + encodeURIComponent(url) + '&line=' + line;
var uri = '/index.php?opcao=default&tarefa=js_err_logger';
var opt= { method:'post', postBody:params, onSuccess:function(r) { if(debug=='1') alert(r.responseText); }, on404:function(t) { alert(t.statusText)}, onFailure:function(t) { alert(t.statusText) }, asynchronous:true };
return new Ajax.Request(uri,opt);
}
return false;
}
window.onerror = js_err_logger;