Sentry-javascript: Automatically log all thrown errors?

Created on 10 Feb 2013  ·  31Comments  ·  Source: getsentry/sentry-javascript

Is there a way to get Raven to log all thrown errors? For some reason, it logs some throw calls but not others. I found that it tends to not log behavior that is nested further down the call stack.

Most helpful comment

Here you go:

var __hasProp = {}.hasOwnProperty,
  __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

window.Error = (function(_super) {

  __extends(_Class, _super);

  function _Class() {
    var error;
    error = _Class.__super__.constructor.apply(this, arguments);
    Raven.captureException(error);
    return error;
  }

  return _Class;

})(Error);

All 31 comments

haha, error handling in Javascript is really terrible. Can you provide me an example of how you're throwing the errors?

For example, throwing a string doesn't allow us to get any information except the message that was sent. With an actual Error object, we can (attempt) to get a stack.

So the more information, the better for this.

Indeed.

I am throwing an error like so:

throw new Error("Error");

Sometimes it logs in sentry and sometimes it doesn't.

Is this on a page that I can take a look at somewhere? Or can you put it somewhere? Honestly, that's just not enough information. There are about 10 factors that can go into why an error doesn't get logged, and most of them are out of our hands. :) So if I can see the full context, I can give you a suggestion to help the browser out.

The app is actually written in CoffeeScript that gets compiled to JavaScript using require.js. The main entry point looks like so:

Raven.config('http://[email protected]');
Raven.context(function() {
  define(['cs!csmain']);
});

I've tried without the context wrapper as well and that didn't seem to change anything. It still logged throw calls that were made higher up in the call stack while ignoring those down below.

Are you running Raven.install()

And for require.js, if you explicitly wanted to wrap modules, you'd do:

define(['module'], Raven.wrap(function(module) {
  // insert cool stuff here
}));

I forgot it in the snippet, but I am calling install() after config()

I have not tried wrapping around modules, but I figured if it already works in some places, why not in others?

It all depends really on the callstack. When things start going into async land, it gets rough. For example, this would not do as expected:

Raven.context(function() {
  setTimeout(function() {
    throw new Error('crap');
  }, 1);
});

The internal function gets run in it's own context outside of the main context. Node.js solves this with a thing called "domains", but sadly, those don't exist in browser land.

So if an error is uncaught and bubbles all the way to the top, it usually gets rejected because it's 100% worthless at that point.

Ah, I see. Perhaps there's a way to utilize window.onerror?

FWIW, if possible, the most confident way of capturing an exception is to explicitly use Raven.captureException. I understand that that's not always feasible, but just an FYI.

So an explicit try...except block is the mos reliable:

try {
  throw new Error('something');
} catch(e) {
  Raven.captureException(e);
}

Right. Of course it would be great to automatically capture errors, but JavaScript doesn't make it an easy game to play...

@pheuter Nope. :) And that's the fun part. Once an error gets to window.onerror, it's not an actual Error object anymore. It flattens down to just a useless string. And it also imposes cross domain security issues. So basically, once an error hits window.onerror, it's usually discarded since the only information we have may only be: "Script error.".

Sucks. Oh well, I appreciate the clarification!

No, Javascript does not. It's really terrible, in fact. :) I'm actively researching and exploring ways to exploit the browser to giving us better information. The idea has even crossed my mind to monkey patch Function.prototype.call. But that's probably really bad news.

Totally! If you have any recommendations or suggestions to clarify documentation, please let me know. I'm always looking for that stuff.

Will do, the configuration and usage docs have been pretty straightforward and easy to follow.

I wonder if there's a way to extend Error to make this work.

@mattrobenolt, this is the approach we're taking using CoffeeScript.

window.Error = class extends Error
  constructor: ->
    error = super
    Raven.captureException error
    return error

Then just use throw new Error "Test Error"

Updated comment above for clarification.

Hmm. I'll play with this over the weekend. Last I tried, it wouldn't let me patch over window.Error. I'll try again in more browsers and see what's possible.

Thanks for the headsup!

Also, can you give me that in normal Javascript? I'm pretty sure what it's doing, I just want to double check. I don't write Coffeescript.

Here you go:

var __hasProp = {}.hasOwnProperty,
  __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

window.Error = (function(_super) {

  __extends(_Class, _super);

  function _Class() {
    var error;
    error = _Class.__super__.constructor.apply(this, arguments);
    Raven.captureException(error);
    return error;
  }

  return _Class;

})(Error);

Now that I think about it, this is a flawed approach. Just overriding the constructor is going to cause Raven to capture every error object, whether it's thrown or not. :)

FYI, errorception found a way to handle this. Would be cool if raven-js could do the same.

@dmcquay Can you provide an example that Errorception captures? I can probably reverse engineer it.

I actually assume that all JS error handlers are 50% raven.js ;)

:poop:

@BYK, any ideas?

I don't have any inside knowledge about errorception. I am using the service and it seems to work as advertised. That's all I know.

I inspected how they work and it looks like they simply attach themselves to window.onerror and don't care about the stack trace. At least for these kind of things.

Hijacking the Error object works for Firefox but @mattrobenolt's point about capturing all of them, even the ones that are not thrown is a valid concern.

A dirty workaround for this might be storing created Error instances by hijacking the global constructor and also listen to onerror and compare the message, fileName and lineNo arguments with the properties of the stored Error objects. If a match is found, remove that from the queue and report.

While evaluating all error-notification services, I noticed that some Javascript-specific services (such as https://qbaka.com/) do track the stack trace and display the user action that led to a particular error. Too bad errorception doesn't do that since it seems superior in every other way.

We'll be using Sentry for our Django code, and I stumbled upon this issue while looking for info on how Sentry works for Javascript. Does the current implementation of raven-js require the code to explicitly catch all JS errors and report them to Sentry?

@adityar7 It does not. Raven.js tries it's best to monkey patch and intercept things if it can. In some more edge cases, you may need to wrap explicitly, but we try real hard to make things happen automatically.

@mattrobenolt Got it working by fixing some syntax. Thanks!

Was this page helpful?
0 / 5 - 0 ratings