about summary refs log tree commit diff
path: root/src/logger/index.ts
diff options
context:
space:
mode:
authordan <dan.abramov@gmail.com>2023-12-06 16:32:47 +0000
committerGitHub <noreply@github.com>2023-12-06 16:32:47 +0000
commit7229cda5a52192266d8e0ee202ae3d3fee7c66a3 (patch)
treee20fa8773a737e3fd05447ab5890bafb1b3b55a7 /src/logger/index.ts
parentdf55c5fdeb5e67caac13dfdb77e1a80330cdd874 (diff)
downloadvoidsky-7229cda5a52192266d8e0ee202ae3d3fee7c66a3.tar.zst
Throttle non-critical Sentry messages (#2110)
* Throttle non-critical Sentry messages

* Run all timers in tests
Diffstat (limited to 'src/logger/index.ts')
-rw-r--r--src/logger/index.ts30
1 files changed, 28 insertions, 2 deletions
diff --git a/src/logger/index.ts b/src/logger/index.ts
index f03850767..733d0e4b0 100644
--- a/src/logger/index.ts
+++ b/src/logger/index.ts
@@ -170,8 +170,8 @@ export const sentryTransport: Transport = (
         [LogLevel.Warn]: 'warning',
         [LogLevel.Error]: 'error',
       }[level] || 'log') as Sentry.Breadcrumb['level']
-
-      Sentry.captureMessage(message, {
+      // Defer non-critical messages so they're sent in a batch
+      queueMessageForSentry(message, {
         level: messageLevel,
         tags,
         extra: meta,
@@ -188,6 +188,32 @@ export const sentryTransport: Transport = (
   }
 }
 
+const queuedMessages: [string, Parameters<typeof Sentry.captureMessage>[1]][] =
+  []
+let sentrySendTimeout: ReturnType<typeof setTimeout> | null = null
+function queueMessageForSentry(
+  message: string,
+  captureContext: Parameters<typeof Sentry.captureMessage>[1],
+) {
+  queuedMessages.push([message, captureContext])
+  if (!sentrySendTimeout) {
+    // Throttle sending messages with a leading delay
+    // so that we can get Sentry out of the critical path.
+    sentrySendTimeout = setTimeout(() => {
+      sentrySendTimeout = null
+      sendQueuedMessages()
+    }, 7000)
+  }
+}
+function sendQueuedMessages() {
+  while (queuedMessages.length > 0) {
+    const record = queuedMessages.shift()
+    if (record) {
+      Sentry.captureMessage(record[0], record[1])
+    }
+  }
+}
+
 /**
  * Main class. Defaults are provided in the constructor so that subclasses are
  * technically possible, if we need to go that route in the future.