import * as Sentry from '@sentry/browser' import { BrowserTracing } from '@sentry/tracing' import type { Span, SpanContext, Transaction, TransactionContext, } from '@sentry/types' import type { BrowserTracingOptions } from '@sentry/tracing/types/browser/browsertracing' export function initTracing( sentryDsn: string, browserTracingOptions: Partial = {}, tracesSampleRate: number = 0.01 ) { Sentry.init({ dsn: sentryDsn, integrations: [ new BrowserTracing({ tracingOrigins: [ 'localhost', /https:\/\/[a-zA-Z0-9-_]*\.adalo\.com/, /https:\/\/[a-zA-Z0-9-_]*\.herokuapp\.com/, /^\//, ], ...browserTracingOptions, }), ], sampleRate: 0.1, tracesSampleRate, }) } export function startTransaction( context: TransactionContext ): Transaction | undefined { const transaction = Sentry.startTransaction(context) // Fail fast when Sentry hasn't been initialized. // Consumers of this library must run initTracing at the start of the program. if (!transaction) { throw new Error( `Tracing has not been initialized. Have you invoked initTracing() yet?` ) } Sentry.getCurrentHub().configureScope(scope => scope.setSpan(transaction)) return transaction } export function finishTransaction(txn: Transaction): void { txn.finish() Sentry.getCurrentHub().configureScope(scope => scope.setSpan(undefined)) } function getCurrentSpan(): Span | undefined { const scope = Sentry.getCurrentHub().getScope() return scope?.getSpan() } export function startSpan(spanContext: SpanContext): Span | undefined { const parentSpan = getCurrentSpan() return parentSpan?.startChild(spanContext) } /** * Utility that wraps a function in an instrumented Sentry Span. * * TODO: This is very similar to (and originally copied from) the same method in database. Consider moving to the utils repo to dedupe. */ export function sentryTracingInterceptor( func: (...args: unknown[]) => T, spanName: string = func.name, logArguments = true ): (...args: unknown[]) => Promise { // eslint-disable-next-line func-names return async function (this: unknown, ...args: unknown[]): Promise { const span = startSpan({ op: spanName, description: spanName, data: { function: func.name, arguments: logArguments ? args : undefined, }, }) if (span === undefined) { // eslint-disable-next-line @typescript-eslint/return-await return await func.apply(this, args) } try { const ret = await func.apply(this, args) span.setStatus('ok') return ret } catch (err) { span.setStatus('unknown_error') throw err } finally { span.finish() } } }