From 7a136960cc62d911a473a13cae48d331e22373fd Mon Sep 17 00:00:00 2001 From: "Christian W. Damus" Date: Thu, 15 Jun 2023 08:35:18 -0400 Subject: [PATCH] Parameterize the error handling (#13) Extract the error handler that shows the error dialog into the globals where other points of customization are implemented, while maintaining compatibility for contexts such as the traceconv worker that doesn't use the frontend globals. Also add an API to force the error dialog for the case when an external agent needs to show it. --- ui/src/base/logging.ts | 6 ++++-- ui/src/frontend/error_dialog.ts | 6 ++++++ ui/src/frontend/globals.ts | 12 +++++++++++- ui/src/frontend/index.ts | 8 +++----- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/ui/src/base/logging.ts b/ui/src/base/logging.ts index 945d96a983..b44fb2d280 100644 --- a/ui/src/base/logging.ts +++ b/ui/src/base/logging.ts @@ -39,7 +39,9 @@ export function setErrorHandler(handler: ErrorHandler) { errorHandler = handler; } -export function reportError(err: ErrorEvent|PromiseRejectionEvent|{}) { +export function reportError(err: ErrorEvent|PromiseRejectionEvent|{}): void; +export function reportError(err: ErrorEvent|PromiseRejectionEvent|{}, handler: ErrorHandler): void; +export function reportError(err: ErrorEvent|PromiseRejectionEvent|{}, handler = errorHandler) { let errLog = ''; let errorObj = undefined; @@ -62,7 +64,7 @@ export function reportError(err: ErrorEvent|PromiseRejectionEvent|{}) { errLog += `UA: ${navigator.userAgent}\n`; console.error(errLog, err); - errorHandler(errLog); + handler?.(errLog); } // This function serves two purposes. diff --git a/ui/src/frontend/error_dialog.ts b/ui/src/frontend/error_dialog.ts index e3a28a5cff..cd51513b63 100644 --- a/ui/src/frontend/error_dialog.ts +++ b/ui/src/frontend/error_dialog.ts @@ -32,6 +32,12 @@ let timeLastReport = 0; const queuedErrors = new Array(); const ERR_QUEUE_MAX_LEN = 10; +export function showErrorDialog(errLog: string) { + // Force showing the dialog by resetting the last report time + timeLastReport = 0; + maybeShowErrorDialog(errLog); +} + export function maybeShowErrorDialog(errLog: string) { globals.logging.logError(errLog); const now = performance.now(); diff --git a/ui/src/frontend/globals.ts b/ui/src/frontend/globals.ts index cd179ed7e0..50c9c6476d 100644 --- a/ui/src/frontend/globals.ts +++ b/ui/src/frontend/globals.ts @@ -14,7 +14,7 @@ import {BigintMath} from '../base/bigint_math'; import {HttpRcpEngineCustomizer} from '../common/http_rpc_engine'; -import {assertExists} from '../base/logging'; +import {ErrorHandler, assertExists} from '../base/logging'; import {Actions, AddTrackLikeArgs, DeferredAction} from '../common/actions'; import {AggregateData} from '../common/aggregation_data'; import {Args, ArgsTree} from '../common/arg_types'; @@ -45,6 +45,7 @@ import { RafScheduler } from './raf_scheduler'; import { Router } from './router'; import {ServiceWorkerController} from './service_worker_controller'; import {PxSpan, TimeScale} from './time_scale'; +import { maybeShowErrorDialog } from './error_dialog'; type Dispatch = (action: DeferredAction) => void; type TrackDataStore = Map; @@ -265,6 +266,7 @@ class Globals { private _cachePrefix: string = ''; private _viewOpener?: ViewOpener = undefined; + private _errorHandler: ErrorHandler = maybeShowErrorDialog; private _allowFileDrop = true; private _httpRpcEngineCustomizer?: HttpRcpEngineCustomizer; private _promptToLoadFromTraceProcessorShell = true; @@ -641,6 +643,14 @@ class Globals { this._viewOpener = viewOpener; } + get errorHandler(): ErrorHandler { + return this._errorHandler; + } + + set errorHandler(errorHandler: ErrorHandler) { + this._errorHandler = errorHandler; + } + get allowFileDrop(): boolean { return this._allowFileDrop; } diff --git a/ui/src/frontend/index.ts b/ui/src/frontend/index.ts index fad73235ba..aed5f44845 100644 --- a/ui/src/frontend/index.ts +++ b/ui/src/frontend/index.ts @@ -19,7 +19,7 @@ import {Patch, produce} from 'immer'; import m from 'mithril'; import {defer} from '../base/deferred'; -import {assertExists, reportError, setErrorHandler} from '../base/logging'; +import {assertExists, reportError} from '../base/logging'; import {Actions, DeferredAction, StateActions} from '../common/actions'; import {createEmptyState} from '../common/empty_state'; import {RECORDING_V2_FLAG} from '../common/feature_flags'; @@ -36,7 +36,6 @@ import { import {AnalyzePage} from './analyze_page'; import {initCssConstants} from './css_constants'; import {registerDebugGlobals} from './debug'; -import {maybeShowErrorDialog} from './error_dialog'; import {installFileDropHandler} from './file_drop_handler'; import {FlagsPage} from './flags_page'; import {globals} from './globals'; @@ -233,9 +232,8 @@ function main() { document.head.append(script, css); // Add Error handlers for JS error and for uncaught exceptions in promises. - setErrorHandler((err: string) => maybeShowErrorDialog(err)); - window.addEventListener('error', (e) => reportError(e)); - window.addEventListener('unhandledrejection', (e) => reportError(e)); + window.addEventListener('error', (e) => reportError(e, globals.errorHandler)); + window.addEventListener('unhandledrejection', (e) => reportError(e, globals.errorHandler)); const extensionLocalChannel = new MessageChannel();