Skip to content

Commit b46a735

Browse files
authored
fix(ember): Ensure unnecessary spans are avoided (#11846)
Extracted out from #11827. I added tests for loading & error states as well, to ensure this does not regress.
1 parent 40f30d5 commit b46a735

File tree

14 files changed

+117
-4
lines changed

14 files changed

+117
-4
lines changed

packages/ember/addon/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { getOwnConfig, isDevelopingApp, macroCondition } from '@embroider/macros
55
import { startSpan } from '@sentry/browser';
66
import type { BrowserOptions } from '@sentry/browser';
77
import * as Sentry from '@sentry/browser';
8-
import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, applySdkMetadata } from '@sentry/core';
8+
import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, applySdkMetadata } from '@sentry/core';
99
import { GLOBAL_OBJ } from '@sentry/utils';
1010
import Ember from 'ember';
1111

@@ -75,9 +75,11 @@ export const instrumentRoutePerformance = <T extends RouteConstructor>(BaseRoute
7575
{
7676
attributes: {
7777
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,
78+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.ember',
7879
},
7980
op,
8081
name,
82+
onlyIfParent: true,
8183
},
8284
() => {
8385
return fn(...args);

packages/ember/addon/instance-initializers/sentry-performance.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,12 @@ export function _instrumentEmberRouter(
145145

146146
routerService.on('routeWillChange', (transition: Transition) => {
147147
const { fromRoute, toRoute } = getTransitionInformation(transition, routerService);
148+
149+
// We want to ignore loading && error routes
150+
if (transitionIsIntermediate(transition)) {
151+
return;
152+
}
153+
148154
activeRootSpan?.end();
149155

150156
activeRootSpan = startBrowserTracingNavigationSpan(client, {
@@ -167,8 +173,8 @@ export function _instrumentEmberRouter(
167173
});
168174
});
169175

170-
routerService.on('routeDidChange', () => {
171-
if (!transitionSpan || !activeRootSpan) {
176+
routerService.on('routeDidChange', transition => {
177+
if (!transitionSpan || !activeRootSpan || transitionIsIntermediate(transition)) {
172178
return;
173179
}
174180
transitionSpan.end();
@@ -492,3 +498,18 @@ function _instrumentNavigation(
492498
export default {
493499
initialize,
494500
};
501+
502+
function transitionIsIntermediate(transition: Transition): boolean {
503+
// We want to use ignore, as this may actually be defined on new versions
504+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
505+
// @ts-ignore This actually exists on newer versions
506+
const isIntermediate: boolean | undefined = transition.isIntermediate;
507+
508+
if (typeof isIntermediate === 'boolean') {
509+
return isIntermediate;
510+
}
511+
512+
// For versions without this, we look if the route is a `.loading` or `.error` route
513+
// This is not perfect and may false-positive in some cases, but it's the best we can do
514+
return transition.to?.localName === 'loading' || transition.to?.localName === 'error';
515+
}

packages/ember/tests/acceptance/sentry-performance-test.ts

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { click, visit } from '@ember/test-helpers';
1+
import { click, find, visit } from '@ember/test-helpers';
22
import { setupApplicationTest } from 'ember-qunit';
33
import { module, test } from 'qunit';
44

@@ -56,4 +56,45 @@ module('Acceptance | Sentry Performance', function (hooks) {
5656
},
5757
});
5858
});
59+
60+
test('Test page with loading state', async function (assert) {
61+
await visit('/with-loading');
62+
63+
assertSentryTransactionCount(assert, 1);
64+
assertSentryTransactions(assert, 0, {
65+
spans: [
66+
'ui.ember.transition | route:undefined -> route:with-loading.index',
67+
'ui.ember.route.before_model | with-loading.index',
68+
'ui.ember.route.model | with-loading.index',
69+
'ui.ember.route.after_model | with-loading.index',
70+
'ui.ember.route.setup_controller | with-loading.index',
71+
],
72+
transaction: 'route:with-loading.index',
73+
attributes: {
74+
fromRoute: undefined,
75+
toRoute: 'with-loading.index',
76+
},
77+
});
78+
});
79+
80+
test('Test page with error state', async function (assert) {
81+
await visit('/with-error');
82+
83+
// Ensure we are on error page
84+
assert.ok(find('#test-page-load-error'));
85+
86+
assertSentryTransactionCount(assert, 1);
87+
assertSentryTransactions(assert, 0, {
88+
spans: [
89+
'ui.ember.transition | route:undefined -> route:with-error.index',
90+
'ui.ember.route.before_model | with-error.index',
91+
'ui.ember.route.model | with-error.index',
92+
],
93+
transaction: 'route:with-error.index',
94+
attributes: {
95+
fromRoute: undefined,
96+
toRoute: 'with-error.index',
97+
},
98+
});
99+
});
59100
});

packages/ember/tests/dummy/app/router.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,12 @@ Router.map(function () {
1515
this.route('slow-loading-route', function () {
1616
this.route('index', { path: '/' });
1717
});
18+
19+
this.route('with-loading', function () {
20+
this.route('index', { path: '/' });
21+
});
22+
23+
this.route('with-error', function () {
24+
this.route('index', { path: '/' });
25+
});
1826
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import Route from '@ember/routing/route';
2+
3+
export default class WithErrorErrorRoute extends Route {
4+
public model(): void {
5+
// Just swallow the error...
6+
}
7+
8+
public setupController() {
9+
// Just swallow the error...
10+
}
11+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import Route from '@ember/routing/route';
2+
import { instrumentRoutePerformance } from '@sentry/ember';
3+
4+
class WithErrorIndexRoute extends Route {
5+
public model(): Promise<void> {
6+
return Promise.reject('Test error');
7+
}
8+
}
9+
10+
export default instrumentRoutePerformance(WithErrorIndexRoute);
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import Route from '@ember/routing/route';
2+
import { instrumentRoutePerformance } from '@sentry/ember';
3+
4+
import timeout from '../../helpers/utils';
5+
6+
class WithLoadingIndexRoute extends Route {
7+
public model(): Promise<void> {
8+
return timeout(1000);
9+
}
10+
}
11+
12+
export default instrumentRoutePerformance(WithLoadingIndexRoute);

packages/ember/tests/dummy/app/templates/application.hbs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
<Link @route='index'>Errors</Link>
1313
<Link @route='tracing'>Tracing</Link>
1414
<Link @route='replay'>Replay</Link>
15+
<Link @route='with-loading'>With Loading</Link>
16+
<Link @route='with-error'>With Error</Link>
1517
</div>
1618
<div class="content-container">
1719
{{outlet}}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{{outlet}}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<div id='test-page-load-error'>Error when loading the page!</div>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Page loaded!
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{{outlet}}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Page loaded!
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Loading page...

0 commit comments

Comments
 (0)