sentry.ts 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import { getFeatureFlag } from "@excalidraw/common";
  2. import * as Sentry from "@sentry/browser";
  3. import callsites from "callsites";
  4. const SentryEnvHostnameMap: { [key: string]: string } = {
  5. "excalidraw.com": "production",
  6. "staging.excalidraw.com": "staging",
  7. "vercel.app": "staging",
  8. };
  9. const SENTRY_DISABLED = import.meta.env.VITE_APP_DISABLE_SENTRY === "true";
  10. // Disable Sentry locally or inside the Docker to avoid noise/respect privacy
  11. const onlineEnv =
  12. !SENTRY_DISABLED &&
  13. Object.keys(SentryEnvHostnameMap).find(
  14. (item) => window.location.hostname.indexOf(item) >= 0,
  15. );
  16. Sentry.init({
  17. dsn: onlineEnv
  18. ? "https://[email protected]/5179260"
  19. : undefined,
  20. environment: onlineEnv ? SentryEnvHostnameMap[onlineEnv] : undefined,
  21. release: import.meta.env.VITE_APP_GIT_SHA,
  22. ignoreErrors: [
  23. "undefined is not an object (evaluating 'window.__pad.performLoop')", // Only happens on Safari, but spams our servers. Doesn't break anything
  24. "InvalidStateError: Failed to execute 'transaction' on 'IDBDatabase': The database connection is closing.", // Not much we can do about the IndexedDB closing error
  25. /(Failed to fetch|(fetch|loading) dynamically imported module)/i, // This is happening when a service worker tries to load an old asset
  26. /QuotaExceededError: (The quota has been exceeded|.*setItem.*Storage)/i, // localStorage quota exceeded
  27. "Internal error opening backing store for indexedDB.open", // Private mode and disabled indexedDB
  28. ],
  29. integrations: [
  30. Sentry.captureConsoleIntegration({
  31. levels: ["error"],
  32. }),
  33. Sentry.featureFlagsIntegration(),
  34. ],
  35. beforeSend(event) {
  36. if (event.request?.url) {
  37. event.request.url = event.request.url.replace(/#.*$/, "");
  38. }
  39. if (!event.exception) {
  40. event.exception = {
  41. values: [
  42. {
  43. type: "ConsoleError",
  44. value: event.message ?? "Unknown error",
  45. stacktrace: {
  46. frames: callsites()
  47. .slice(1)
  48. .filter(
  49. (frame) =>
  50. frame.getFileName() &&
  51. !frame.getFileName()?.includes("@sentry_browser.js"),
  52. )
  53. .map((frame) => ({
  54. filename: frame.getFileName() ?? undefined,
  55. function: frame.getFunctionName() ?? undefined,
  56. in_app: !(
  57. frame.getFileName()?.includes("node_modules") ?? false
  58. ),
  59. lineno: frame.getLineNumber() ?? undefined,
  60. colno: frame.getColumnNumber() ?? undefined,
  61. })),
  62. },
  63. mechanism: {
  64. type: "instrument",
  65. handled: true,
  66. data: {
  67. function: "console.error",
  68. handler: "Sentry.beforeSend",
  69. },
  70. },
  71. },
  72. ],
  73. };
  74. }
  75. return event;
  76. },
  77. });
  78. const flagsIntegration =
  79. Sentry.getClient()?.getIntegrationByName<Sentry.FeatureFlagsIntegration>(
  80. "FeatureFlags",
  81. );
  82. if (flagsIntegration) {
  83. flagsIntegration.addFeatureFlag(
  84. "COMPLEX_BINDINGS",
  85. getFeatureFlag("COMPLEX_BINDINGS"),
  86. );
  87. }