Slide 1

Slide 1 text

Mats Bryntse Founder, @bryntum Record.Replay.Reproduce Dealing with javascript errors in modern web apps >>

Slide 2

Slide 2 text

Who is Mats Bryntse? • From Stockholm • Working with javascript past 10 years • Founder of Bryntum • Scheduler, Gantt & kanban UI components • Testing tools, logging tools • @bryntum • www.bryntum.com !

Slide 3

Slide 3 text

Error handling 101

Slide 4

Slide 4 text

Javascript error basics • Javascript errors are unhandled exceptions in your code base • Or in the frameworks you use • Doesn’t matter where errors happen, poor user impression • With JS codebases in the size of MBs, cannot ignore error handling + logging • Good news - it’s easy

Slide 5

Slide 5 text

When a web site error happens, you as a dev see…

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

Nothing

Slide 8

Slide 8 text

Two scenarios for the end user: • Error is captured by you. User notified • Or…… • Nothing happens for user, will probably try same action again. • If you’re lucky, user will contact you ✉ ✊

Slide 9

Slide 9 text

Live demo of an error

Slide 10

Slide 10 text

What is a javascript Error?

Slide 11

Slide 11 text

The ErrorEvent constructor • When an error happens, an ´error´ event is fired on the window object • ErrorEvent.message • ErrorEvent.filename • ErrorEvent.lineno • ErrorEvent.colno // Normal browsers only • ErrorEvent.error // Contains stack. Normal browsers only

Slide 12

Slide 12 text

Global error handler // Old school window.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’ event. Listen with capture=true to also get notified of resource load errors Errors are easily caught in window.onerror

Slide 13

Slide 13 text

You can throw your own Errors too // Bad, no call stack will be available throw ‘My own error’; // preferred throw new Error(‘This will have a call stack’); try { // Code written after drinking beer goes here } catch(e) { // Oops, log error } finally { // always called } • throw a String • Or better, an Error instance (=> callstack) • try/catch/finally

Slide 14

Slide 14 text

Script error. • For errors originating in foreign origin scripts • No stack, no line, no col, no error message. Nothing. Nada. Nichts. • Solution - add a crossOrigin attribute to external script tags • And add a CORS header: Access-Control-Allow-Origin: * 
 
 window.onerror = function (message, url, line, column, error) {
 console.log(message); // Script error if you forget crossOrigin.
 }


Slide 15

Slide 15 text

Developer vs Bugs

Slide 16

Slide 16 text

Bug life cycle Fix Occurrence ℹ Investigate Reproduce Report ✅

Slide 17

Slide 17 text

Developers need to be “in context” to fix a bug

Slide 18

Slide 18 text

Debug context wish list 1. Error message 2. File / line number 3. Call stack 4. Screenshot 5. Step by step description 6. Log of user / browser session activity 7. Seeing the user reproduce the error 8. Live breakpoint in production environment 9. Live breakpoint on my localhost, in my fav browser

Slide 19

Slide 19 text

Once you have breakpoint, it’s all downhill!

Slide 20

Slide 20 text

Error at Object.module.exports.request (/home/vagrant/src/kumascript/lib/kumascript/caching.js:366:17) at attempt (/home/vagrant/src/kumascript/lib/kumascript/loaders.js:180:24) at ks_utils.Class.get (/home/vagrant/src/kumascript/lib/kumascript/loaders.js:194:9) at /home/vagrant/src/kumascript/lib/kumascript/macros.js:282:24 at /home/vagrant/src/kumascript/node_modules/async/lib/async.js:118:13 at Array.forEach (native) at _each (/home/vagrant/src/kumascript/node_modules/async/lib/async.js:39:24) at Object.async.each (/home/vagrant/src/kumascript/node_modules/async/lib/async.js:117:9) at ks_utils.Class.reloadTemplates (/home/vagrant/src/kumascript/lib/kumascript/macros.js:281:19) at ks_utils.Class.process (/home/vagrant/src/kumascript/lib/kumascript/macros.js:217:15) “A live breakpoint is worth a 1000 callstacks”

Slide 21

Slide 21 text

Common approaches to error handling

Slide 22

Slide 22 text

• Pros: Cheap • Cons: Bugs live forever Do nothing

Slide 23

Slide 23 text

Email ping pong

Slide 24

Slide 24 text

Email ping pong - Enterprise version Error in web app Reports to own support Your company User realises it’s an error 01010 10110 11110 User Dear User, /Depressed dev. Can’t reproduce, need more info. Sincerely yours,

Slide 25

Slide 25 text

• Pros: None • Cons: Slow, expensive, demoralizing, frustrated end user

