Add info about interactions to error reports

Summary: When reporting errors we could add info about interactions which caused errors. Ability to connect errors and interactions could be quite helpful for analysing and debugging errors and where they are coming from.

Reviewed By: passy, mweststrate

Differential Revision: D28467575

fbshipit-source-id: bef69917a4d6c786d762a2f6eb75a47fd4e46b0f
This commit is contained in:
Anton Nikolaev
2021-05-18 08:06:07 -07:00
committed by Facebook GitHub Bot
parent 03a1add092
commit 853ee24c9b
9 changed files with 51 additions and 13 deletions

View File

@@ -0,0 +1,16 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
export function v4() {
return '00000000-0000-0000-0000-000000000000';
}
export function v1() {
return '00000000-0000-0000-0000-000000000000';
}

View File

@@ -15,14 +15,7 @@
export function cleanStack(_stack: string, _loc?: string) {}
import ScribeLogger from './ScribeLogger';
export type ObjectError =
| Error
| {
message: string;
stack?: string;
};
export default class ErrorReporter {
constructor(_scribeLogger: ScribeLogger) {}
report(_err: ObjectError) {}
report(_err: Error) {}
}

View File

@@ -7,11 +7,20 @@
* @format
*/
import {InteractionReport} from 'flipper-plugin';
export class CancelledPromiseError extends Error {
constructor(msg: string) {
super(msg);
this.name = 'CancelledPromiseError';
}
name: 'CancelledPromiseError';
}
declare global {
interface Error {
interaction?: InteractionReport;
}
}
export function isError(obj: any): obj is Error {

View File

@@ -12,12 +12,14 @@
"@emotion/css": "^11.1.3",
"@emotion/react": "^11.4.0",
"@reach/observe-rect": "^1.2.0",
"@types/uuid": "^8.3.0",
"immer": "^9.0.2",
"lodash": "^4.17.21",
"react-color": "^2.19.3",
"react-element-to-jsx-string": "^14.3.2",
"react-virtual": "^2.7.1",
"string-natural-compare": "^3.0.0"
"string-natural-compare": "^3.0.0",
"uuid": "^8.3.2"
},
"devDependencies": {
"@types/jest": "^26.0.23",

View File

@@ -92,6 +92,8 @@ test('Correct top level API exposed', () => {
"FlipperLib",
"HighlightManager",
"Idler",
"InteractionReport",
"InteractionReporter",
"LogLevel",
"LogTypes",
"Logger",

View File

@@ -69,6 +69,8 @@ export {
withTrackingScope,
useTrackedCallback,
wrapInteractionHandler as _wrapInteractionHandler,
InteractionReport,
InteractionReporter,
} from './ui/Tracked';
export {DataFormatter} from './ui/DataFormatter';

View File

@@ -10,6 +10,7 @@
import React, {useMemo} from 'react';
import {Children, cloneElement, createContext, useContext} from 'react';
import reactElementToJSXString from 'react-element-to-jsx-string';
import {v4 as uuid} from 'uuid';
export type InteractionReport = {
// Duration of the event handler itself, not including any time the promise handler might have been pending
@@ -22,6 +23,7 @@ export type InteractionReport = {
action: string;
componentType: string;
event: string;
uuid: string;
};
export type InteractionReporter = (report: InteractionReport) => void;
@@ -124,8 +126,9 @@ export function wrapInteractionHandler<T extends Function>(
scope: string,
action?: string,
): T {
const interaction_uuid = uuid();
function report(start: number, initialEnd: number, error?: any) {
globalInteractionReporter({
const interactionReport: InteractionReport = {
duration: initialEnd - start,
totalDuration: Date.now() - start,
success: error ? 0 : 1,
@@ -143,7 +146,13 @@ export function wrapInteractionHandler<T extends Function>(
: 'unknown'),
scope,
event,
});
uuid: interaction_uuid,
};
if (error && typeof error === 'object') {
// associate the error with the interaction caused it
error.interaction = interactionReport;
}
globalInteractionReporter(interactionReport);
}
const res = function trappedInteractionHandler(this: any) {
@@ -168,7 +177,7 @@ export function wrapInteractionHandler<T extends Function>(
(error: any) => r(initialEnd, error),
);
res = res.catch((error: any) => {
// we need to create another rejected promise so error is again marked as "unhandled"
// we need to create another rejected promise so error is again marked as "unhandled".
return Promise.reject(error);
});
} else {

View File

@@ -54,6 +54,7 @@ test('Tracked button', () => {
event: 'onClick',
scope: 'Flipper',
success: 1,
uuid: '00000000-0000-0000-0000-000000000000',
});
});
@@ -74,6 +75,7 @@ test('Tracked button - custom handler', () => {
event: 'onDoubleClick',
scope: 'Flipper',
success: 1,
uuid: '00000000-0000-0000-0000-000000000000',
});
});
@@ -99,6 +101,7 @@ test('Throwing action', () => {
event: 'click',
scope: 'test',
success: 0,
uuid: '00000000-0000-0000-0000-000000000000',
});
});
@@ -124,6 +127,7 @@ test('Async action', async () => {
event: 'click',
scope: 'test',
success: 1,
uuid: '00000000-0000-0000-0000-000000000000',
});
});
@@ -155,6 +159,7 @@ test('Throwing async action', async () => {
event: 'click',
scope: 'test',
success: 0,
uuid: '00000000-0000-0000-0000-000000000000',
});
});

View File

@@ -3143,7 +3143,7 @@
resolved "https://registry.yarnpkg.com/@types/url-join/-/url-join-4.0.0.tgz#72eff71648a429c7d4acf94e03780e06671369bd"
integrity sha512-awrJu8yML4E/xTwr2EMatC+HBnHGoDxc2+ImA9QyeUELI1S7dOCIZcyjki1rkwoA8P2D2NVgLAJLjnclkdLtAw==
"@types/uuid@^8.0.0", "@types/uuid@^8.0.1":
"@types/uuid@^8.0.0", "@types/uuid@^8.0.1", "@types/uuid@^8.3.0":
version "8.3.0"
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f"
integrity sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==