import { getCurrentHub, startTransaction, captureException } from "@sentry/nextjs"; import type { Span, Transaction } from "@sentry/types"; /* WHEN TO USE We ran a script that performs a simple mathematical calculation within a loop of 1000000 iterations. Our results were: Plain execution time: 441, Monitored execution time: 8094. This suggests that using these wrappers within large loops can incur significant overhead and is thus not recommended. For smaller loops, the cost incurred may not be very significant on an absolute scale considering that a million monitored iterations only took roughly 8 seconds when monitored. */ const setUpMonitoring = (name: string) => { // Attempt to retrieve the current transaction from Sentry's scope let transaction = getCurrentHub().getScope()?.getTransaction(); // Check if there's an existing transaction, if not, start a new one if (!transaction) { transaction = startTransaction({ op: name, name: name, }); } // Start a new span in the current transaction const span = transaction.startChild({ op: name, description: `Executing ${name}`, }); return [transaction, span]; }; // transaction will always be Transaction, since returned in a list with Span type must be listed as either or here const finishMonitoring = (transaction: Transaction | Span, span: Span) => { // Attempt to retrieve the current transaction from Sentry's scope span.finish(); // If this was a new transaction, finish it if (!getCurrentHub().getScope()?.getTransaction()) { transaction.finish(); } }; const monitorCallbackAsync = async any>( cb: T, ...args: Parameters ): Promise> => { // Check if Sentry set if (!process.env.NEXT_PUBLIC_SENTRY_DSN) return (await cb(...args)) as ReturnType; const [transaction, span] = setUpMonitoring(cb.name); try { const result = await cb(...args); return result as ReturnType; } catch (error) { captureException(error); throw error; } finally { finishMonitoring(transaction, span); } }; const monitorCallbackSync = any>( cb: T, ...args: Parameters ): ReturnType => { // Check if Sentry set if (!process.env.NEXT_PUBLIC_SENTRY_DSN) return cb(...args) as ReturnType; const [transaction, span] = setUpMonitoring(cb.name); try { const result = cb(...args); return result as ReturnType; } catch (error) { captureException(error); throw error; } finally { finishMonitoring(transaction, span); } }; export default monitorCallbackAsync; export { monitorCallbackSync };