2020-12-03 08:58:46 -05:00
|
|
|
// Conditionally enable Sentry based on whether the DSN token is set
|
2022-04-22 06:42:57 -04:00
|
|
|
import getMeta from '../utils/meta'
|
2022-07-28 10:38:55 -04:00
|
|
|
import OError from '@overleaf/o-error'
|
2023-09-27 05:45:49 -04:00
|
|
|
import { debugConsole } from '@/utils/debugging'
|
2022-04-22 06:42:57 -04:00
|
|
|
|
2024-06-18 06:01:37 -04:00
|
|
|
const {
|
|
|
|
sentryAllowedOriginRegex,
|
|
|
|
sentryDsn,
|
|
|
|
sentryEnvironment,
|
|
|
|
sentryRelease,
|
|
|
|
} = getMeta('ol-ExposedSettings')
|
|
|
|
|
|
|
|
const reporterPromise = sentryDsn ? sentryReporter() : nullReporter()
|
2020-12-03 08:58:46 -05:00
|
|
|
|
|
|
|
function sentryReporter() {
|
|
|
|
return (
|
|
|
|
import(/* webpackMode: "eager" */ '@sentry/browser')
|
|
|
|
.then(Sentry => {
|
|
|
|
let eventCount = 0
|
|
|
|
|
|
|
|
Sentry.init({
|
2024-06-18 06:01:37 -04:00
|
|
|
dsn: sentryDsn,
|
|
|
|
environment: sentryEnvironment,
|
|
|
|
release: sentryRelease,
|
2021-05-12 06:28:30 -04:00
|
|
|
autoSessionTracking: false,
|
2020-12-03 08:58:46 -05:00
|
|
|
|
|
|
|
// Ignore errors unless they come from our origins
|
2022-08-04 05:38:30 -04:00
|
|
|
// Adapted from: https://docs.sentry.io/platforms/javascript/configuration/filtering/#decluttering-sentry
|
2024-06-18 06:01:37 -04:00
|
|
|
allowUrls: [new RegExp(sentryAllowedOriginRegex)],
|
2020-12-03 08:58:46 -05:00
|
|
|
|
|
|
|
ignoreErrors: [
|
|
|
|
// Ignore very noisy error
|
|
|
|
'SecurityError: Permission denied to access property "pathname" on cross-origin object',
|
|
|
|
// Ignore unhandled error that is "expected" - see https://github.com/overleaf/issues/issues/3321
|
|
|
|
/^Missing PDF/,
|
|
|
|
// Ignore "expected" error from aborted fetch - see https://github.com/overleaf/issues/issues/3321
|
|
|
|
/^AbortError/,
|
|
|
|
// Ignore spurious error from Ace internals - see https://github.com/overleaf/issues/issues/3321
|
|
|
|
'ResizeObserver loop limit exceeded',
|
2021-04-27 03:52:58 -04:00
|
|
|
'ResizeObserver loop completed with undelivered notifications.',
|
2021-08-16 10:58:36 -04:00
|
|
|
// Microsoft Outlook SafeLink crawler
|
|
|
|
// https://forum.sentry.io/t/unhandledrejection-non-error-promise-rejection-captured-with-value/14062
|
|
|
|
/Non-Error promise rejection captured with value: Object Not Found Matching Id/,
|
2022-10-06 04:27:59 -04:00
|
|
|
// Ignore CM6 error until upgraded
|
|
|
|
"Cannot read properties of undefined (reading 'length')",
|
2023-11-27 06:27:11 -05:00
|
|
|
// Ignore Angular digest iteration limit - see https://github.com/overleaf/internal/issues/15750
|
|
|
|
'10 $digest() iterations reached',
|
2024-10-25 07:32:20 -04:00
|
|
|
// Ignore a frequent unhandled promise rejection
|
|
|
|
/Non-Error promise rejection captured with keys: currentTarget, detail, isTrusted, target/,
|
2020-12-03 08:58:46 -05:00
|
|
|
],
|
|
|
|
|
2022-08-05 05:03:24 -04:00
|
|
|
denyUrls: [
|
|
|
|
// Chrome extensions
|
|
|
|
/extensions\//i,
|
|
|
|
/^chrome:\/\//i,
|
|
|
|
],
|
|
|
|
|
2020-12-03 08:58:46 -05:00
|
|
|
beforeSend(event) {
|
|
|
|
// Limit number of events sent to Sentry to 100 events "per page load",
|
|
|
|
// (i.e. the cap will be reset if the page is reloaded). This prevent
|
|
|
|
// hitting their server-side event cap.
|
|
|
|
eventCount++
|
|
|
|
if (eventCount > 100) {
|
|
|
|
return null // Block the event from sending
|
|
|
|
}
|
2022-08-05 05:03:24 -04:00
|
|
|
|
|
|
|
// Do not send events related to third party code (extensions)
|
|
|
|
if (
|
2024-10-03 08:33:50 -04:00
|
|
|
(event.extra?.arguments as { type: string }[] | undefined)?.[0]
|
|
|
|
?.type === 'UNSTABLE_editor:extensions'
|
2022-08-05 05:03:24 -04:00
|
|
|
) {
|
|
|
|
return null // Block the event from sending
|
|
|
|
}
|
|
|
|
|
|
|
|
return event
|
2021-04-27 03:52:58 -04:00
|
|
|
},
|
2020-12-03 08:58:46 -05:00
|
|
|
})
|
|
|
|
|
2024-06-18 06:01:37 -04:00
|
|
|
Sentry.setUser({ id: getMeta('ol-user_id') })
|
2020-12-03 08:58:46 -05:00
|
|
|
|
2022-04-22 06:42:57 -04:00
|
|
|
const splitTestAssignments = getMeta('ol-splitTestVariants')
|
|
|
|
if (splitTestAssignments) {
|
|
|
|
for (const [name, value] of Object.entries(splitTestAssignments)) {
|
2022-04-26 05:37:22 -04:00
|
|
|
// Ensure Sentry tag name is within the 32-character limit
|
|
|
|
Sentry.setTag(`ol.${name}`.slice(0, 32), value.toString())
|
2022-04-22 06:42:57 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-03 08:58:46 -05:00
|
|
|
return Sentry
|
|
|
|
})
|
|
|
|
// If Sentry fails to load, use the null reporter instead
|
2021-05-12 06:28:30 -04:00
|
|
|
.catch(error => {
|
2023-09-27 05:45:49 -04:00
|
|
|
debugConsole.error(error)
|
2021-05-12 06:28:30 -04:00
|
|
|
return nullReporter()
|
|
|
|
})
|
2020-12-03 08:58:46 -05:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
function nullReporter() {
|
|
|
|
return Promise.resolve({
|
2023-09-27 05:45:49 -04:00
|
|
|
captureException: debugConsole.error,
|
|
|
|
captureMessage: debugConsole.error,
|
2020-12-03 08:58:46 -05:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-10-16 06:54:35 -04:00
|
|
|
// https://develop.sentry.dev/sdk/data-model/event-payloads/contexts/
|
|
|
|
// https://docs.sentry.io/platforms/javascript/enriching-events/context/#passing-context-directly
|
|
|
|
type Options = {
|
|
|
|
tags?: Record<string, any>
|
|
|
|
extra?: Record<string, any>
|
|
|
|
}
|
|
|
|
|
|
|
|
export function captureException(err: Error, options?: Options) {
|
2022-07-28 10:38:55 -04:00
|
|
|
options = options || {}
|
|
|
|
const extra = Object.assign(OError.getFullInfo(err), options.extra || {})
|
|
|
|
const fullStack = OError.getFullStack(err)
|
|
|
|
if (err.stack !== fullStack) {
|
|
|
|
// Attach tracebacks from OError.tag() and OError.cause.
|
|
|
|
extra.fullStack = fullStack
|
|
|
|
}
|
|
|
|
reporterPromise.then(reporter =>
|
|
|
|
reporter.captureException(err, {
|
|
|
|
...options,
|
|
|
|
extra,
|
|
|
|
})
|
|
|
|
)
|
2020-12-03 08:58:46 -05:00
|
|
|
}
|