improve error handling & map stack trace (#809)
* improve error handling & map stack trace * log error message and tweak * support logging multiple errors * move dynamic import inside try/catch
This commit is contained in:
parent
a613d02147
commit
80a49e9611
47
package-lock.json
generated
47
package-lock.json
generated
@ -4761,6 +4761,14 @@
|
|||||||
"is-arrayish": "^0.2.1"
|
"is-arrayish": "^0.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"error-stack-parser": {
|
||||||
|
"version": "2.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.6.tgz",
|
||||||
|
"integrity": "sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==",
|
||||||
|
"requires": {
|
||||||
|
"stackframe": "^1.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"es-abstract": {
|
"es-abstract": {
|
||||||
"version": "1.17.4",
|
"version": "1.17.4",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz",
|
||||||
@ -14120,11 +14128,50 @@
|
|||||||
"resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
|
"resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
|
||||||
"integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w=="
|
"integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w=="
|
||||||
},
|
},
|
||||||
|
"stack-generator": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/stack-generator/-/stack-generator-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-/t1ebrbHkrLrDuNMdeAcsvynWgoH/i4o8EGGfX7dEYDoTXOYVAkEpFdtshlvabzc6JlJ8Kf9YdFEoz7JkzGN9Q==",
|
||||||
|
"requires": {
|
||||||
|
"stackframe": "^1.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"stack-utils": {
|
"stack-utils": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz",
|
||||||
"integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA=="
|
"integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA=="
|
||||||
},
|
},
|
||||||
|
"stackframe": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-0PlYhdKh6AfFxRyK/v+6/k+/mMfyiEBbTM5L94D0ZytQnJ166wuwoTYLHFWGbs2dpA8Rgq763KGWmN1EQEYHRQ=="
|
||||||
|
},
|
||||||
|
"stacktrace-gps": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/stacktrace-gps/-/stacktrace-gps-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-qIr8x41yZVSldqdqe6jciXEaSCKw1U8XTXpjDuy0ki/apyTn/r3w9hDAAQOhZdxvsC93H+WwwEu5cq5VemzYeg==",
|
||||||
|
"requires": {
|
||||||
|
"source-map": "0.5.6",
|
||||||
|
"stackframe": "^1.1.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"source-map": {
|
||||||
|
"version": "0.5.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz",
|
||||||
|
"integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"stacktrace-js": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/stacktrace-js/-/stacktrace-js-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==",
|
||||||
|
"requires": {
|
||||||
|
"error-stack-parser": "^2.0.6",
|
||||||
|
"stack-generator": "^2.0.5",
|
||||||
|
"stacktrace-gps": "^3.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"static-extend": {
|
"static-extend": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
"react": "16.12.0",
|
"react": "16.12.0",
|
||||||
"react-dom": "16.12.0",
|
"react-dom": "16.12.0",
|
||||||
"react-scripts": "3.4.0",
|
"react-scripts": "3.4.0",
|
||||||
"roughjs": "4.0.4"
|
"roughjs": "4.0.4",
|
||||||
|
"stacktrace-js": "2.0.2"
|
||||||
},
|
},
|
||||||
"description": "",
|
"description": "",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -2322,20 +2322,70 @@ export class App extends React.Component<any, AppState> {
|
|||||||
|
|
||||||
const rootElement = document.getElementById("root");
|
const rootElement = document.getElementById("root");
|
||||||
|
|
||||||
class TopErrorBoundary extends React.Component {
|
interface TopErrorBoundaryState {
|
||||||
state = { hasError: false, stack: "", localStorage: "" };
|
unresolvedError: Error[] | null;
|
||||||
|
hasError: boolean;
|
||||||
|
stack: string;
|
||||||
|
localStorage: string;
|
||||||
|
}
|
||||||
|
|
||||||
static getDerivedStateFromError(error: any) {
|
class TopErrorBoundary extends React.Component<any, TopErrorBoundaryState> {
|
||||||
console.error(error);
|
state: TopErrorBoundaryState = {
|
||||||
return {
|
unresolvedError: null,
|
||||||
|
hasError: false,
|
||||||
|
stack: "",
|
||||||
|
localStorage: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidCatch(error: Error) {
|
||||||
|
const _localStorage: any = {};
|
||||||
|
for (const [key, value] of Object.entries({ ...localStorage })) {
|
||||||
|
try {
|
||||||
|
_localStorage[key] = JSON.parse(value);
|
||||||
|
} catch (err) {
|
||||||
|
_localStorage[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setState(state => ({
|
||||||
hasError: true,
|
hasError: true,
|
||||||
localStorage: JSON.stringify({ ...localStorage }),
|
unresolvedError: state.unresolvedError
|
||||||
stack: error.stack,
|
? state.unresolvedError.concat(error)
|
||||||
};
|
: [error],
|
||||||
|
localStorage: JSON.stringify(_localStorage),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidUpdate() {
|
||||||
|
if (this.state.unresolvedError !== null) {
|
||||||
|
let stack = "";
|
||||||
|
for (const error of this.state.unresolvedError) {
|
||||||
|
if (stack) {
|
||||||
|
stack += `\n\n================\n\n`;
|
||||||
|
}
|
||||||
|
stack += `${error.message}:\n\n`;
|
||||||
|
try {
|
||||||
|
const StackTrace = await import("stacktrace-js");
|
||||||
|
stack += (await StackTrace.fromError(error)).join("\n");
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
stack += error.stack || "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState(state => ({
|
||||||
|
unresolvedError: null,
|
||||||
|
stack: `${
|
||||||
|
state.stack ? `${state.stack}\n\n================\n\n${stack}` : stack
|
||||||
|
}`,
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private selectTextArea(event: React.MouseEvent<HTMLTextAreaElement>) {
|
private selectTextArea(event: React.MouseEvent<HTMLTextAreaElement>) {
|
||||||
(event.target as HTMLTextAreaElement).select();
|
if (event.target !== document.activeElement) {
|
||||||
|
event.preventDefault();
|
||||||
|
(event.target as HTMLTextAreaElement).select();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createGithubIssue() {
|
private async createGithubIssue() {
|
||||||
@ -2391,14 +2441,20 @@ class TopErrorBoundary extends React.Component {
|
|||||||
<label>Error stack trace:</label>
|
<label>Error stack trace:</label>
|
||||||
<textarea
|
<textarea
|
||||||
rows={10}
|
rows={10}
|
||||||
onClick={this.selectTextArea}
|
onPointerDown={this.selectTextArea}
|
||||||
defaultValue={this.state.stack}
|
readOnly={true}
|
||||||
|
value={
|
||||||
|
this.state.unresolvedError
|
||||||
|
? "Loading data. please wait..."
|
||||||
|
: this.state.stack
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<label>LocalStorage content:</label>
|
<label>LocalStorage content:</label>
|
||||||
<textarea
|
<textarea
|
||||||
rows={5}
|
rows={5}
|
||||||
onClick={this.selectTextArea}
|
onPointerDown={this.selectTextArea}
|
||||||
defaultValue={this.state.localStorage}
|
readOnly={true}
|
||||||
|
value={this.state.localStorage}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user