diff --git a/packages/browser/src/profiling/integration.ts b/packages/browser/src/profiling/integration.ts index 5173705feaa6..3f823429c122 100644 --- a/packages/browser/src/profiling/integration.ts +++ b/packages/browser/src/profiling/integration.ts @@ -1,5 +1,5 @@ -import { getCurrentScope } from '@sentry/core'; -import type { Client, EventEnvelope, EventProcessor, Hub, Integration, Transaction } from '@sentry/types'; +import { convertIntegrationFnToClass, getCurrentScope } from '@sentry/core'; +import type { EventEnvelope, IntegrationFn, Transaction } from '@sentry/types'; import type { Profile } from '@sentry/types/src/profiling'; import { logger } from '@sentry/utils'; @@ -16,108 +16,97 @@ import { takeProfileFromGlobalCache, } from './utils'; -/** - * Browser profiling integration. Stores any event that has contexts["profile"]["profile_id"] - * This exists because we do not want to await async profiler.stop calls as transaction.finish is called - * in a synchronous context. Instead, we handle sending the profile async from the promise callback and - * rely on being able to pull the event from the cache when we need to construct the envelope. This makes the - * integration less reliable as we might be dropping profiles when the cache is full. - * - * @experimental - */ -export class BrowserProfilingIntegration implements Integration { - public static id: string = 'BrowserProfilingIntegration'; +const INTEGRATION_NAME = 'BrowserProfiling'; - public readonly name: string; +const browserProfilingIntegration: IntegrationFn = () => { + return { + name: INTEGRATION_NAME, + setup(client) { + const scope = getCurrentScope(); - /** @deprecated This is never set. */ - public getCurrentHub?: () => Hub; + const transaction = scope.getTransaction(); - public constructor() { - this.name = BrowserProfilingIntegration.id; - } - - /** - * @inheritDoc - */ - public setupOnce(_addGlobalEventProcessor: (callback: EventProcessor) => void, _getCurrentHub: () => Hub): void { - // noop - } - - /** @inheritdoc */ - public setup(client: Client): void { - const scope = getCurrentScope(); - - const transaction = scope.getTransaction(); - - if (transaction && isAutomatedPageLoadTransaction(transaction)) { - if (shouldProfileTransaction(transaction)) { - startProfileForTransaction(transaction); - } - } - - if (typeof client.on !== 'function') { - logger.warn('[Profiling] Client does not support hooks, profiling will be disabled'); - return; - } - - client.on('startTransaction', (transaction: Transaction) => { - if (shouldProfileTransaction(transaction)) { - startProfileForTransaction(transaction); - } - }); - - client.on('beforeEnvelope', (envelope): void => { - // if not profiles are in queue, there is nothing to add to the envelope. - if (!getActiveProfilesCount()) { - return; + if (transaction && isAutomatedPageLoadTransaction(transaction)) { + if (shouldProfileTransaction(transaction)) { + startProfileForTransaction(transaction); + } } - const profiledTransactionEvents = findProfiledTransactionsFromEnvelope(envelope); - if (!profiledTransactionEvents.length) { + if (typeof client.on !== 'function') { + logger.warn('[Profiling] Client does not support hooks, profiling will be disabled'); return; } - const profilesToAddToEnvelope: Profile[] = []; - - for (const profiledTransaction of profiledTransactionEvents) { - const context = profiledTransaction && profiledTransaction.contexts; - const profile_id = context && context['profile'] && context['profile']['profile_id']; - const start_timestamp = context && context['profile'] && context['profile']['start_timestamp']; - - if (typeof profile_id !== 'string') { - DEBUG_BUILD && logger.log('[Profiling] cannot find profile for a transaction without a profile context'); - continue; + client.on('startTransaction', (transaction: Transaction) => { + if (shouldProfileTransaction(transaction)) { + startProfileForTransaction(transaction); } + }); - if (!profile_id) { - DEBUG_BUILD && logger.log('[Profiling] cannot find profile for a transaction without a profile context'); - continue; + client.on('beforeEnvelope', (envelope): void => { + // if not profiles are in queue, there is nothing to add to the envelope. + if (!getActiveProfilesCount()) { + return; } - // Remove the profile from the transaction context before sending, relay will take care of the rest. - if (context && context['profile']) { - delete context.profile; + const profiledTransactionEvents = findProfiledTransactionsFromEnvelope(envelope); + if (!profiledTransactionEvents.length) { + return; } - const profile = takeProfileFromGlobalCache(profile_id); - if (!profile) { - DEBUG_BUILD && logger.log(`[Profiling] Could not retrieve profile for transaction: ${profile_id}`); - continue; + const profilesToAddToEnvelope: Profile[] = []; + + for (const profiledTransaction of profiledTransactionEvents) { + const context = profiledTransaction && profiledTransaction.contexts; + const profile_id = context && context['profile'] && context['profile']['profile_id']; + const start_timestamp = context && context['profile'] && context['profile']['start_timestamp']; + + if (typeof profile_id !== 'string') { + DEBUG_BUILD && logger.log('[Profiling] cannot find profile for a transaction without a profile context'); + continue; + } + + if (!profile_id) { + DEBUG_BUILD && logger.log('[Profiling] cannot find profile for a transaction without a profile context'); + continue; + } + + // Remove the profile from the transaction context before sending, relay will take care of the rest. + if (context && context['profile']) { + delete context.profile; + } + + const profile = takeProfileFromGlobalCache(profile_id); + if (!profile) { + DEBUG_BUILD && logger.log(`[Profiling] Could not retrieve profile for transaction: ${profile_id}`); + continue; + } + + const profileEvent = createProfilingEvent( + profile_id, + start_timestamp as number | undefined, + profile, + profiledTransaction as ProfiledEvent, + ); + if (profileEvent) { + profilesToAddToEnvelope.push(profileEvent); + } } - const profileEvent = createProfilingEvent( - profile_id, - start_timestamp as number | undefined, - profile, - profiledTransaction as ProfiledEvent, - ); - if (profileEvent) { - profilesToAddToEnvelope.push(profileEvent); - } - } + addProfilesToEnvelope(envelope as EventEnvelope, profilesToAddToEnvelope); + }); + }, + }; +}; - addProfilesToEnvelope(envelope as EventEnvelope, profilesToAddToEnvelope); - }); - } -} +/** + * Browser profiling integration. Stores any event that has contexts["profile"]["profile_id"] + * This exists because we do not want to await async profiler.stop calls as transaction.finish is called + * in a synchronous context. Instead, we handle sending the profile async from the promise callback and + * rely on being able to pull the event from the cache when we need to construct the envelope. This makes the + * integration less reliable as we might be dropping profiles when the cache is full. + * + * @experimental + */ +// eslint-disable-next-line deprecation/deprecation +export const BrowserProfilingIntegration = convertIntegrationFnToClass(INTEGRATION_NAME, browserProfilingIntegration); diff --git a/packages/bun/src/integrations/bunserver.ts b/packages/bun/src/integrations/bunserver.ts index 6644728c19b3..89d245908400 100644 --- a/packages/bun/src/integrations/bunserver.ts +++ b/packages/bun/src/integrations/bunserver.ts @@ -1,28 +1,30 @@ -import { Transaction, captureException, continueTrace, runWithAsyncContext, startSpan } from '@sentry/core'; -import type { Integration } from '@sentry/types'; +import { + Transaction, + captureException, + continueTrace, + convertIntegrationFnToClass, + runWithAsyncContext, + startSpan, +} from '@sentry/core'; +import type { IntegrationFn } from '@sentry/types'; import { getSanitizedUrlString, parseUrl } from '@sentry/utils'; +const INTEGRATION_NAME = 'BunServer'; + +const bunServerIntegration: IntegrationFn = () => { + return { + name: INTEGRATION_NAME, + setupOnce() { + instrumentBunServe(); + }, + }; +}; + /** * Instruments `Bun.serve` to automatically create transactions and capture errors. */ -export class BunServer implements Integration { - /** - * @inheritDoc - */ - public static id: string = 'BunServer'; - - /** - * @inheritDoc - */ - public name: string = BunServer.id; - - /** - * @inheritDoc - */ - public setupOnce(): void { - instrumentBunServe(); - } -} +// eslint-disable-next-line deprecation/deprecation +export const BunServer = convertIntegrationFnToClass(INTEGRATION_NAME, bunServerIntegration); /** * Instruments Bun.serve by patching it's options. diff --git a/packages/core/src/metrics/integration.ts b/packages/core/src/metrics/integration.ts index 9ce7f836ca8c..0c3fa626a9e5 100644 --- a/packages/core/src/metrics/integration.ts +++ b/packages/core/src/metrics/integration.ts @@ -1,38 +1,23 @@ -import type { ClientOptions, Integration } from '@sentry/types'; +import type { ClientOptions, IntegrationFn } from '@sentry/types'; import type { BaseClient } from '../baseclient'; +import { convertIntegrationFnToClass } from '../integration'; import { SimpleMetricsAggregator } from './simpleaggregator'; +const INTEGRATION_NAME = 'MetricsAggregator'; + +const metricsAggregatorIntegration: IntegrationFn = () => { + return { + name: INTEGRATION_NAME, + setup(client: BaseClient) { + client.metricsAggregator = new SimpleMetricsAggregator(client); + }, + }; +}; + /** * Enables Sentry metrics monitoring. * * @experimental This API is experimental and might having breaking changes in the future. */ -export class MetricsAggregator implements Integration { - /** - * @inheritDoc - */ - public static id: string = 'MetricsAggregator'; - - /** - * @inheritDoc - */ - public name: string; - - public constructor() { - this.name = MetricsAggregator.id; - } - - /** - * @inheritDoc - */ - public setupOnce(): void { - // Do nothing - } - - /** - * @inheritDoc - */ - public setup(client: BaseClient): void { - client.metricsAggregator = new SimpleMetricsAggregator(client); - } -} +// eslint-disable-next-line deprecation/deprecation +export const MetricsAggregator = convertIntegrationFnToClass(INTEGRATION_NAME, metricsAggregatorIntegration); diff --git a/packages/integration-shims/src/Feedback.ts b/packages/integration-shims/src/Feedback.ts index 3f41a15a8231..78db6083d3c2 100644 --- a/packages/integration-shims/src/Feedback.ts +++ b/packages/integration-shims/src/Feedback.ts @@ -1,4 +1,5 @@ import type { Integration } from '@sentry/types'; +import { consoleSandbox } from '@sentry/utils'; /** * This is a shim for the Feedback integration. @@ -20,8 +21,10 @@ class FeedbackShim implements Integration { public constructor(_options: any) { this.name = FeedbackShim.id; - // eslint-disable-next-line no-console - console.error('You are using new Feedback() even though this bundle does not include Feedback.'); + consoleSandbox(() => { + // eslint-disable-next-line no-console + console.error('You are using new Feedback() even though this bundle does not include Feedback.'); + }); } /** jsdoc */