Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically log all thrown errors? #67

Closed
pheuter opened this issue Feb 10, 2013 · 31 comments
Closed

Automatically log all thrown errors? #67

pheuter opened this issue Feb 10, 2013 · 31 comments

Comments

@pheuter
Copy link

pheuter commented Feb 10, 2013

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.

@mattrobenolt
Copy link
Contributor

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.

@pheuter
Copy link
Author

pheuter commented Feb 10, 2013

Indeed.

I am throwing an error like so:

throw new Error("Error");

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

@mattrobenolt
Copy link
Contributor

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.

@pheuter
Copy link
Author

pheuter commented Feb 10, 2013

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://key@url.com');
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.

@mattrobenolt
Copy link
Contributor

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
}));

@pheuter
Copy link
Author

pheuter commented Feb 10, 2013

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?

@mattrobenolt
Copy link
Contributor

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.

@pheuter
Copy link
Author

pheuter commented Feb 10, 2013

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

@mattrobenolt
Copy link
Contributor

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);
}

@pheuter
Copy link
Author

pheuter commented Feb 10, 2013

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

@mattrobenolt
Copy link
Contributor

@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.".

@pheuter
Copy link
Author

pheuter commented Feb 10, 2013

Sucks. Oh well, I appreciate the clarification!

@mattrobenolt
Copy link
Contributor

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.

@mattrobenolt
Copy link
Contributor

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

@pheuter
Copy link
Author

pheuter commented Feb 10, 2013

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

@pheuter pheuter closed this as completed Feb 10, 2013
@paulyoung
Copy link

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

@paulyoung
Copy link

@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"

@paulyoung
Copy link

Updated comment above for clarification.

@mattrobenolt
Copy link
Contributor

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.

@paulyoung
Copy link

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);

@mattrobenolt
Copy link
Contributor

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. :)

@dmcquay
Copy link

dmcquay commented Aug 22, 2013

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

@mattrobenolt
Copy link
Contributor

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

@dcramer
Copy link
Member

dcramer commented Aug 22, 2013

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

@mattrobenolt
Copy link
Contributor

💩

@mattrobenolt
Copy link
Contributor

@BYK, any ideas?

@dmcquay
Copy link

dmcquay commented Aug 22, 2013

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.

@BYK
Copy link
Contributor

BYK commented Aug 25, 2013

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.

@adityar7
Copy link

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?

@mattrobenolt
Copy link
Contributor

@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.

@adityar7
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants