@@ -8,18 +8,13 @@ import type { EmberRunQueues } from '@ember/runloop/-private/types';
88import { getOwnConfig , isTesting , macroCondition } from '@embroider/macros' ;
99import * as Sentry from '@sentry/browser' ;
1010import type { ExtendedBackburner } from '@sentry/ember/runloop' ;
11- import type { Span , Transaction } from '@sentry/types' ;
11+ import type { Span } from '@sentry/types' ;
1212import { GLOBAL_OBJ , browserPerformanceTimeOrigin , timestampInSeconds } from '@sentry/utils' ;
1313
1414import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core' ;
1515import type { BrowserClient } from '..' ;
1616import { getActiveSpan , startInactiveSpan } from '..' ;
17- import type { EmberRouterMain , EmberSentryConfig , GlobalConfig , OwnConfig , StartTransactionFunction } from '../types' ;
18-
19- type SentryTestRouterService = RouterService & {
20- _startTransaction ?: StartTransactionFunction ;
21- _sentryInstrumented ?: boolean ;
22- } ;
17+ import type { EmberRouterMain , EmberSentryConfig , GlobalConfig , OwnConfig } from '../types' ;
2318
2419function getSentryConfig ( ) : EmberSentryConfig {
2520 const _global = GLOBAL_OBJ as typeof GLOBAL_OBJ & GlobalConfig ;
@@ -98,26 +93,17 @@ export function _instrumentEmberRouter(
9893 routerService : RouterService ,
9994 routerMain : EmberRouterMain ,
10095 config : EmberSentryConfig ,
101- startTransaction : StartTransactionFunction ,
102- startTransactionOnPageLoad ?: boolean ,
103- ) : {
104- startTransaction : StartTransactionFunction ;
105- } {
96+ ) : void {
10697 const { disableRunloopPerformance } = config ;
10798 const location = routerMain . location ;
108- let activeTransaction : Transaction | undefined ;
99+ let activeRootSpan : Span | undefined ;
109100 let transitionSpan : Span | undefined ;
110101
111102 const url = getLocationURL ( location ) ;
112103
113- if ( macroCondition ( isTesting ( ) ) ) {
114- ( routerService as SentryTestRouterService ) . _sentryInstrumented = true ;
115- ( routerService as SentryTestRouterService ) . _startTransaction = startTransaction ;
116- }
117-
118- if ( startTransactionOnPageLoad && url ) {
104+ if ( url ) {
119105 const routeInfo = routerService . recognize ( url ) ;
120- activeTransaction = startTransaction ( {
106+ Sentry . startBrowserTracingNavigationSpan ( {
121107 name : `route:${ routeInfo . name } ` ,
122108 op : 'pageload' ,
123109 origin : 'auto.pageload.ember' ,
@@ -127,20 +113,22 @@ export function _instrumentEmberRouter(
127113 'routing.instrumentation' : '@sentry/ember' ,
128114 } ,
129115 } ) ;
116+ activeRootSpan = getActiveSpan ( ) ;
130117 }
131118
132119 const finishActiveTransaction = ( _ : unknown , nextInstance : unknown ) : void => {
133120 if ( nextInstance ) {
134121 return ;
135122 }
136- activeTransaction ?. end ( ) ;
123+ activeRootSpan ?. end ( ) ;
137124 getBackburner ( ) . off ( 'end' , finishActiveTransaction ) ;
138125 } ;
139126
140127 routerService . on ( 'routeWillChange' , ( transition : Transition ) => {
141128 const { fromRoute, toRoute } = getTransitionInformation ( transition , routerService ) ;
142- activeTransaction ?. end ( ) ;
143- activeTransaction = startTransaction ( {
129+ activeRootSpan ?. end ( ) ;
130+
131+ Sentry . startBrowserTracingNavigationSpan ( {
144132 name : `route:${ toRoute } ` ,
145133 op : 'navigation' ,
146134 origin : 'auto.navigation.ember' ,
@@ -150,6 +138,9 @@ export function _instrumentEmberRouter(
150138 'routing.instrumentation' : '@sentry/ember' ,
151139 } ,
152140 } ) ;
141+
142+ activeRootSpan = getActiveSpan ( ) ;
143+
153144 transitionSpan = startInactiveSpan ( {
154145 attributes : {
155146 [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] : 'auto.ui.ember' ,
@@ -160,22 +151,18 @@ export function _instrumentEmberRouter(
160151 } ) ;
161152
162153 routerService . on ( 'routeDidChange' , ( ) => {
163- if ( ! transitionSpan || ! activeTransaction ) {
154+ if ( ! transitionSpan || ! activeRootSpan ) {
164155 return ;
165156 }
166157 transitionSpan . end ( ) ;
167158
168159 if ( disableRunloopPerformance ) {
169- activeTransaction . end ( ) ;
160+ activeRootSpan . end ( ) ;
170161 return ;
171162 }
172163
173164 getBackburner ( ) . on ( 'end' , finishActiveTransaction ) ;
174165 } ) ;
175-
176- return {
177- startTransaction,
178- } ;
179166}
180167
181168function _instrumentEmberRunloop ( config : EmberSentryConfig ) : void {
@@ -411,61 +398,64 @@ export async function instrumentForPerformance(appInstance: ApplicationInstance)
411398 // Maintaining backwards compatibility with config.browserTracingOptions, but passing it with Sentry options is preferred.
412399 const browserTracingOptions = config . browserTracingOptions || config . sentry . browserTracingOptions || { } ;
413400
414- const { BrowserTracing } = await import ( '@sentry/browser' ) ;
401+ const { browserTracingIntegration } = await import ( '@sentry/browser' ) ;
415402
416403 const idleTimeout = config . transitionTimeout || 5000 ;
417404
418- const browserTracing = new BrowserTracing ( {
419- routingInstrumentation : ( customStartTransaction , startTransactionOnPageLoad ) => {
420- // eslint-disable-next-line ember/no-private-routing-service
421- const routerMain = appInstance . lookup ( 'router:main' ) as EmberRouterMain ;
422- let routerService = appInstance . lookup ( 'service:router' ) as RouterService & {
423- externalRouter ?: RouterService ;
424- _hasMountedSentryPerformanceRouting ?: boolean ;
425- } ;
426-
427- if ( routerService . externalRouter ) {
428- // Using ember-engines-router-service in an engine.
429- routerService = routerService . externalRouter ;
430- }
431- if ( routerService . _hasMountedSentryPerformanceRouting ) {
432- // Routing listens to route changes on the main router, and should not be initialized multiple times per page.
433- return ;
434- }
435- if ( ! routerService . recognize ) {
436- // Router is missing critical functionality to limit cardinality of the transaction names.
437- return ;
438- }
439- routerService . _hasMountedSentryPerformanceRouting = true ;
440- _instrumentEmberRouter ( routerService , routerMain , config , customStartTransaction , startTransactionOnPageLoad ) ;
441- } ,
405+ const browserTracing = browserTracingIntegration ( {
442406 idleTimeout,
443407 ...browserTracingOptions ,
444408 } ) ;
445409
446- if ( macroCondition ( isTesting ( ) ) ) {
447- const client = Sentry . getClient ( ) ;
448-
449- if (
450- client &&
451- ( client as BrowserClient ) . getIntegrationByName &&
452- ( client as BrowserClient ) . getIntegrationByName ( 'BrowserTracing' )
453- ) {
454- // Initializers are called more than once in tests, causing the integrations to not be setup correctly.
455- return ;
456- }
457- }
410+ Sentry . disableDefaultBrowserTracingNavigationSpan ( ) ;
411+ Sentry . disableDefaultBrowserTracingPageLoadSpan ( ) ;
412+
413+ const client = Sentry . getClient < BrowserClient > ( ) ;
414+
415+ const isAlreadyInitialized = macroCondition ( isTesting ( ) ) ? ! ! client ?. getIntegrationByName ( 'BrowserTracing' ) : false ;
458416
459- const client = Sentry . getClient ( ) ;
460417 if ( client && client . addIntegration ) {
461418 client . addIntegration ( browserTracing ) ;
462419 }
463420
421+ // We _always_ call this, as it triggers the page load & navigation spans
422+ _instrumentNavigation ( appInstance , config ) ;
423+
424+ // Skip instrumenting the stuff below again in tests, as these are not reset between tests
425+ if ( isAlreadyInitialized ) {
426+ return ;
427+ }
428+
464429 _instrumentEmberRunloop ( config ) ;
465430 _instrumentComponents ( config ) ;
466431 _instrumentInitialLoad ( config ) ;
467432}
468433
434+ function _instrumentNavigation ( appInstance : ApplicationInstance , config : EmberSentryConfig ) : void {
435+ // eslint-disable-next-line ember/no-private-routing-service
436+ const routerMain = appInstance . lookup ( 'router:main' ) as EmberRouterMain ;
437+ let routerService = appInstance . lookup ( 'service:router' ) as RouterService & {
438+ externalRouter ?: RouterService ;
439+ _hasMountedSentryPerformanceRouting ?: boolean ;
440+ } ;
441+
442+ if ( routerService . externalRouter ) {
443+ // Using ember-engines-router-service in an engine.
444+ routerService = routerService . externalRouter ;
445+ }
446+ if ( routerService . _hasMountedSentryPerformanceRouting ) {
447+ // Routing listens to route changes on the main router, and should not be initialized multiple times per page.
448+ return ;
449+ }
450+ if ( ! routerService . recognize ) {
451+ // Router is missing critical functionality to limit cardinality of the transaction names.
452+ return ;
453+ }
454+
455+ routerService . _hasMountedSentryPerformanceRouting = true ;
456+ _instrumentEmberRouter ( routerService , routerMain , config ) ;
457+ }
458+
469459export default {
470460 initialize,
471461} ;
0 commit comments