Upload
diogo-antunes
View
1.106
Download
0
Tags:
Embed Size (px)
DESCRIPTION
JS errors, they come from browsers. In various forms, languages and if they are happening in a customer you don't see them. We have a jungle of browsers out there, between desktop, mobile, tablets, tv's etc. Different flavors with the same pain in the end. Log your JS errors, adding stack trace information for them using stacktrace.js. And a small dashboard to look into it. Presented @ #fronttrends 2013
Citation preview
KNOW YOUR ERRORSBECAUSE IT'S A JUNGLE OUT THERE
WHO AM I?Diogo AntunesBooking.comSenior Client Side Developer@dicode
OVERVIEW
logging JS errorsproof of concepttools/services
SO WHY LOG JS ERRORS IF?
YOU DO TDD
YOU DO SELENIUM TESTS
YOU DO HEADLESS BROWSER TESTING
YOU HAVE A TESTING TEAM
IT WORKS ON MY MACHINE
IT'S A JUNGLE OUT THERE!
3RD PARTY SCRIPTS THAT YOU DON'T CONTROLTwitter, Facebook, GA
YOU USE A CDN
even if it is just to load jquery
USERS INSTALL PLUGINS
YOUR MARKETING DEPARTMENT LIKES TRACKING PIXELS
YES, SOME THINGS YOU CANNOT CONTROLbut some of them you can mitigate
SOME CHALLENGES
LOCALIZED MESSAGES
Expected identifier, string or number
Identificador esperado
Se esperaba un identificador, una cadena o un número
Bezeichner erwartet
标识ّف د ا و
LINE NUMBERminify js
using gzip and preserving new lines may be a temporary solution
CRYPTIC MESSAGEScannot find method of undefined
Script error.
cross origin domain policy
Chrome and Firefox
Access-Control-Allow-Origin: *
BE SAFEdeploy environment vars that disable 3rd party code
if possible, without making any deploy to live
that way you can take action quickly
LET'S DO SOME LOGGING
APPROACHES
WINDOW.ONERROR
works across the board
amount of information is limited
window.onerror = function(msg, url, lno){ /* No impact besides parsing overhead is only for the request to log the error when one actually happens */ return true; //hides the message in supported browsers};
TRY/CATCH
works across the board
try { throw new Error("my error");} catch (e){ e.stack; //chrome, firefox e.message; //opera log(e.stack || e.message || e);}
TRY/CATCH
more meaningful errors
performance hit, but you should evaluate if it matters
may lead to a lot of nesting if not thought through
var fn = function(){ throw "new error"; //this exception will not be caught //since it's a string it will not have stack trace};try{ setTimeout(fn,0);} catch(e) { }
TYPES OF EXCEPTIONS
ErrorEvalErrorRangeErrorReferenceErrorSyntaxErrorTypeErrorURIError
LOGGING
GET VS POST
both methods work fine
get has the size of url limitation
you can truncate some data (case by case evaluation)
IMAGE (GET)//assuming src was already calculatedvar img = new Image(1,1);img.onload = function() {};img.src = "/log?msg=error&url=http%3A%2F%2Flocalhost&lno=1";
IFRAME (POST)var iframe = document.createElement('iframe');document.body.appendChild(iframe);var iframeDoc = iframe.contentDocument,content = '<form method="post" action="/log">\<input type="text" name="msg" value="Script Error">\<input type="text" name="url" value="http%3A%2F%2Flocalhost">\<input type="text" name="lno" value="1">\</form>';iframeDoc.open();iframeDoc.write(content);iframeDoc.close();iframeDoc.body.firstChild.submit();
XHR (BOTH)var xhr = new XMLHttpRequest();//postxhr.open("POST",'/log');xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");xhr.send( payload );//getxhr.open("GET",'/log?' + qs);xhr.send();
IF YOU WANT JUST A COUNTER
Google Analytics is also an option
_gaq.push([ '_trackEvent', 'jserror', url + ':' + lno, message || '']);
STACKTRACE.JS<script src="path/to/stacktrace.js"></script>
<script>
</script>
//... your code ...
if (errorCondition) {
var trace = printStackTrace();
//Output however you want!
alert(trace.join('\n\n'));
}
//... more code of yours ...
STACKTRACE.JSFirefox (and Iceweasel) 0.9+
Google Chrome 1+
Safari 3.0+ (including iOS 1+)
Opera 7+
IE 5.5+
Konqueror 3.5+
Flock 1.0+
SeaMonkey 1.0+
K-Meleon 1.5.3+
Epiphany 2.28.0+
Iceape 1.1+
YOUR DASHBOARD
NODEJS + REDIS
express
node_redis
npm install -g express
express dashboard_js
npm install redis
EXPRESS//assuming a sample express app
var log = require('./routes/log');
app.get('/log', log.index);app.post('/log', log.index);app.get('/log_list', log.list);app.get('/log_chart', log.chart);
THE ROUTERS
exports.index = function (req, res) { var msg = req.param('msg', ''), url = req.param('url', ''), lno = req.param('lno', 0), js_error = msg + ':!:' + url + ':!:' + lno; minute = ((+new Date()/60000|0)*60000), data = [ 'jserrors', '' + minute, 1 ];
if(!msg) { res.send('', 400); }
redis_cli.hincrby( data, function(){} ); redis_cli.lpush( 'jserror_' + minute, js_error); res.send('', 202);};
exports.list = function(req, res) {var to = (+new Date()/60000|0)*60000, from = to - 20 * 60000; inc = 60000, prefix = 'jserror_', result = {}, cb = function(res, i){. return function(err, reply){ var ret = []; reply.forEach(function(val, ind){ ret[ind] = val.split(':!:'); }); result[i] = ret; if(i === to) { res.json(result); } }; }; for(var i = from; i<=to; i+=inc) { redis_cli.lrange( [prefix+i,0,100], cb(res, i) ); }};
exports.chart = function(req, res) { var to = (+new Date()/60000|0)*60000, inc = 60000, from = to - 20 * 60000, redis_param = ['jserrors'], ret = []; for(var i = from; i<=to; i+=inc) { redis_param.push(''+i); ret.push({d: new Date(i)}); } redis_cli.hmget( redis_param, function(err, reply){ reply.forEach(function(val, ind){ ret[ind].v = val || 0; }); res.json(ret); });};
MISCELLANEOUS
jquery 2.0
twitter bootstrap
morris
IN ACTION
SERVICES OUT THERE
Smart error groupingTeam collaborationEasiness of integrationUsers statistics
QBAKA
Smart grouping of errorsWe don't rewrite your codeAutomatic ignoring of errorsFilter errors to your liking
{ERRORCEPTION}
you can point it to your own serviceor use appspotmore a service than a SAAS
JSERRLOG
Low overheadEmail digestShows the JavaScript code that caused the errorAutomatic cleanup
MUSCULA
SINCE WE ALREADY LOGGING
Navigation Timing API
not available - Opera, Safari
PROPERTIES
navigationStartunloadEventStartunloadEventEndredirectStartredirectEndfetchStartdomainLookupStartdomainLookupEndconnectStartconnectEnd
PROPERTIES
secureConnectionStartrequestStartresponseStartresponseEnddomLoadingdomInteractivedomContentLoadedEventStartdomContentLoadedEventEnddomCompleteloadEventStartloadEventEnd
VISUAL INDICATION
FRONTEND SPOF
any 3rd party widgetcustom font downloadingeven your own JS can cause it...
LOG EVERYTHING YOU CANEVERYWHERE
don't expect your users to report your errors
be aware, be prepared
THANKS!
Diogo Antunes
Booking.com jobs
Q&A