diff --git a/README.md b/README.md index 2010157..69eabf2 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ module.exports = function(environment/*, appConfig */) { raygun: { apiKey: 'APP_API_KEY_HERE', enabled: true, - enableCrashReporting: true, + enableCrashReporting: false, enableUserTracking: true, enablePulse: true, saveIfOffline: true, @@ -55,7 +55,7 @@ user id, with anonymous id or an actual user id provided after login. The config for a development build uses environment variables. -- `export RAYGUN_ENABLED=true; export RAYGUN_CRASH_REPORTING=true; export RAYGUN_USER_TRACKING=true; export RAYGUN_API_KEY='X'; ember s` +- `export RAYGUN_ENABLED=true; export RAYGUN_CRASH_REPORTING=false; export RAYGUN_USER_TRACKING=true; export RAYGUN_API_KEY='X'; ember s` - visit On Windows you can use PowerShell to set an environment variable, `$env:RAYGUN_ENABLED="true"` @@ -81,12 +81,15 @@ export default function raygunErrorFilter(error) { ``` If the utility function returns the error passed in, then it will be reported. +To ensure the filter function is used with `window.onerror` (uncaught errors) +set the config value for `enableCrashReporting` to `false`. A `true` setting +would use Raygun's automatic setup for `winodow.onerror`, which doesn't filter. See the dummy app example, [utils/raygun-error-filter](tests/dummy/app/utils/raygun-error-filter.js). -Crash reporting is generated through `Ember.onerror`, `RSVP.on('error', () => {})`, -and `Ember.Logger.error`. When your application's config enables Raygun -Crash reporting, this behavior is setup using an instance initializer. +Crash reporting is generated through `Ember.onerror`, `RSVP.on('error', () => {})`, +`Ember.Logger.error`, and `window.onerror`. When your application's config enables +Raygun Crash reporting, this behavior is setup using an instance initializer. If you would like to define how your app reports runtime errors to Raygun, then you may generate your own instance initializer. diff --git a/addon/instance-initializers/raygun.js b/addon/instance-initializers/raygun.js index 71286ca..ece448f 100644 --- a/addon/instance-initializers/raygun.js +++ b/addon/instance-initializers/raygun.js @@ -12,6 +12,9 @@ export function initialize(appInstance) { setupEmberOnError(filter); setupRSVPOnError(filter); setupErrorLogger(filter); + if (!isTruthy(config.raygun.enableCrashReporting)) { + setupWindowOnError(filter); + } } } @@ -24,6 +27,16 @@ function isEnabled(config) { return config && config.apiKey && isTruthy(config.enabled); } +function setupWindowOnError(filter) { + let handler = 'window.onerror'; + // See https://github.com/MindscapeHQ/raygun4js#usage + window.onerror = function(error) { + if (filter(error)) { + sendToRayGun(error, handler); + } + } +} + function setupEmberOnError(filter) { let handler = 'Ember.onerror'; // https://guides.emberjs.com/v2.11.0/configuring-ember/debugging/#toc_implement-an-ember-onerror-hook-to-log-all-errors-in-production diff --git a/tests/unit/instance-initializers/raygun-test.js b/tests/unit/instance-initializers/raygun-test.js index c0b5682..24e2661 100644 --- a/tests/unit/instance-initializers/raygun-test.js +++ b/tests/unit/instance-initializers/raygun-test.js @@ -16,11 +16,13 @@ module('Unit | Instance Initializer | raygun', { setupRg4jsStub.call(this); setupFilter.call(this); Ember.onerror = undefined; + this.ogOnerror = window.onerror; adapterException = Ember.Test.adapter.exception; Ember.Test.adapter.exception = () => null; }, afterEach() { Ember.Test.adapter.exception = adapterException; + window.onerror = this.ogOnerror; Ember.onerror = undefined; teardownRg4jsStub.call(this); teardownFilter.call(this); @@ -29,12 +31,33 @@ module('Unit | Instance Initializer | raygun', { } }); +test('it sets up raygun error handling with a filter to use window.onerror', function(assert) { + enableRaygun.call(this); + + initialize(this.appInstance); + // sinon cannot spy/stub window.onerror + const currentOnerror = window.onerror; + let onErrorSpyCalled = false; + window.onerror = (err) => { + onErrorSpyCalled = true; + currentOnerror(err); + }; + const error = new Error('window.onerror test'); + window.onerror(error); + assert.ok(onErrorSpyCalled); + assert.ok(this.filterSpy.calledOnce); + assert.ok(this.rg4jsStub.calledOnce); + assert.ok(this.rg4jsStub.calledWith('send')); + assert.equal(this.rg4jsStub.firstCall.args[1].error, error); + window.onerror = currentOnerror; +}); + test('it sets up raygun error handling with a filter to use Ember.onerror', function(assert) { enableRaygun.call(this); initialize(this.appInstance); - const error = new Error('onerror test'); + const error = new Error('Ember.onerror test'); Ember.onerror(error); assert.ok(this.filterSpy.calledOnce); assert.ok(this.rg4jsStub.calledOnce); @@ -119,11 +142,12 @@ test('when disabled RSVP.reject does not send error to raygun', function(assert) }); }); -function enableRaygun(enabled = true) { +function enableRaygun(enabled = true, autoWindowOnerror = false) { this.appInstance.register('config:environment', { raygun: { enabled: enabled, apiKey: 'secret', + enableCrashReporting: autoWindowOnerror } }); } @@ -145,3 +169,4 @@ function teardownRg4jsStub() { this.rg4jsStub.restore(); delete this.rg4jsStub; } +