diff --git a/CHANGELOG.md b/CHANGELOG.md index bae62c77f..d0b706123 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ - Added support for error reporting of "falsey" errors such as `null`, `NaN`, `undefined`, `false`, `""` ([#1345](https://github.com/airbrake/airbrake-js/pull/1345)) +- Added the `instrumentation.unhandledrejection` option, which enables/disables + the Airbrake handler for the `unhandledrejection` event + ([#1356](https://github.com/airbrake/airbrake-js/pull/1356)) ### [2.1.8] (December 6, 2022) diff --git a/packages/browser/README.md b/packages/browser/README.md index fb780b045..548f0da36 100644 --- a/packages/browser/README.md +++ b/packages/browser/README.md @@ -310,6 +310,21 @@ const airbrake = new Notifier({ }); ``` +#### unhandledrejection + +Instruments the [unhandledrejection][unhandledrejection] event and sends +performance statistics to Airbrake. You can disable that behavior using the +`instrumentation` option: + +```js +const airbrake = new Notifier({ + // ... + instrumentation: { + unhandledrejection: false, + }, +}); +``` + ### APM #### Routes @@ -372,3 +387,4 @@ this.airbrake.queues.notify(queueInfo); [fetch]: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch [onerror]: https://developer.mozilla.org/en-US/docs/Web/API/Window/error_event [xhr]: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest +[unhandledrejection]: https://developer.mozilla.org/en-US/docs/Web/API/Window/unhandledrejection_event diff --git a/packages/browser/src/instrumentation/unhandledrejection.ts b/packages/browser/src/instrumentation/unhandledrejection.ts new file mode 100644 index 000000000..24b9e20f0 --- /dev/null +++ b/packages/browser/src/instrumentation/unhandledrejection.ts @@ -0,0 +1,33 @@ +import { Notifier } from '../notifier'; + +export function instrumentUnhandledrejection(notifier: Notifier): void { + const handler = onUnhandledrejection.bind(notifier); + + window.addEventListener('unhandledrejection', handler); + notifier._onClose.push(() => { + window.removeEventListener('unhandledrejection', handler); + }); +} + +function onUnhandledrejection(e: any): void { + // Handle native or bluebird Promise rejections + // https://developer.mozilla.org/en-US/docs/Web/Events/unhandledrejection + // http://bluebirdjs.com/docs/api/error-management-configuration.html + let reason = e.reason || (e.detail && e.detail.reason); + if (!reason) return; + + let msg = reason.message || String(reason); + if (msg.indexOf && msg.indexOf('airbrake: ') === 0) return; + + if (typeof reason !== 'object' || reason.error === undefined) { + this.notify({ + error: reason, + context: { + unhandledRejection: true, + }, + }); + return; + } + + this.notify({ ...reason, context: { unhandledRejection: true } }); +} diff --git a/packages/browser/src/notifier.ts b/packages/browser/src/notifier.ts index 5a75df017..b482af691 100644 --- a/packages/browser/src/notifier.ts +++ b/packages/browser/src/notifier.ts @@ -6,6 +6,7 @@ import { instrumentDOM } from './instrumentation/dom'; import { instrumentFetch } from './instrumentation/fetch'; import { instrumentLocation } from './instrumentation/location'; import { instrumentXHR } from './instrumentation/xhr'; +import { instrumentUnhandledrejection } from './instrumentation/unhandledrejection'; import { INotice } from './notice'; import { IInstrumentationOptions, IOptions } from './options'; @@ -37,16 +38,9 @@ export class Notifier extends BaseNotifier { this.onOffline = this.onOffline.bind(this); window.addEventListener('offline', this.onOffline); - this.onUnhandledrejection = this.onUnhandledrejection.bind(this); - window.addEventListener('unhandledrejection', this.onUnhandledrejection); - this._onClose.push(() => { window.removeEventListener('online', this.onOnline); window.removeEventListener('offline', this.onOffline); - window.removeEventListener( - 'unhandledrejection', - this.onUnhandledrejection - ); }); } @@ -83,6 +77,12 @@ export class Notifier extends BaseNotifier { if (enabled(opt.xhr) && typeof XMLHttpRequest !== 'undefined') { instrumentXHR(this); } + if ( + enabled(opt.unhandledrejection) && + typeof addEventListener === 'function' + ) { + instrumentUnhandledrejection(this); + } } public notify(err: any): Promise { @@ -123,35 +123,6 @@ export class Notifier extends BaseNotifier { this.offline = true; } - protected onUnhandledrejection(e: any): void { - // Handle native or bluebird Promise rejections - // https://developer.mozilla.org/en-US/docs/Web/Events/unhandledrejection - // http://bluebirdjs.com/docs/api/error-management-configuration.html - let reason = e.reason || (e.detail && e.detail.reason); - if (!reason) { - return; - } - let msg = reason.message || String(reason); - if (msg.indexOf && msg.indexOf('airbrake: ') === 0) { - return; - } - if (typeof reason !== 'object' || reason.error === undefined) { - this.notify({ - error: reason, - context: { - unhandledRejection: true, - }, - }); - return; - } - this.notify({ - ...reason, - context: { - unhandledRejection: true, - }, - }); - } - onerror( message: string, filename?: string, diff --git a/packages/browser/src/options.ts b/packages/browser/src/options.ts index 1717e9b6f..464ab4b87 100644 --- a/packages/browser/src/options.ts +++ b/packages/browser/src/options.ts @@ -11,6 +11,7 @@ export interface IInstrumentationOptions { history?: boolean; console?: boolean; xhr?: boolean; + unhandledrejection?: boolean; } export interface IOptions {