mirror of
https://github.com/supabase/supabase.git
synced 2026-09-22 13:37:53 +08:00
8984305b1e
## Problem Browser Sentry reporting sends ordinary application errors at full volume even though full-page crashes are the highest-priority signal. ## Fix Sample eligible browser errors without `globalErrorBoundary` at 1% across Studio, www, and docs. Keep 100% of eligible errors tagged with `globalErrorBoundary`, preserve consent and existing noise filters, and record the applied rate in `codeSampleRate`. ## How to test - Run `node node_modules/vitest/vitest.mjs run ../../packages/common/sentry.test.ts lib/sentry-capture.test.tsx` from `apps/www`. - Run `node node_modules/vitest/vitest.mjs run lib/sentry-client-options.test.ts` from `apps/studio`. - Expected result: tagged page crashes bypass sampling, ordinary errors use the 1% cutoff, and Studio applies sampling once while preserving its existing filters. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Bug Fixes** - Improved error reporting reliability by ensuring page-crash errors are captured without sampling. - Non-crash application errors are now sampled at a low rate, with sampling metadata retained for monitoring. - Updated filtering behavior so relevant Studio errors continue to be reported consistently, including errors previously affected by client-side filtering. - Preserved filtering for third-party-only errors that do not represent application failures. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
73 lines
2.5 KiB
TypeScript
73 lines
2.5 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
import { filterSentryEvent } from './sentry'
|
|
|
|
const enabled = { isPlatform: true, hasConsent: true }
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks()
|
|
})
|
|
|
|
describe('which errors get sent to Sentry', () => {
|
|
it.each([undefined, {}, { third_party_code: false }, { third_party_code: 'false' }])(
|
|
'sends sampled app errors and records the sample rate: %j',
|
|
(tags) => {
|
|
vi.spyOn(Math, 'random').mockReturnValue(0)
|
|
const event = { tags, exception: { values: [{ value: 'Page crashed' }] } }
|
|
expect(filterSentryEvent(event, enabled)).toBe(event)
|
|
expect(event.tags).toEqual({ ...tags, codeSampleRate: '0.01' })
|
|
}
|
|
)
|
|
|
|
it.each([true, 'true'])('drops errors marked as coming from outside the app: %s', (tag) => {
|
|
expect(filterSentryEvent({ tags: { third_party_code: tag } }, enabled)).toBeNull()
|
|
})
|
|
|
|
it.each([true, 'true'])(
|
|
'sends page crashes even when the code location is missing: %s',
|
|
(tag) => {
|
|
const random = vi.spyOn(Math, 'random').mockReturnValue(0.99)
|
|
const event = {
|
|
tags: { third_party_code: true, globalErrorBoundary: tag },
|
|
exception: { values: [{ value: 'Page crashed' }] },
|
|
}
|
|
expect(filterSentryEvent(event, enabled)).toBe(event)
|
|
expect(event.tags).toEqual({
|
|
third_party_code: true,
|
|
globalErrorBoundary: tag,
|
|
codeSampleRate: '1',
|
|
})
|
|
expect(random).not.toHaveBeenCalled()
|
|
}
|
|
)
|
|
|
|
it.each([
|
|
[0.0099, true],
|
|
[0.01, false],
|
|
])('sends 1%% of errors that did not crash the page: %s', (randomValue, isSent) => {
|
|
vi.spyOn(Math, 'random').mockReturnValue(randomValue)
|
|
const event = { tags: {}, exception: { values: [{ value: 'Application error' }] } }
|
|
|
|
expect(filterSentryEvent(event, enabled) === event).toBe(isSent)
|
|
})
|
|
|
|
it.each([undefined, false, 'false', null, 1])(
|
|
'drops errors from outside the app unless marked as a page crash: %s',
|
|
(tag) => {
|
|
expect(
|
|
filterSentryEvent({ tags: { third_party_code: true, globalErrorBoundary: tag } }, enabled)
|
|
).toBeNull()
|
|
}
|
|
)
|
|
|
|
it.each([
|
|
{ isPlatform: false, hasConsent: true },
|
|
{ isPlatform: true, hasConsent: false },
|
|
{ isPlatform: false, hasConsent: false },
|
|
])('drops all errors and page crashes when reporting is turned off: %j', (settings) => {
|
|
for (const tags of [undefined, { globalErrorBoundary: true, third_party_code: true }]) {
|
|
expect(filterSentryEvent({ tags }, settings)).toBeNull()
|
|
}
|
|
})
|
|
})
|