|
1 | 1 | import { |
2 | 2 | ExceptionlessClient, |
3 | 3 | IEventPlugin, |
4 | | - PluginContext |
| 4 | + PluginContext, |
| 5 | + nameof |
5 | 6 | } from "@exceptionless/core"; |
6 | 7 |
|
7 | 8 | export class GlobalHandlerPlugin implements IEventPlugin { |
8 | 9 | public priority: number = 100; |
9 | 10 | public name: string = "GlobalHandlerPlugin"; |
10 | 11 |
|
11 | | - private client: ExceptionlessClient = null; |
| 12 | + private _client: ExceptionlessClient = null; |
12 | 13 |
|
13 | 14 | public startup(context: PluginContext): Promise<void> { |
14 | | - if (this.client) { |
| 15 | + if (this._client) { |
15 | 16 | return; |
16 | 17 | } |
17 | 18 |
|
18 | | - this.client = context.client; |
| 19 | + this._client = context.client; |
19 | 20 | Error.stackTraceLimit = Infinity; |
20 | 21 |
|
21 | 22 | // TODO: Discus if we want to unwire this handler in suspend? |
22 | 23 | const originalOnError: OnErrorEventHandlerNonNull = globalThis.onerror; |
23 | | - globalThis.onerror = (event: Event | string, source?: string, lineno?: number, colno?: number, error?: Error): any => { |
24 | | - /* |
25 | | - const builder = this.client.createUnhandledException(new Error(stackTrace.message || (options || {}).status || "Script error"), "onerror"); |
26 | | - builder.pluginContextData["@@_TraceKit.StackTrace"] = stackTrace; |
27 | | - void builder.submit(); // TODO: Handle async? |
28 | | - */ |
| 24 | + globalThis.onerror = (event: Event | string, source?: string, lineno?: number, colno?: number, error?: Error) => { |
| 25 | + // TODO: Handle async |
| 26 | + void this._client.submitUnhandledException(error || this.buildError(event, source, lineno, colno), nameof<Window>("onerror")); |
29 | 27 |
|
30 | 28 | // eslint-disable-next-line prefer-rest-params |
31 | 29 | return originalOnError ? originalOnError.apply(this, ...arguments) : false; |
32 | 30 | }; |
33 | 31 |
|
| 32 | + const originalOnunhandledrejection = globalThis.onunhandledrejection; |
| 33 | + globalThis.onunhandledrejection = (pre: PromiseRejectionEvent) => { |
| 34 | + let error = pre.reason; |
| 35 | + try { |
| 36 | + const reason = (<any>pre).detail?.reason; |
| 37 | + if (reason) { |
| 38 | + error = reason; |
| 39 | + } |
| 40 | + // eslint-disable-next-line no-empty |
| 41 | + } catch (ex) { } |
| 42 | + |
| 43 | + // TODO: Handle async |
| 44 | + void this._client.submitUnhandledException(error, nameof<Window>("onunhandledrejection")); |
| 45 | + |
| 46 | + // eslint-disable-next-line prefer-rest-params |
| 47 | + return originalOnunhandledrejection ? originalOnunhandledrejection.apply(this, ...arguments) : false; |
| 48 | + }; |
| 49 | + |
34 | 50 | return Promise.resolve(); |
35 | 51 | } |
| 52 | + |
| 53 | + private buildError(event: Event | string, source?: string, lineno?: number, colno?: number): Error { |
| 54 | + let name: string = "Error"; |
| 55 | + let message: string = Object.prototype.toString.call(event) === '[object ErrorEvent]' ? (<ErrorEvent>event).message : null; |
| 56 | + if (message) { |
| 57 | + const errorNameRegex: RegExp = /^(?:[Uu]ncaught (?:exception: )?)?(?:((?:Aggregate|Eval|Internal|Range|Reference|Syntax|Type|URI|)Error): )?(.*)$)/i; |
| 58 | + const [_, errorName, errorMessage] = errorNameRegex.exec(message); |
| 59 | + if (errorName) { |
| 60 | + name = errorName; |
| 61 | + } |
| 62 | + if (errorMessage) { |
| 63 | + message = errorMessage; |
| 64 | + } |
| 65 | + } |
| 66 | + |
| 67 | + const error = new Error(message || "Script error"); |
| 68 | + error.name = name; |
| 69 | + error.stack = `at ${source || ""}:${!isNaN(lineno) ? lineno : 0}${!isNaN(colno) ? ":" + colno : ""}`; |
| 70 | + return error; |
| 71 | + } |
36 | 72 | } |
0 commit comments