Slide 26

Slide 26 text

Roll your own logger

Slide 27

Slide 27 text

Roll your own logger • Pros: Simple, get basic error info. Awareness • Cons: Lots of code to scan through

Slide 28

Slide 28 text

Using a 3rd party logger • Pros: Tons of data, call stack, console logs, ajax, user activity. Enables you to search for the error • Cons: Slow, tons of data to parse, manual work, code to review

Slide 29

Slide 29 text

Quick poll

Slide 30

Slide 30 text

Making an error logger in < 10 minutes

Slide 31

Slide 31 text

1. Create single table db • date, message, file, line, callstack etc CREATE TABLE `error` ( `msg` char(60), `callstack` char(1000), … ) ENGINE=InnoDB DEFAULT CHARSET=utf8

Slide 32

Slide 32 text

2. PHP script to receive error data and store it in DB

Slide 33

Slide 33 text

3. Setup client side logging • Log message, file, line, stack etc.. • Add any extra meta relevant for your debugging (userId/name/…) // Poor mans error logger window.onerror = function log(msg) { new Image().src = "log.php?msg=" + encodeURIComponent(msg); } throw new Error("Ooops");

Slide 34

Slide 34 text

Manual error logging, things to consider • Store error logs in a database on a non-production server • Throttle logging on client side + server side • Probably we only care about the first error on a page

Slide 35

Slide 35 text

Bryntum - How we (used to) handle errors

Slide 36

Slide 36 text

Online examples is a test suite of sorts

Slide 37

Slide 37 text

Previous error handling at Bryntum • Web site visitors are test monkeys unknowingly === free help • Errors logged in a DB • Emails sent to devs = At best, useful for finding simple bugs

Slide 38

Slide 38 text

Error handling at Bryntum Instant feedback Site visitors / “Late QA” Developers

Slide 39

Slide 39 text

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… ,

Slide 40

Slide 40 text

Wish list…

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

Logs about failed ajax requests Usually produces errors that are less tested (aka happy testing)

Slide 43

Slide 43 text

See how the application looked at the time of crash ?

Slide 44

Slide 44 text

Know what the user did during page session

Slide 45

Slide 45 text

Ability to replay the user session

Slide 46

Slide 46 text

RootCause - debugging javascript errors in 2017

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

Callstack, browser, user environment info

Slide 49

Slide 49 text

Capturing function arguments

Slide 50

Slide 50 text

Screenshot at the time of the error

Slide 51

Slide 51 text

Hiding sensitive data before screenshot

Slide 52

Slide 52 text

+ environment data collected Many things to consider… • OS • Browser • Window size • Touch support • Window blur/focus events • Date + Timezone • Language • Failed ajax requests • Cookie state • Network connectivity events

Slide 53

Slide 53 text

Timeline visualising activity

Slide 54

Slide 54 text

Notifying the developers

Slide 55

Slide 55 text

Notifying the affected user • Optional popup for the user that triggered the error • Shows status of the error (New, Reproduced, Fixed)

Slide 56

Slide 56 text

Cuts 99% of communication out • No need for QA / end users to email devs with crash reports, step by step • No need for devs to notify QA that bug is fixed

Slide 57

Slide 57 text

Two way communication Error data posted Current error status [new/reproduced/fixed] Users / QA Developers

Slide 58

Slide 58 text

Opt in dialog before logging

Slide 59

Slide 59 text

Feedback button for “soft” errors

Slide 60

Slide 60 text

Installing the logger in your web app window.logger = new RC.Logger({
 applicationId : 'yourToken',
 recordUserActions : true,
 showFeedbackButton : true,
 logAjaxRequests : true,
 captureScreenshot : true,
 environment : 'prod',
 user : {
 email : '[email protected]',
 name : 'Anton'
 }
 });


Slide 61

Slide 61 text

DEMO TIME!

Slide 62

Slide 62 text

Technical details • Recorder: 100% vanilla JS • Screenshots: HTML2Canvas • Dashboard: Ext JS • Replay studio powered by Siesta

Slide 63

Slide 63 text

>> Fast forward into context Fix Occurrence ℹ Investigate Reproduce Report ✅

Slide 64

Slide 64 text

No content

Slide 65

Slide 65 text

Privacy concerns..?

Slide 66

Slide 66 text

No content

Slide 67

Slide 67 text

BETA open at http://app.therootcause.io Summing up: • Fix your external script tags. Never see “Script error”. Ever. • Don’t rely on users reporting bugs • Choose an automated error reporting tool (invite code r2d2)

Slide 68

Slide 68 text

Breakpoint or GTFO @bryntum Questions?