SenchaCon 2016: Expect the Unexpected - Dealing with Errors in Web Apps

Post on 12-Jan-2017

124 views 0 download

Transcript of SenchaCon 2016: Expect the Unexpected - Dealing with Errors in Web Apps

Expect the unexpected - dealing with errors in web apps

Mats Bryntse

Founder, @bryntum

Who is Mats Bryntse?

• From Stockholm, Sweden

• Working with Ext JS since 2007

• mankz in the Sencha forums

• Founder of Bryntum (Scheduler, Gantt, Kanban Taskboard, Siesta)

• @bryntum

What is a javascript Error?

Javascript error basics

• Javascript errors are unhandled exceptions happening in your code base

• Or in the frameworks you use

• Doesn’t matter where it happens, poor user impression regardless

• With JS codebases in the size of MBs, we can no longer ignore error handling + logging

• Good news - it’s easy 😀

What does the user see when there is a JS error?

🤔

Nothing, unless you show them

😳

The ErrorEvent constructor

• When an error happens, an ErrorEvent is fired on the window object

• ErrorEvent.message

• ErrorEvent.filename

• ErrorEvent.lineno

• ErrorEvent.colno // Normal browsers only

• ErrorEvent.error // Normal browsers only

Global error handler

// Old schoolwindow.onerror = function(message, source, lineno, colno, error) { … };

window.addEventListener(‘error’, function(event) { // event.message // event.filename // event.lineno // event.colno // good browsers only // event.error (has stack property, in good browsers)}, true);

…or by listening to the window ‘error’ eventListen with capture=true to also get notified of resource load errors

Errors are easily caught in window.onerror

You can throw your own Error too

// Bad, no call stack will be availablethrow ‘My own error’;

// preferredthrow new Error(‘This will have call stack’);

try { // Questionable code goes here} catch(e) { // log error} finally { // always called}

• throw a String

• Or better, an Error instance (callstack)

• Catch using simple try/catch/finally

The error reporting cycle

What’s the typical strategy for error reporting at Enterprise X?

Flow of an error - Enterprise version

Error in web app

Reports to own support Your company

User realises it’s an error

010101011011110

User Dear User,

/Depressed dev.

Can’t reproduce, need more info.

Sincerely yours,

Too much guessing…

🕵🏼

10 points

“Add-to-cart button doesn’t work”

9 points ‘a is undefined’

9 points ‘console.lgo is not a function’

8 points line 1, column 536171

7 points

6 points

5 points Step by step:First login as userAdd few items to cartClick checkout button => crash

Logging and monitoring errors in your web app

Logging is easy

• Log message, file, line, stack etc..

• Add any extra meta relevant for your debugging (userId/name/…)

• Poor mans error logger:

function log(msg) { new Image().src = "log.php?msg=" + encodeURIComponent(msg);}

window.onerror = log;

throw new Error("Ooops");

Saving error info

• Store error logs in some database on a non-production server

• Throttle logging on client side + server side

• Probably we only care about the first error on a page

Flow of an error - Improved version

Error in web app

Your company

User realises it’s an error

010101011011110

User

Making sense of a callstack is sometimes easy…

…but often it takes a lot of detective work

🕵🏼

Solving a complex puzzleConnecting the dots…

undefined is not a function

Bryntum - How we (used to) handle errors

Online examples is a test suite of sorts

Previous error handling at Bryntum

• Web site visitors are test monkeys unknowingly === free help• Errors logged in a DB

• Emails sent to devs

= Very useful for finding and rapidly fixing bugs

Error handling at Bryntum

Instant feedback

Site visitors / “Late QA”Developers

Error handling at Bryntum

• What we had was pretty good, not great

• Lots of time spent playing detective, looking at callstacks

• Just error message, filename, callstack isn’t enough to rapidly locate root cause

• We would like to know more…

🕵🏼

Wish list…

Function arguments

Know how the crashing function was called

function getUserInfo(id) { var user = this.store.getById(id); // => null

return user.getInfo(); // Cannot call getInfo of null }

getUserInfo(-1); // crashes, would be neat to know input args

Logs about failed ajax requests

Usually produces errors that are less tested (aka happy testing)

See how the application looked at the time of crash

?

Know what the user did during page session

🎥

What if there was a tool that did all this…?

🤔😀

Introducing the new shiny…

Detailed data about users environment

Capturing arguments passed to the crashing function

Screenshot at the time of the error

Support for hiding sensitive data before screenshot

+ environment data collectedMany things to consider…

• OS

• Browser

• Window size

• Touch support

• Window blur/focus events

• Date + Timezone

• Language

• Failed ajax requests

• Cookie state

• Network connectivity events

Timeline visualising activityShows ajax requests, window resizing, hide/show, connectivity

Notifying the developers

Notifying the affected user

• Optional popup for the user that triggered the error

• Shows status of the error (New, Reproduced, Fixed)

Two way communication

Error data posted

Current error status [new/reproduced/fixed]

Users / QADevelopers

Cuts 99% of communication out

• No need for QA to email devs about crash reports

• No need for devs to notify QA that bug is already fixed

DEMO TIME

Installing the logger in your app

var logger = new Err.ErrorLogger({ recordUserActions : true, maxNbrLogs : 1, logResourceLoadFailures : true, applicationId : ‘your-cool-app‘, version : ‘2.0.0-rc.1’, logAjaxRequests : true, enableScreenshot : true, saveCookies : true, frameworkVersion : Ext.versions.extjs.version });

logger.addTag('ReadOnlyUser', true); logger.addTag('Secret Flag', 'XYZ');

In a dream world we would be able to:

See on the user’s machine when error happens live Reproduce the error on in production Reproduce the error locally

🤔

DEMO TIME

BETA release imminent

Beta testers wanted! mats@bryntum.com

Launch December 2016

Summing up:

Questions?