mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
Add sentry integration (#1141)
This commit is contained in:
parent
b7f681a068
commit
4ecbbab7da
8 changed files with 190 additions and 112 deletions
|
@ -1,13 +1,11 @@
|
|||
export default `
|
||||
### Stack trace
|
||||
|
||||
\`\`\`
|
||||
// paste stack trace here
|
||||
\`\`\`
|
||||
|
||||
export default (sentryErrorId) => `
|
||||
### Scene content
|
||||
|
||||
\`\`\`
|
||||
// paste scene content here (if it doesn't contain sensitive data)
|
||||
Paste scene content here
|
||||
\`\`\`
|
||||
|
||||
### Sentry Error ID
|
||||
|
||||
${sentryErrorId}
|
||||
`;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import React from "react";
|
||||
import * as Sentry from "@sentry/browser";
|
||||
import { resetCursor } from "../utils";
|
||||
import { t } from "../i18n";
|
||||
|
||||
interface TopErrorBoundaryState {
|
||||
unresolvedError: Error[] | null;
|
||||
hasError: boolean;
|
||||
stack: string;
|
||||
sentryEventId: string;
|
||||
localStorage: string;
|
||||
}
|
||||
|
||||
|
@ -14,9 +14,8 @@ export class TopErrorBoundary extends React.Component<
|
|||
TopErrorBoundaryState
|
||||
> {
|
||||
state: TopErrorBoundaryState = {
|
||||
unresolvedError: null,
|
||||
hasError: false,
|
||||
stack: "",
|
||||
sentryEventId: "",
|
||||
localStorage: "",
|
||||
};
|
||||
|
||||
|
@ -24,7 +23,7 @@ export class TopErrorBoundary extends React.Component<
|
|||
return this.state.hasError ? this.errorSplash() : this.props.children;
|
||||
}
|
||||
|
||||
componentDidCatch(error: Error) {
|
||||
componentDidCatch(error: Error, errorInfo: any) {
|
||||
resetCursor();
|
||||
const _localStorage: any = {};
|
||||
for (const [key, value] of Object.entries({ ...localStorage })) {
|
||||
|
@ -34,39 +33,17 @@ export class TopErrorBoundary extends React.Component<
|
|||
_localStorage[key] = value;
|
||||
}
|
||||
}
|
||||
this.setState((state) => ({
|
||||
hasError: true,
|
||||
unresolvedError: state.unresolvedError
|
||||
? 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 (error) {
|
||||
console.error(error);
|
||||
stack += error.stack || "";
|
||||
}
|
||||
}
|
||||
Sentry.withScope((scope) => {
|
||||
scope.setExtras(errorInfo);
|
||||
const eventId = Sentry.captureException(error);
|
||||
|
||||
this.setState((state) => ({
|
||||
unresolvedError: null,
|
||||
stack: `${
|
||||
state.stack ? `${state.stack}\n\n================\n\n${stack}` : stack
|
||||
}`,
|
||||
hasError: true,
|
||||
sentryEventId: eventId,
|
||||
localStorage: JSON.stringify(_localStorage),
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private selectTextArea(event: React.MouseEvent<HTMLTextAreaElement>) {
|
||||
|
@ -79,10 +56,8 @@ export class TopErrorBoundary extends React.Component<
|
|||
private async createGithubIssue() {
|
||||
let body = "";
|
||||
try {
|
||||
const templateStr = (await import("../bug-issue-template")).default;
|
||||
if (typeof templateStr === "string") {
|
||||
body = encodeURIComponent(templateStr);
|
||||
}
|
||||
const templateStrFn = (await import("../bug-issue-template")).default;
|
||||
body = encodeURIComponent(templateStrFn(this.state.sentryEventId));
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
@ -124,26 +99,20 @@ export class TopErrorBoundary extends React.Component<
|
|||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="ErrorSplash-paragraph">
|
||||
{t("errorSplash.trackedToSentry_pre")}
|
||||
{this.state.sentryEventId}
|
||||
{t("errorSplash.trackedToSentry_post")}
|
||||
</div>
|
||||
<div className="ErrorSplash-paragraph">
|
||||
{t("errorSplash.openIssueMessage_pre")}
|
||||
<button onClick={this.createGithubIssue}>
|
||||
<button onClick={() => this.createGithubIssue()}>
|
||||
{t("errorSplash.openIssueMessage_button")}
|
||||
</button>
|
||||
{t("errorSplash.openIssueMessage_post")}
|
||||
</div>
|
||||
<div className="ErrorSplash-paragraph">
|
||||
<div className="ErrorSplash-details">
|
||||
<label>{t("errorSplash.errorStack")}</label>
|
||||
<textarea
|
||||
rows={10}
|
||||
onPointerDown={this.selectTextArea}
|
||||
readOnly={true}
|
||||
value={
|
||||
this.state.unresolvedError
|
||||
? t("errorSplash.errorStack_loading")
|
||||
: this.state.stack
|
||||
}
|
||||
/>
|
||||
<label>{t("errorSplash.sceneContent")}</label>
|
||||
<textarea
|
||||
rows={5}
|
||||
|
|
|
@ -1,10 +1,29 @@
|
|||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import * as Sentry from "@sentry/browser";
|
||||
import { TopErrorBoundary } from "./components/TopErrorBoundary";
|
||||
import { IsMobileProvider } from "./is-mobile";
|
||||
import { App } from "./components/App";
|
||||
import "./styles.scss";
|
||||
|
||||
const SentyEnvHostnameMap: { [key: string]: string } = {
|
||||
"excalidraw.com": "production",
|
||||
"now.sh": "staging",
|
||||
};
|
||||
|
||||
const onlineEnv = Object.keys(SentyEnvHostnameMap).find(
|
||||
(item) => window.location.hostname.indexOf(item) >= 0,
|
||||
);
|
||||
|
||||
Sentry.init({
|
||||
// Disable Sentry locally to avoid noise
|
||||
dsn: onlineEnv
|
||||
? "https://7bfc596a5bf945eda6b660d3015a5460@sentry.io/5179260"
|
||||
: undefined,
|
||||
environment: onlineEnv ? SentyEnvHostnameMap[onlineEnv] : undefined,
|
||||
release: process.env.REACT_APP_GIT_SHA,
|
||||
});
|
||||
|
||||
// Block pinch-zooming on iOS outside of the content area
|
||||
document.addEventListener(
|
||||
"touchmove",
|
||||
|
|
|
@ -105,11 +105,11 @@
|
|||
"clearCanvasMessage": "If reloading doesn't work, try ",
|
||||
"clearCanvasMessage_button": "clearing the canvas.",
|
||||
"clearCanvasCaveat": " This will result in loss of work ",
|
||||
"openIssueMessage_pre": "Before doing so, we'd appreciate if you opened an issue on our ",
|
||||
"trackedToSentry_pre": "The error with identifier ",
|
||||
"trackedToSentry_post": " was tracked on our system.",
|
||||
"openIssueMessage_pre": "We were very cautious not to include your scene information on the error. If your scene is not private, please consider following up on our ",
|
||||
"openIssueMessage_button": "bug tracker.",
|
||||
"openIssueMessage_post": " Please include the following error stack trace (and if it's not private, also the scene content):",
|
||||
"errorStack": "Error stack trace:",
|
||||
"errorStack_loading": "Loading data. please wait...",
|
||||
"openIssueMessage_post": " Please include information below by copying and pasting into the GitHub issue.",
|
||||
"sceneContent": "Scene content:"
|
||||
},
|
||||
"roomDialog": {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue