From 698513f992f4891735f613ff5b67900e16e4cb49 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 9 Sep 2026 22:05:19 +0200 Subject: [PATCH 1/2] feat(ember): Give component definition lookups their own span op Ember spans that resolve a component definition were using the `function` op, which infers a span description of "Function execution" and loses the component name. They now use `ui.resolve`, a new op proposed in getsentry/sentry-conventions#633. The op is hard-coded with a TODO until that lands and we can import the const. Route hook spans keep the route as `sentry.description` and are named after the hook when span streaming is on, so the name matches `code.function.name` (the `function` op's name template) in both trace lifecycles. Also converts the `ember-classic` E2E app to span streaming and turns on `enableComponentDefinitions` there, so `ui.resolve` gets covered. That flag was off in every app, so the code path had never run in CI. `ember-embroider` and `ember-vite` still cover the static lifecycle. Co-Authored-By: Claude Opus 5 (1M context) --- MIGRATION.md | 15 ++-- .../sentry-performance.ts | 2 + .../ember-classic/tests/performance.test.ts | 47 ++++++++-- .../ember-embroider/tests/performance.test.ts | 18 ++-- .../tests/streamed-performance.test.ts | 20 +++++ .../ember/src/utils/instrumentEmberGlobals.ts | 6 +- .../src/utils/instrumentRoutePerformance.ts | 12 ++- .../tests/instrument-ember-globals.test.ts | 86 +++++++++++++++++++ .../instrument-route-performance.test.ts | 64 ++++++++++++++ 9 files changed, 245 insertions(+), 25 deletions(-) create mode 100644 packages/ember/tests/instrument-ember-globals.test.ts diff --git a/MIGRATION.md b/MIGRATION.md index fd236135ae68..a1336ea46359 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -881,13 +881,13 @@ These changes are not caught by TypeScript. If you filter, group, or alert on sp **Frontend & UI:** -| Area | Before | After | -| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------- | -| Frontend routing | `ui.angular.routing`, `ui.sveltekit.routing`, `ui.ember.transition` | `router` | -| React, Vue & Svelte component lifecycles | `ui.react.mount`/`render`/`update`, `ui.svelte.init`/`update`, Vue `render`/`update`/`mount`/`create`/`activate`/`unmount`/`destroy` | `ui.mount`, `ui.render`, `ui.update`, `ui.unmount` | -| Angular tracing decorators | `ui.angular.init` (`TraceDirective`/`TraceClass`), `ui.angular.` (`TraceMethod`) | `ui.mount`, `function` | -| Ember route hooks, runloop & components | `ui.ember.route.`, `ui.ember.runloop.`, `ui.ember.component.render`/`definition`/`init` | `function`, `ui.task`, `ui.render`/`function`/`ui.mount` | -| Browser paint entries | `paint` | `browser.paint` | +| Area | Before | After | +| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------- | +| Frontend routing | `ui.angular.routing`, `ui.sveltekit.routing`, `ui.ember.transition` | `router` | +| React, Vue & Svelte component lifecycles | `ui.react.mount`/`render`/`update`, `ui.svelte.init`/`update`, Vue `render`/`update`/`mount`/`create`/`activate`/`unmount`/`destroy` | `ui.mount`, `ui.render`, `ui.update`, `ui.unmount` | +| Angular tracing decorators | `ui.angular.init` (`TraceDirective`/`TraceClass`), `ui.angular.` (`TraceMethod`) | `ui.mount`, `function` | +| Ember route hooks, runloop & components | `ui.ember.route.`, `ui.ember.runloop.`, `ui.ember.component.render`/`definition`/`init` | `function`, `ui.task`, `ui.render`/`ui.resolve`/`ui.mount` | +| Browser paint entries | `paint` | `browser.paint` | **Databases, cache & messaging:** @@ -1003,6 +1003,7 @@ The following span names were adjusted: | `router` | Framework-specific, sometimes containing the raw URL | `/users/123`, `SvelteKit Route Change` | The span's `http.route`, or `Router` if the SDK has none | `/users/:id`, `Router` | | `handler` | Framework-specific, often carrying the request method | `GET /users/:id`, `route-handler`, `getUser` | The span's `http.route`, or `Request handler` if the SDK has none | `/users/:id`, `Request handler` | | `function` (Angular `TraceMethod`) | The decorator's `name` option in angle brackets | ``, `` | The decorator's `name` option, or `Function execution` if it has none | `Login.ngOnInit`, `getUsers`, `Function execution` | +| `function` (Ember route hooks) | The full route name | `slow-loading-route.index` | The hook the span wraps, matching its `code.function.name`. The route moves to `sentry.description` | `beforeModel`, `model`, `setupController` | | `function.gcp` | The request method and path for HTTP functions, otherwise the trigger's event or trigger type | `POST /users`, `google.pubsub.topic.publish`, `firebase.function.http.request` | The function name, or `Serverless function execution` if the SDK cannot resolve one | `myFunction`, `Serverless function execution` | | `function.aws` | The Lambda function name | `my-function` | Unchanged, except that the SDK now falls back to `Serverless function execution` if it cannot resolve the function name | `my-function`, `Serverless function execution` | | `graphql` | The graphql phase and, for operations, the operation name | `query GetUser`, `graphql.parse`, `graphql.resolve user.0.name` | The operation type, or the processing type where there is none | `GraphQL query`, `GraphQL parse`, `GraphQL resolve` | diff --git a/dev-packages/e2e-tests/test-applications/ember-classic/app/instance-initializers/sentry-performance.ts b/dev-packages/e2e-tests/test-applications/ember-classic/app/instance-initializers/sentry-performance.ts index b7c3f70b1e30..844f038aeeef 100644 --- a/dev-packages/e2e-tests/test-applications/ember-classic/app/instance-initializers/sentry-performance.ts +++ b/dev-packages/e2e-tests/test-applications/ember-classic/app/instance-initializers/sentry-performance.ts @@ -5,6 +5,8 @@ export function initialize(appInstance: ApplicationInstance): void { instrumentAppInstancePerformance(appInstance, { minimumRunloopQueueDuration: 0, minimumComponentRenderDuration: 0, + // Off by default, enabled here so the suite covers `ui.resolve` spans. + enableComponentDefinitions: true, }); } diff --git a/dev-packages/e2e-tests/test-applications/ember-classic/tests/performance.test.ts b/dev-packages/e2e-tests/test-applications/ember-classic/tests/performance.test.ts index 5875a4483ae1..e9ff45718ab9 100644 --- a/dev-packages/e2e-tests/test-applications/ember-classic/tests/performance.test.ts +++ b/dev-packages/e2e-tests/test-applications/ember-classic/tests/performance.test.ts @@ -178,17 +178,19 @@ test('captures correct spans for navigation', async ({ page }) => { expect(beforeModelSpans).toEqual( expect.arrayContaining([ expect.objectContaining({ - name: 'slow-loading-route', + name: 'beforeModel', attributes: expect.objectContaining({ 'code.function.name': { type: 'string', value: 'beforeModel' }, + 'sentry.description': { type: 'string', value: 'slow-loading-route' }, 'sentry.op': { type: 'string', value: 'function' }, 'sentry.origin': { type: 'string', value: 'auto.ui.ember' }, }), }), expect.objectContaining({ - name: 'slow-loading-route.index', + name: 'beforeModel', attributes: expect.objectContaining({ 'code.function.name': { type: 'string', value: 'beforeModel' }, + 'sentry.description': { type: 'string', value: 'slow-loading-route.index' }, 'sentry.op': { type: 'string', value: 'function' }, 'sentry.origin': { type: 'string', value: 'auto.ui.ember' }, }), @@ -199,15 +201,17 @@ test('captures correct spans for navigation', async ({ page }) => { expect(modelSpans).toEqual( expect.arrayContaining([ expect.objectContaining({ - name: 'slow-loading-route', + name: 'model', attributes: expect.objectContaining({ 'code.function.name': { type: 'string', value: 'model' }, + 'sentry.description': { type: 'string', value: 'slow-loading-route' }, }), }), expect.objectContaining({ - name: 'slow-loading-route.index', + name: 'model', attributes: expect.objectContaining({ 'code.function.name': { type: 'string', value: 'model' }, + 'sentry.description': { type: 'string', value: 'slow-loading-route.index' }, }), }), ]), @@ -216,15 +220,17 @@ test('captures correct spans for navigation', async ({ page }) => { expect(afterModelSpans).toEqual( expect.arrayContaining([ expect.objectContaining({ - name: 'slow-loading-route', + name: 'afterModel', attributes: expect.objectContaining({ 'code.function.name': { type: 'string', value: 'afterModel' }, + 'sentry.description': { type: 'string', value: 'slow-loading-route' }, }), }), expect.objectContaining({ - name: 'slow-loading-route.index', + name: 'afterModel', attributes: expect.objectContaining({ 'code.function.name': { type: 'string', value: 'afterModel' }, + 'sentry.description': { type: 'string', value: 'slow-loading-route.index' }, }), }), ]), @@ -243,3 +249,32 @@ test('captures correct spans for navigation', async ({ page }) => { ]), ); }); + +test('captures a `ui.resolve` span alongside the `ui.render` span for a component', async ({ page }) => { + const spansPromise = collectStreamedSpans('ember-classic', spans => { + return spans.some(span => getSpanOp(span) === 'ui.resolve') && spans.some(span => getSpanOp(span) === 'ui.render'); + }); + + await page.goto(`/tracing`); + + const spans = await spansPromise; + + const resolveSpan = spans.find(span => getSpanOp(span) === 'ui.resolve')!; + const renderSpan = spans.find(span => getSpanOp(span) === 'ui.render')!; + + expect(resolveSpan).toMatchObject({ + attributes: expect.objectContaining({ + 'sentry.op': { type: 'string', value: 'ui.resolve' }, + 'sentry.origin': { type: 'string', value: 'auto.ui.ember' }, + 'ui.component_name': { type: 'string', value: resolveSpan.name }, + }), + }); + + expect(renderSpan).toMatchObject({ + attributes: expect.objectContaining({ + 'sentry.op': { type: 'string', value: 'ui.render' }, + 'sentry.origin': { type: 'string', value: 'auto.ui.ember' }, + 'ui.component_name': { type: 'string', value: renderSpan.name }, + }), + }); +}); diff --git a/dev-packages/e2e-tests/test-applications/ember-embroider/tests/performance.test.ts b/dev-packages/e2e-tests/test-applications/ember-embroider/tests/performance.test.ts index 4de378600e6c..1cf6c9827b24 100644 --- a/dev-packages/e2e-tests/test-applications/ember-embroider/tests/performance.test.ts +++ b/dev-packages/e2e-tests/test-applications/ember-embroider/tests/performance.test.ts @@ -178,17 +178,19 @@ test('captures correct spans for navigation', async ({ page }) => { expect(beforeModelSpans).toEqual( expect.arrayContaining([ expect.objectContaining({ - name: 'slow-loading-route', + name: 'beforeModel', attributes: expect.objectContaining({ 'code.function.name': { type: 'string', value: 'beforeModel' }, + 'sentry.description': { type: 'string', value: 'slow-loading-route' }, 'sentry.op': { type: 'string', value: 'function' }, 'sentry.origin': { type: 'string', value: 'auto.ui.ember' }, }), }), expect.objectContaining({ - name: 'slow-loading-route.index', + name: 'beforeModel', attributes: expect.objectContaining({ 'code.function.name': { type: 'string', value: 'beforeModel' }, + 'sentry.description': { type: 'string', value: 'slow-loading-route.index' }, 'sentry.op': { type: 'string', value: 'function' }, 'sentry.origin': { type: 'string', value: 'auto.ui.ember' }, }), @@ -199,15 +201,17 @@ test('captures correct spans for navigation', async ({ page }) => { expect(modelSpans).toEqual( expect.arrayContaining([ expect.objectContaining({ - name: 'slow-loading-route', + name: 'model', attributes: expect.objectContaining({ 'code.function.name': { type: 'string', value: 'model' }, + 'sentry.description': { type: 'string', value: 'slow-loading-route' }, }), }), expect.objectContaining({ - name: 'slow-loading-route.index', + name: 'model', attributes: expect.objectContaining({ 'code.function.name': { type: 'string', value: 'model' }, + 'sentry.description': { type: 'string', value: 'slow-loading-route.index' }, }), }), ]), @@ -216,15 +220,17 @@ test('captures correct spans for navigation', async ({ page }) => { expect(afterModelSpans).toEqual( expect.arrayContaining([ expect.objectContaining({ - name: 'slow-loading-route', + name: 'afterModel', attributes: expect.objectContaining({ 'code.function.name': { type: 'string', value: 'afterModel' }, + 'sentry.description': { type: 'string', value: 'slow-loading-route' }, }), }), expect.objectContaining({ - name: 'slow-loading-route.index', + name: 'afterModel', attributes: expect.objectContaining({ 'code.function.name': { type: 'string', value: 'afterModel' }, + 'sentry.description': { type: 'string', value: 'slow-loading-route.index' }, }), }), ]), diff --git a/dev-packages/e2e-tests/test-applications/ember-strict-resolver/tests/streamed-performance.test.ts b/dev-packages/e2e-tests/test-applications/ember-strict-resolver/tests/streamed-performance.test.ts index bd6405989474..e66312a19316 100644 --- a/dev-packages/e2e-tests/test-applications/ember-strict-resolver/tests/streamed-performance.test.ts +++ b/dev-packages/e2e-tests/test-applications/ember-strict-resolver/tests/streamed-performance.test.ts @@ -17,3 +17,23 @@ test('names the transition span with the low cardinality fallback', async ({ pag expect(transitionSpan.name).toBe('Router'); expect(transitionSpan.attributes['sentry.origin']).toEqual({ type: 'string', value: 'auto.ui.ember' }); }); + +test('names route hook spans after the hook and keeps the route as the description', async ({ page }) => { + const modelSpanPromise = waitForStreamedSpan( + 'ember-strict-resolver', + span => + getSpanOp(span) === 'function' && + span.attributes['code.function.name']?.value === 'model' && + span.attributes['sentry.description']?.value === 'slow-loading-route.index', + ); + + await page.goto('/tracing'); + await page.getByText('Transition to slow loading route').click(); + + const modelSpan = await modelSpanPromise; + + expect(modelSpan.name).toBe('model'); + expect(modelSpan.attributes['code.function.name']).toEqual({ type: 'string', value: 'model' }); + expect(modelSpan.attributes['sentry.description']).toEqual({ type: 'string', value: 'slow-loading-route.index' }); + expect(modelSpan.attributes['sentry.origin']).toEqual({ type: 'string', value: 'auto.ui.ember' }); +}); diff --git a/packages/ember/src/utils/instrumentEmberGlobals.ts b/packages/ember/src/utils/instrumentEmberGlobals.ts index 6d19479af04c..a7b6fe761a30 100644 --- a/packages/ember/src/utils/instrumentEmberGlobals.ts +++ b/packages/ember/src/utils/instrumentEmberGlobals.ts @@ -1,7 +1,7 @@ import { subscribe } from '@ember/instrumentation'; import { scheduleOnce } from '@ember/runloop'; import { SENTRY_OP, UI_COMPONENT_NAME } from '@sentry/conventions/attributes'; -import { UI_MOUNT, UI_RENDER, UI_TASK, FUNCTION } from '@sentry/conventions/op'; +import { UI_MOUNT, UI_RENDER, UI_TASK } from '@sentry/conventions/op'; import { getActiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startInactiveSpan } from '@sentry/browser'; import type { Span } from '@sentry/core'; import { browserPerformanceTimeOrigin, timestampInSeconds } from '@sentry/core'; @@ -193,7 +193,9 @@ function _instrumentComponents(config: { }, after(_name: string, _timestamp: number, payload: object) { - _processComponentRenderAfter(payload as Payload, beforeComponentDefinitionEntries, FUNCTION, 0); + // TODO: Use the `UI_RESOLVE` const from `@sentry/conventions/op` once the op is released. + // See https://github.com/getsentry/sentry-conventions/pull/633 + _processComponentRenderAfter(payload as Payload, beforeComponentDefinitionEntries, 'ui.resolve', 0); }, }); } diff --git a/packages/ember/src/utils/instrumentRoutePerformance.ts b/packages/ember/src/utils/instrumentRoutePerformance.ts index 080326bab3ce..2757972d0e91 100644 --- a/packages/ember/src/utils/instrumentRoutePerformance.ts +++ b/packages/ember/src/utils/instrumentRoutePerformance.ts @@ -1,7 +1,7 @@ import { startSpan } from '@sentry/browser'; -import { CODE_FUNCTION_NAME, SENTRY_OP } from '@sentry/conventions/attributes'; +import { CODE_FUNCTION_NAME, SENTRY_DESCRIPTION, SENTRY_OP } from '@sentry/conventions/attributes'; import { FUNCTION } from '@sentry/conventions/op'; -import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core'; +import { getClient, hasSpanStreamingEnabled, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core'; import type Route from '@ember/routing/route'; @@ -33,19 +33,23 @@ type RouteConstructor = new (...args: ConstructorParameters) => Ro export function instrumentRoutePerformance(BaseRoute: T): T { const instrumentFunction = async ( hookName: string, - name: string, + fullRouteName: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Route hooks have varied signatures that can't be unified with unknown fn: (...args: any[]) => any, args: unknown[], ): Promise => { + const client = getClient(); + const isStreaming = !!client && hasSpanStreamingEnabled(client); return startSpan( { attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.ember', [SENTRY_OP]: FUNCTION, [CODE_FUNCTION_NAME]: hookName, + // A streamed span is named after the hook, so the route it belongs to only survives here. + ...(isStreaming && { [SENTRY_DESCRIPTION]: fullRouteName }), }, - name, + name: isStreaming ? hookName : fullRouteName, onlyIfParent: true, }, () => { diff --git a/packages/ember/tests/instrument-ember-globals.test.ts b/packages/ember/tests/instrument-ember-globals.test.ts new file mode 100644 index 000000000000..2c7b6e90966d --- /dev/null +++ b/packages/ember/tests/instrument-ember-globals.test.ts @@ -0,0 +1,86 @@ +import { subscribe } from '@ember/instrumentation'; +import { startInactiveSpan } from '@sentry/browser'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +type Subscriber = { + before: (name: string, timestamp: number, payload: object) => void; + after: (name: string, timestamp: number, payload: object) => void; +}; + +vi.mock('@ember/instrumentation', () => ({ subscribe: vi.fn() })); +vi.mock('@ember/runloop', () => ({ scheduleOnce: vi.fn(), _backburner: undefined, run: {} })); +vi.mock('@sentry/browser', () => ({ + getActiveSpan: vi.fn(() => undefined), + startInactiveSpan: vi.fn(() => ({ end: vi.fn() })), + SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN: 'sentry.origin', +})); + +function getSubscriber(eventName: string): Subscriber | undefined { + const call = vi.mocked(subscribe).mock.calls.find(([name]) => name === eventName); + return call?.[1] as Subscriber | undefined; +} + +async function instrumentComponents(enableComponentDefinitions: boolean): Promise { + const { instrumentGlobalsForPerformance } = await import('../src/utils/instrumentEmberGlobals.ts'); + instrumentGlobalsForPerformance({ + disableRunloopPerformance: true, + disableInitialLoadInstrumentation: true, + // The renders below take ~0ms, so drop the threshold that would skip them. + minimumComponentRenderDuration: 0, + enableComponentDefinitions, + }); +} + +describe('component instrumentation', () => { + const payload = { containerKey: 'component:test-component', initialRender: true as const, object: '' }; + + beforeEach(() => { + vi.clearAllMocks(); + vi.resetModules(); + }); + + it('starts a `ui.render` span for a component render', async () => { + await instrumentComponents(false); + + const subscriber = getSubscriber('render.component'); + subscriber?.before('render.component', 0, payload); + subscriber?.after('render.component', 0, payload); + + expect(startInactiveSpan).toHaveBeenCalledWith( + expect.objectContaining({ + name: 'component:test-component', + attributes: expect.objectContaining({ + 'sentry.op': 'ui.render', + 'sentry.origin': 'auto.ui.ember', + 'ui.component_name': 'component:test-component', + }), + }), + ); + }); + + it('starts a `ui.resolve` span for a component definition lookup', async () => { + await instrumentComponents(true); + + const subscriber = getSubscriber('render.getComponentDefinition'); + subscriber?.before('render.getComponentDefinition', 0, payload); + subscriber?.after('render.getComponentDefinition', 0, payload); + + expect(startInactiveSpan).toHaveBeenCalledWith( + expect.objectContaining({ + name: 'component:test-component', + attributes: expect.objectContaining({ + 'sentry.op': 'ui.resolve', + 'sentry.origin': 'auto.ui.ember', + 'ui.component_name': 'component:test-component', + }), + }), + ); + }); + + it('does not subscribe to component definition lookups unless they are enabled', async () => { + await instrumentComponents(false); + + expect(getSubscriber('render.getComponentDefinition')).toBeUndefined(); + expect(getSubscriber('render.component')).toBeDefined(); + }); +}); diff --git a/packages/ember/tests/instrument-route-performance.test.ts b/packages/ember/tests/instrument-route-performance.test.ts index 3f0bee0321fb..d7a06bc5d6ea 100644 --- a/packages/ember/tests/instrument-route-performance.test.ts +++ b/packages/ember/tests/instrument-route-performance.test.ts @@ -1,5 +1,6 @@ import type Route from '@ember/routing/route'; import { startSpan } from '@sentry/browser'; +import { hasSpanStreamingEnabled } from '@sentry/core'; import { describe, expect, it, vi } from 'vitest'; vi.mock('@sentry/browser', () => ({ @@ -7,6 +8,8 @@ vi.mock('@sentry/browser', () => ({ })); vi.mock('@sentry/core', () => ({ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN: 'sentry.origin', + getClient: vi.fn(() => ({})), + hasSpanStreamingEnabled: vi.fn(() => false), })); describe('instrumentRoutePerformance', () => { @@ -62,4 +65,65 @@ describe('instrumentRoutePerformance', () => { expect(startSpan).toHaveBeenCalledTimes(4); }); + + it('names the span after the route when span streaming is disabled', async () => { + const { instrumentRoutePerformance } = await import('../src/utils/instrumentRoutePerformance.ts'); + + class DummyRoute { + public fullRouteName = 'dummy'; + + public model(): void {} + } + + const InstrumentedDummyRoute = instrumentRoutePerformance( + DummyRoute as unknown as new (...args: unknown[]) => Route, + ); + + await new InstrumentedDummyRoute().model(); + + expect(startSpan).toHaveBeenCalledWith( + { + attributes: { + 'sentry.origin': 'auto.ui.ember', + 'sentry.op': 'function', + 'code.function.name': 'model', + }, + name: 'dummy', + onlyIfParent: true, + }, + expect.any(Function), + ); + }); + + it('names the span after the hook and describes it with the route when span streaming is enabled', async () => { + vi.mocked(hasSpanStreamingEnabled).mockReturnValueOnce(true); + + const { instrumentRoutePerformance } = await import('../src/utils/instrumentRoutePerformance.ts'); + + class DummyRoute { + public fullRouteName = 'dummy'; + + public model(): void {} + } + + const InstrumentedDummyRoute = instrumentRoutePerformance( + DummyRoute as unknown as new (...args: unknown[]) => Route, + ); + + await new InstrumentedDummyRoute().model(); + + expect(startSpan).toHaveBeenCalledWith( + { + attributes: { + 'sentry.origin': 'auto.ui.ember', + 'sentry.op': 'function', + 'code.function.name': 'model', + 'sentry.description': 'dummy', + }, + name: 'model', + onlyIfParent: true, + }, + expect.any(Function), + ); + }); }); From f102a7e7307bcb89792bfc6b2c27d3a44a2ff7c9 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 11 Sep 2026 17:28:42 +0200 Subject: [PATCH 2/2] Update packages/ember/src/utils/instrumentRoutePerformance.ts --- packages/ember/src/utils/instrumentRoutePerformance.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/ember/src/utils/instrumentRoutePerformance.ts b/packages/ember/src/utils/instrumentRoutePerformance.ts index 2757972d0e91..1515c7ed3f90 100644 --- a/packages/ember/src/utils/instrumentRoutePerformance.ts +++ b/packages/ember/src/utils/instrumentRoutePerformance.ts @@ -46,7 +46,6 @@ export function instrumentRoutePerformance(BaseRoute [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.ember', [SENTRY_OP]: FUNCTION, [CODE_FUNCTION_NAME]: hookName, - // A streamed span is named after the hook, so the route it belongs to only survives here. ...(isStreaming && { [SENTRY_DESCRIPTION]: fullRouteName }), }, name: isStreaming ? hookName : fullRouteName,