A Journey into 

Client Side Errors

Arunoda Susiripala

 

MeteorHacks

Kadira.io

Overview

How we debug errors locally 
(Dev Mode)

How we can track errors in Production

Some Better Options

Our Demo App

Code

Template.simple.events({
    "click button": function() {
        fetchFromServer("getSomeTweets", displayTweets);
    }
});

function displayTweets(err, date) {
    console.log(data.tweets);
}

Let's Debug Our Error

Async Errors

Template.without_async.events({
    "click button": function() {
        throw new Error("oops. something went wrong");
    }
});
Template.with_async.events({
    "click button": function() {
        setTimeout(function() {
          throw new Error("oops. something went wrong");
        }, 100);
    }
});

Minified Code

Source Maps

Our App in Production

On Users Browser

We can't Debug It

User is your Grandma

 

(Code is not minified yet)

function ReportError(type, data) {
    console.log("A new Error of type: " + type);
    console.log(data);
}

window.onerror

Code

Template.window_onerror.events({
    "click button": function() {
        fetchFromServer("getSomeTweets", displayTweets);
    }
});

function displayTweets(err, date) {
    console.log(data.tweets);
}

window.onerror = function() {
  ReportError("window.onerror", arguments);
};

Result: Chrome

Result: Firefox

Result: Safari

Tracking Error Manually

Template.trycatch1.events({
    "click button": function() {
        try {
          throw new Error("oops. something went wrong");
        } catch(ex) {
          ReportError("trycatch1", ex);
        }
    }
});
Template.trycatch2.events({
    "click button": function() {
        try {
          setTimeout(function() {
            throw new Error("oops. something went wrong");
          }, 100);
        } catch(ex) {
          ReportError("trycatch2", ex);
        }
    }
});

Different StackTrace Formats

Result: Chrome

Result: FireFox

Result: IE

Result: Safari

Solution

No Async Stacks

Issues

window.onerror is limited

tracking errors manually is hard

no async stacks

Enter: Zone.JS

It's a Execution Context

Zone.JS Demo Time

var reporter = {
  onError: function(ex) {
    console.log(ex);
  }
};

zone.fork(reporter).run(function() {
  throw new Error('oops something goes wrong');
});

Async Errors

var reporter = {
  onError: function(ex) {
    console.log(ex);
  }
};

zone.fork(reporter).run(function() {
  setTimeout(function() {
    throw new Error('oops something goes wrong inside setTimeout');
  }, 1000);
});

Long StackTraces

zone.fork(Zone.longStackTraceZone);

Template.with_async.events({
    "click button": function() {
        setTimeout(function() {
          throw new Error("oops. something went wrong");
        }, 100);
    }
});

Zone.JS with Minified Code

zone.fork(Zone.longStackTraceZone);

Template.with_async.events({
    "click button": function() {
        setTimeout(function() {
          throw new Error("oops. something went wrong");
        }, 100);
    }
});

Let's Think Differently!

To Fix an Error?

We need context

Set of Actions Occured

Error Message

How We Did It?

Extending Zones

var originalMeteorCall = Meteor.call;

Meteor.call = function(methodName) {
    var args = Array.prototype.slice.call(arguments, 1);
    zone.addAction("Meteor.call", {
        method: methodName,
        args: args
    }};

    originalMeteorCall.apply(this, arguments);
}

Nothing is Free

try {
  this.beforeTask();
  result = fn.apply(applyTo, applyWith);
} catch (e) {
  if (zone.onError) {
    zone.onError(e);
  } else {
    throw e;
  }
} finally {
  this.afterTask();
  window.zone = oldZone;
}

Thank You!

A Tour on Client Side Errors

By arunoda

A Tour on Client Side Errors

  • 1,842