UNPKG

@sentry/ember

Version:
122 lines (105 loc) 4.05 kB
// import/export got a false positive, and affects most of our index barrel files // can be removed once following issue is fixed: https://github.com/import-js/eslint-plugin-import/issues/703 /* eslint-disable import/export */ import { assert } from '@ember/debug'; import type Route from '@ember/routing/route'; import { getOwnConfig } from '@embroider/macros'; import type { BrowserOptions } from '@sentry/browser'; import { startSpan } from '@sentry/browser'; import * as Sentry from '@sentry/browser'; import type { Client, TransactionSource } from '@sentry/core'; import { applySdkMetadata, GLOBAL_OBJ, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, } from '@sentry/core'; import type { EmberSentryConfig, GlobalConfig, OwnConfig } from './types'; function _getSentryInitConfig(): EmberSentryConfig['sentry'] { const _global = GLOBAL_OBJ as typeof GLOBAL_OBJ & GlobalConfig; _global.__sentryEmberConfig = _global.__sentryEmberConfig ?? {}; return _global.__sentryEmberConfig; } /** * Initialize the Sentry SDK for Ember. */ export function init(_runtimeConfig?: BrowserOptions): Client | undefined { const environmentConfig = getOwnConfig<OwnConfig>().sentryConfig; assert('Missing configuration.', environmentConfig); assert('Missing configuration for Sentry.', environmentConfig.sentry || _runtimeConfig); if (!environmentConfig.sentry) { // If environment config is not specified but the above assertion passes, use runtime config. environmentConfig.sentry = { ..._runtimeConfig }; } // Merge runtime config into environment config, preferring runtime. Object.assign(environmentConfig.sentry, _runtimeConfig || {}); const initConfig = Object.assign({}, environmentConfig.sentry); applySdkMetadata(initConfig, 'ember'); // Persist Sentry init options so they are identical when performance initializers call init again. const sentryInitConfig = _getSentryInitConfig(); Object.assign(sentryInitConfig, initConfig); return Sentry.init(initConfig); } type RouteConstructor = new (...args: ConstructorParameters<typeof Route>) => Route; export const instrumentRoutePerformance = <T extends RouteConstructor>(BaseRoute: T): T => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const instrumentFunction = async <X extends (...args: unknown[]) => any>( op: string, name: string, fn: X, args: Parameters<X>, source: TransactionSource, ): Promise<ReturnType<X>> => { return startSpan( { attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source, [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.ember', }, op, name, onlyIfParent: true, }, () => { return fn(...args); }, ); }; const routeName = BaseRoute.name; return { // @ts-expect-error TS2545 We do not need to redefine a constructor here [routeName]: class extends BaseRoute { public beforeModel(...args: unknown[]): void | Promise<unknown> { return instrumentFunction( 'ui.ember.route.before_model', this.fullRouteName, super.beforeModel.bind(this), args, 'custom', ); } public async model(...args: unknown[]): Promise<unknown> { return instrumentFunction('ui.ember.route.model', this.fullRouteName, super.model.bind(this), args, 'custom'); } public afterModel(...args: unknown[]): void | Promise<unknown> { return instrumentFunction( 'ui.ember.route.after_model', this.fullRouteName, super.afterModel.bind(this), args, 'custom', ); } public setupController(...args: unknown[]): void | Promise<unknown> { return instrumentFunction( 'ui.ember.route.setup_controller', this.fullRouteName, super.setupController.bind(this), args, 'custom', ); } }, }[routeName] as T; }; export * from '@sentry/browser';