From 8af769934f06be821b6eb5a9d687d661c4faff3a Mon Sep 17 00:00:00 2001 From: James Berry <69924001+jlalmes@users.noreply.github.com> Date: Wed, 1 Apr 2026 12:00:00 +0800 Subject: [PATCH] [console-plugin] Feat: Record `unhandledrejection` event (#1104) * feat/console-plugin/add-unhandledrejection-handler * better error * change the window object to the passed in 'win' * empty * improve serialized error messages --------- Co-authored-by: Yun Feng --- .../rrweb/src/plugins/console/record/index.ts | 65 ++++++++++++++----- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/packages/rrweb/src/plugins/console/record/index.ts b/packages/rrweb/src/plugins/console/record/index.ts index 47cd5136..221292c4 100644 --- a/packages/rrweb/src/plugins/console/record/index.ts +++ b/packages/rrweb/src/plugins/console/record/index.ts @@ -114,25 +114,54 @@ function initLogObserver( const cancelHandlers: listenerHandler[] = []; // add listener to thrown errors if (logOptions.level.includes('error')) { - if (window) { - const errorHandler = (event: ErrorEvent) => { - const message = event.message, - error = event.error as Error; - const trace: string[] = ErrorStackParser.parse( - error, - ).map((stackFrame: StackFrame) => stackFrame.toString()); - const payload = [stringify(message, logOptions.stringifyOptions)]; - cb({ - level: 'error', - trace, - payload, - }); - }; - window.addEventListener('error', errorHandler); - cancelHandlers.push(() => { - if (window) window.removeEventListener('error', errorHandler); + const errorHandler = (event: ErrorEvent) => { + const message = event.message, + error = event.error as Error; + const trace: string[] = ErrorStackParser.parse( + error, + ).map((stackFrame: StackFrame) => stackFrame.toString()); + const payload = [stringify(message, logOptions.stringifyOptions)]; + cb({ + level: 'error', + trace, + payload, }); - } + }; + win.addEventListener('error', errorHandler); + cancelHandlers.push(() => { + win.removeEventListener('error', errorHandler); + }); + const unhandledrejectionHandler = (event: PromiseRejectionEvent) => { + let error: Error; + let payload: string[]; + if (event.reason instanceof Error) { + error = event.reason; + payload = [ + stringify( + `Uncaught (in promise) ${error.name}: ${error.message}`, + logOptions.stringifyOptions, + ), + ]; + } else { + error = new Error(); + payload = [ + stringify('Uncaught (in promise)', logOptions.stringifyOptions), + stringify(event.reason, logOptions.stringifyOptions), + ]; + } + const trace: string[] = ErrorStackParser.parse( + error, + ).map((stackFrame: StackFrame) => stackFrame.toString()); + cb({ + level: 'error', + trace, + payload, + }); + }; + win.addEventListener('unhandledrejection', unhandledrejectionHandler); + cancelHandlers.push(() => { + win.removeEventListener('unhandledrejection', unhandledrejectionHandler); + }); } for (const levelType of logOptions.level) { cancelHandlers.push(replace(logger, levelType));