From c2560064e30aa8d7f565cb91d14a5cad19d21d47 Mon Sep 17 00:00:00 2001
From: Alex Gleason <alex@alexgleason.me>
Date: Wed, 8 Sep 2021 15:45:44 -0500
Subject: [PATCH] Sentry: basic monitoring

---
 app/soapbox/build_config.js              |  2 +
 app/soapbox/components/error_boundary.js |  3 +
 app/soapbox/main.js                      |  4 ++
 app/soapbox/monitoring.js                | 16 +++++
 package.json                             |  3 +
 yarn.lock                                | 80 ++++++++++++++++++++++++
 6 files changed, 108 insertions(+)
 create mode 100644 app/soapbox/monitoring.js

diff --git a/app/soapbox/build_config.js b/app/soapbox/build_config.js
index 7e0419619..bb9209d6c 100644
--- a/app/soapbox/build_config.js
+++ b/app/soapbox/build_config.js
@@ -11,6 +11,7 @@ const {
   BACKEND_URL,
   FE_SUBDIRECTORY,
   FE_BUILD_DIR,
+  SENTRY_DSN,
 } = process.env;
 
 const sanitizeURL = url => {
@@ -38,4 +39,5 @@ module.exports = sanitize({
   BACKEND_URL: sanitizeURL(BACKEND_URL),
   FE_SUBDIRECTORY: sanitizeBasename(FE_SUBDIRECTORY),
   FE_BUILD_DIR: sanitizePath(FE_BUILD_DIR) || 'static',
+  SENTRY_DSN,
 });
diff --git a/app/soapbox/components/error_boundary.js b/app/soapbox/components/error_boundary.js
index 731e7ecf2..b2b077a5f 100644
--- a/app/soapbox/components/error_boundary.js
+++ b/app/soapbox/components/error_boundary.js
@@ -2,6 +2,7 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { FormattedMessage } from 'react-intl';
 import Bowser from 'bowser';
+import * as Sentry from '@sentry/browser';
 
 export default class ErrorBoundary extends React.PureComponent {
 
@@ -15,6 +16,8 @@ export default class ErrorBoundary extends React.PureComponent {
   }
 
   componentDidCatch(error, info) {
+    Sentry.captureException(error);
+
     this.setState({
       hasError: true,
       error,
diff --git a/app/soapbox/main.js b/app/soapbox/main.js
index 599831e08..3802874df 100644
--- a/app/soapbox/main.js
+++ b/app/soapbox/main.js
@@ -10,12 +10,16 @@ import React from 'react';
 import ReactDOM from 'react-dom';
 import * as OfflinePluginRuntime from '@lcdp/offline-plugin/runtime';
 import * as perf from './performance';
+import * as monitoring from './monitoring';
 import ready from './ready';
 import { NODE_ENV } from 'soapbox/build_config';
 
 function main() {
   perf.start('main()');
 
+  // Sentry
+  monitoring.start();
+
   ready(() => {
     const mountNode = document.getElementById('soapbox');
 
diff --git a/app/soapbox/monitoring.js b/app/soapbox/monitoring.js
new file mode 100644
index 000000000..c99edaa70
--- /dev/null
+++ b/app/soapbox/monitoring.js
@@ -0,0 +1,16 @@
+import * as Sentry from '@sentry/react';
+import { Integrations } from '@sentry/tracing';
+import { NODE_ENV, SENTRY_DSN } from 'soapbox/build_config';
+
+export function start() {
+  Sentry.init({
+    dsn: SENTRY_DSN,
+    environment: NODE_ENV,
+    debug: NODE_ENV === 'development',
+    integrations: [new Integrations.BrowserTracing()],
+
+    // We recommend adjusting this value in production, or using tracesSampler
+    // for finer control
+    tracesSampleRate: 1.0,
+  });
+}
diff --git a/package.json b/package.json
index 419294299..7a1ee4e28 100644
--- a/package.json
+++ b/package.json
@@ -51,6 +51,9 @@
     "@fontsource/roboto": "^4.5.0",
     "@lcdp/offline-plugin": "^5.1.0",
     "@popperjs/core": "^2.4.4",
+    "@sentry/browser": "^6.12.0",
+    "@sentry/react": "^6.12.0",
+    "@sentry/tracing": "^6.12.0",
     "@welldone-software/why-did-you-render": "^6.2.0",
     "array-includes": "^3.0.3",
     "autoprefixer": "^10.0.0",
diff --git a/yarn.lock b/yarn.lock
index 9e75304e7..958fca38f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2039,6 +2039,81 @@
   resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.9.2.tgz#adea7b6953cbb34651766b0548468e743c6a2353"
   integrity sha512-VZMYa7+fXHdwIq1TDhSXoVmSPEGM/aa+6Aiq3nVVJ9bXr24zScr+NlKFKC3iPljA7ho/GAZr+d2jOf5GIRC30Q==
 
+"@sentry/browser@6.12.0", "@sentry/browser@^6.12.0":
+  version "6.12.0"
+  resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.12.0.tgz#970cd68fa117a1e1336fdb373e3b1fa76cd63e2d"
+  integrity sha512-wsJi1NLOmfwtPNYxEC50dpDcVY7sdYckzwfqz1/zHrede1mtxpqSw+7iP4bHADOJXuF+ObYYTHND0v38GSXznQ==
+  dependencies:
+    "@sentry/core" "6.12.0"
+    "@sentry/types" "6.12.0"
+    "@sentry/utils" "6.12.0"
+    tslib "^1.9.3"
+
+"@sentry/core@6.12.0":
+  version "6.12.0"
+  resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.12.0.tgz#bc7c5f0785b6a392d9ad47bd9b1fae3f5389996c"
+  integrity sha512-mU/zdjlzFHzdXDZCPZm8OeCw7c9xsbL49Mq0TrY0KJjLt4CJBkiq5SDTGfRsenBLgTedYhe5Z/J8Z+xVVq+MfQ==
+  dependencies:
+    "@sentry/hub" "6.12.0"
+    "@sentry/minimal" "6.12.0"
+    "@sentry/types" "6.12.0"
+    "@sentry/utils" "6.12.0"
+    tslib "^1.9.3"
+
+"@sentry/hub@6.12.0":
+  version "6.12.0"
+  resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.12.0.tgz#29e323ab6a95e178fb14fffb684aa0e09707197f"
+  integrity sha512-yR/UQVU+ukr42bSYpeqvb989SowIXlKBanU0cqLFDmv5LPCnaQB8PGeXwJAwWhQgx44PARhmB82S6Xor8gYNxg==
+  dependencies:
+    "@sentry/types" "6.12.0"
+    "@sentry/utils" "6.12.0"
+    tslib "^1.9.3"
+
+"@sentry/minimal@6.12.0":
+  version "6.12.0"
+  resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.12.0.tgz#cbe20e95056cedb9709d7d5b2119ef95206a9f8c"
+  integrity sha512-r3C54Q1KN+xIqUvcgX9DlcoWE7ezWvFk2pSu1Ojx9De81hVqR9u5T3sdSAP2Xma+um0zr6coOtDJG4WtYlOtsw==
+  dependencies:
+    "@sentry/hub" "6.12.0"
+    "@sentry/types" "6.12.0"
+    tslib "^1.9.3"
+
+"@sentry/react@^6.12.0":
+  version "6.12.0"
+  resolved "https://registry.yarnpkg.com/@sentry/react/-/react-6.12.0.tgz#8ae2680d226fafb0da0f3d8366bb285004ba6c2e"
+  integrity sha512-E8Nw9PPzP/EyMy64ksr9xcyYYlBmUA5ROnkPQp7o5wF0xf5/J+nMS1tQdyPnLQe2KUgHlN4kVs2HHft1m7mSYQ==
+  dependencies:
+    "@sentry/browser" "6.12.0"
+    "@sentry/minimal" "6.12.0"
+    "@sentry/types" "6.12.0"
+    "@sentry/utils" "6.12.0"
+    hoist-non-react-statics "^3.3.2"
+    tslib "^1.9.3"
+
+"@sentry/tracing@^6.12.0":
+  version "6.12.0"
+  resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.12.0.tgz#a05c8985ee7fed7310b029b147d8f9f14f2a2e67"
+  integrity sha512-u10QHNknPBzbWSUUNMkvuH53sQd5NaBo6YdNPj4p5b7sE7445Sh0PwBpRbY3ZiUUiwyxV59fx9UQ4yVnPGxZQA==
+  dependencies:
+    "@sentry/hub" "6.12.0"
+    "@sentry/minimal" "6.12.0"
+    "@sentry/types" "6.12.0"
+    "@sentry/utils" "6.12.0"
+    tslib "^1.9.3"
+
+"@sentry/types@6.12.0":
+  version "6.12.0"
+  resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.12.0.tgz#b7395688a79403c6df8d8bb8d81deb8222519853"
+  integrity sha512-urtgLzE4EDMAYQHYdkgC0Ei9QvLajodK1ntg71bGn0Pm84QUpaqpPDfHRU+i6jLeteyC7kWwa5O5W1m/jrjGXA==
+
+"@sentry/utils@6.12.0":
+  version "6.12.0"
+  resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.12.0.tgz#3de261e8d11bdfdc7add64a3065d43517802e975"
+  integrity sha512-oRHQ7TH5TSsJqoP9Gqq25Jvn9LKexXfAh/OoKwjMhYCGKGhqpDNUIZVgl9DWsGw5A5N5xnQyLOxDfyRV5RshdA==
+  dependencies:
+    "@sentry/types" "6.12.0"
+    tslib "^1.9.3"
+
 "@sinonjs/commons@^1.7.0":
   version "1.8.0"
   resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.0.tgz#c8d68821a854c555bba172f3b06959a0039b236d"
@@ -11670,6 +11745,11 @@ tslib@^1.9.0:
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
   integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==
 
+tslib@^1.9.3:
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
+  integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
+
 tslib@^2.0.1:
   version "2.0.2"
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.2.tgz#462295631185db44b21b1ea3615b63cd1c038242"