Throttle non-critical Sentry messages (#2110)

* Throttle non-critical Sentry messages

* Run all timers in tests
zio/stable
dan 2023-12-06 16:32:47 +00:00 committed by GitHub
parent df55c5fdeb
commit 7229cda5a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 31 additions and 2 deletions

View File

@ -37,6 +37,7 @@ const dist = `${Platform.OS}.${release}${
}` }`
init({ init({
autoSessionTracking: false,
dsn: 'https://05bc3789bf994b81bd7ce20c86ccd3ae@o4505071687041024.ingest.sentry.io/4505071690514432', dsn: 'https://05bc3789bf994b81bd7ce20c86ccd3ae@o4505071687041024.ingest.sentry.io/4505071690514432',
debug: false, // If `true`, Sentry will try to print out useful debugging information if something goes wrong with sending the event. Set it to `false` in production debug: false, // If `true`, Sentry will try to print out useful debugging information if something goes wrong with sending the event. Set it to `false` in production
enableInExpoDevelopment: true, enableInExpoDevelopment: true,

View File

@ -179,6 +179,7 @@ describe('general functionality', () => {
level: 'debug', // Sentry bug, log becomes debug level: 'debug', // Sentry bug, log becomes debug
timestamp: sentryTimestamp, timestamp: sentryTimestamp,
}) })
jest.runAllTimers()
expect(Sentry.captureMessage).toHaveBeenCalledWith(message, { expect(Sentry.captureMessage).toHaveBeenCalledWith(message, {
level: 'log', level: 'log',
tags: undefined, tags: undefined,
@ -193,6 +194,7 @@ describe('general functionality', () => {
level: 'warning', level: 'warning',
timestamp: sentryTimestamp, timestamp: sentryTimestamp,
}) })
jest.runAllTimers()
expect(Sentry.captureMessage).toHaveBeenCalledWith(message, { expect(Sentry.captureMessage).toHaveBeenCalledWith(message, {
level: 'warning', level: 'warning',
tags: undefined, tags: undefined,

View File

@ -170,8 +170,8 @@ export const sentryTransport: Transport = (
[LogLevel.Warn]: 'warning', [LogLevel.Warn]: 'warning',
[LogLevel.Error]: 'error', [LogLevel.Error]: 'error',
}[level] || 'log') as Sentry.Breadcrumb['level'] }[level] || 'log') as Sentry.Breadcrumb['level']
// Defer non-critical messages so they're sent in a batch
Sentry.captureMessage(message, { queueMessageForSentry(message, {
level: messageLevel, level: messageLevel,
tags, tags,
extra: meta, 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 * Main class. Defaults are provided in the constructor so that subclasses are
* technically possible, if we need to go that route in the future. * technically possible, if we need to go that route in the future.