Know your errors

Post on 15-May-2015

1.105 views 0 download

Tags:

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

Transcript of Know your errors

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