Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

Know your errors

Know your errors

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

Diogo Antunes

April 24, 2013
Tweet

More Decks by Diogo Antunes

Other Decks in Programming

Transcript

  1. LOCALIZED MESSAGES Expected identifier, string or number Identificador esperado Se

    esperaba un identificador, una cadena o un número Bezeichner erwartet 标识 فّ د و ا
  2. CRYPTIC MESSAGES cannot find method of undefined Script error. cross

    origin domain policy Chrome and Firefox Access-Control-Allow-Origin: *
  3. BE SAFE deploy environment vars that disable 3rd party code

    if possible, without making any deploy to live that way you can take action quickly
  4. 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 };
  5. 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); }
  6. 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) { }
  7. GET VS POST both methods work fine get has the

    size of url limitation you can truncate some data (case by case evaluation)
  8. IMAGE (GET) //assuming src was already calculated var img =

    new Image(1,1); img.onload = function() {}; img.src = "/log?msg=error&url=http%3A%2F%2Flocalhost&lno=1";
  9. 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();
  10. XHR (BOTH) var xhr = new XMLHttpRequest(); //post xhr.open("POST",'/log'); xhr.setRequestHeader("Content-type",

    "application/x-www-form-urlencoded"); xhr.send( payload ); //get xhr.open("GET",'/log?' + qs); xhr.send();
  11. IF YOU WANT JUST A COUNTER Google Analytics is also

    an option _gaq.push([ '_trackEvent', 'jserror', url + ':' + lno, message || '' ]);
  12. 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 ...
  13. STACKTRACE.JS Firefox (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+
  14. 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);
  15. 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); };
  16. 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) ); } };
  17. 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); }); };
  18. Smart grouping of errors We don't rewrite your code Automatic

    ignoring of errors Filter errors to your liking {ERRORCEPTION}
  19. you can point it to your own service or use

    appspot more a service than a SAAS JSERRLOG
  20. LOG EVERYTHING YOU CAN EVERYWHERE don't expect your users to

    report your errors be aware, be prepared
  21. Q&A