@sentry/ember 10.70.0 → 11.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.oxlintrc.json +0 -6
- package/addon/index.ts +9 -18
- package/addon/utils/instrumentEmberAppInstanceForPerformance.ts +3 -2
- package/addon/utils/instrumentEmberGlobals.ts +26 -22
- package/addon/utils/performance.ts +1 -1
- package/package.json +8 -7
- package/tsconfig.json +7 -8
- package/utils/instrumentEmberGlobals.d.ts +12 -0
package/.oxlintrc.json
CHANGED
package/addon/index.ts
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
import { assert } from '@ember/debug';
|
|
5
5
|
import type Route from '@ember/routing/route';
|
|
6
6
|
import { getOwnConfig } from '@embroider/macros';
|
|
7
|
+
import { CODE_FUNCTION_NAME, SENTRY_OP } from '@sentry/conventions/attributes';
|
|
8
|
+
import { GENERAL_FUNCTION_SPAN_OP } from '@sentry/conventions/op';
|
|
7
9
|
import type { BrowserOptions } from '@sentry/browser';
|
|
8
10
|
import { startSpan } from '@sentry/browser';
|
|
9
11
|
import * as Sentry from '@sentry/browser';
|
|
@@ -54,7 +56,7 @@ type RouteConstructor = new (...args: ConstructorParameters<typeof Route>) => Ro
|
|
|
54
56
|
export const instrumentRoutePerformance = <T extends RouteConstructor>(BaseRoute: T): T => {
|
|
55
57
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
56
58
|
const instrumentFunction = async <X extends (...args: unknown[]) => any>(
|
|
57
|
-
|
|
59
|
+
hookName: string,
|
|
58
60
|
name: string,
|
|
59
61
|
fn: X,
|
|
60
62
|
args: Parameters<X>,
|
|
@@ -65,8 +67,9 @@ export const instrumentRoutePerformance = <T extends RouteConstructor>(BaseRoute
|
|
|
65
67
|
attributes: {
|
|
66
68
|
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,
|
|
67
69
|
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.ember',
|
|
70
|
+
[SENTRY_OP]: GENERAL_FUNCTION_SPAN_OP,
|
|
71
|
+
[CODE_FUNCTION_NAME]: hookName,
|
|
68
72
|
},
|
|
69
|
-
op,
|
|
70
73
|
name,
|
|
71
74
|
onlyIfParent: true,
|
|
72
75
|
},
|
|
@@ -82,32 +85,20 @@ export const instrumentRoutePerformance = <T extends RouteConstructor>(BaseRoute
|
|
|
82
85
|
// @ts-expect-error TS2545 We do not need to redefine a constructor here
|
|
83
86
|
[routeName]: class extends BaseRoute {
|
|
84
87
|
public beforeModel(...args: unknown[]): void | Promise<unknown> {
|
|
85
|
-
return instrumentFunction(
|
|
86
|
-
'ui.ember.route.before_model',
|
|
87
|
-
this.fullRouteName,
|
|
88
|
-
super.beforeModel.bind(this),
|
|
89
|
-
args,
|
|
90
|
-
'custom',
|
|
91
|
-
);
|
|
88
|
+
return instrumentFunction('beforeModel', this.fullRouteName, super.beforeModel.bind(this), args, 'custom');
|
|
92
89
|
}
|
|
93
90
|
|
|
94
91
|
public async model(...args: unknown[]): Promise<unknown> {
|
|
95
|
-
return instrumentFunction('
|
|
92
|
+
return instrumentFunction('model', this.fullRouteName, super.model.bind(this), args, 'custom');
|
|
96
93
|
}
|
|
97
94
|
|
|
98
95
|
public afterModel(...args: unknown[]): void | Promise<unknown> {
|
|
99
|
-
return instrumentFunction(
|
|
100
|
-
'ui.ember.route.after_model',
|
|
101
|
-
this.fullRouteName,
|
|
102
|
-
super.afterModel.bind(this),
|
|
103
|
-
args,
|
|
104
|
-
'custom',
|
|
105
|
-
);
|
|
96
|
+
return instrumentFunction('afterModel', this.fullRouteName, super.afterModel.bind(this), args, 'custom');
|
|
106
97
|
}
|
|
107
98
|
|
|
108
99
|
public setupController(...args: unknown[]): void | Promise<unknown> {
|
|
109
100
|
return instrumentFunction(
|
|
110
|
-
'
|
|
101
|
+
'setupController',
|
|
111
102
|
this.fullRouteName,
|
|
112
103
|
super.setupController.bind(this),
|
|
113
104
|
args,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
import type { Client, Span } from '@sentry/core';
|
|
15
15
|
import type { EmberRouterMain } from '../types';
|
|
16
16
|
import { getBackburner } from './performance';
|
|
17
|
-
import { URL_FULL, URL_PATH, URL_TEMPLATE } from '@sentry/conventions/attributes';
|
|
17
|
+
import { SENTRY_OP, URL_FULL, URL_PATH, URL_TEMPLATE } from '@sentry/conventions/attributes';
|
|
18
18
|
|
|
19
19
|
type TransitionWithIntent = Transition & { intent?: { url?: string } };
|
|
20
20
|
|
|
@@ -200,9 +200,10 @@ function _instrumentEmberRouter(
|
|
|
200
200
|
|
|
201
201
|
transitionSpan = startInactiveSpan({
|
|
202
202
|
attributes: {
|
|
203
|
+
// TODO(conventions): Replace `'router'` with the `router` span op constant once it is released in `@sentry/conventions`.
|
|
204
|
+
[SENTRY_OP]: 'router',
|
|
203
205
|
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.ember',
|
|
204
206
|
},
|
|
205
|
-
op: 'ui.ember.transition',
|
|
206
207
|
name: `route:${fromRoute} -> route:${toRoute}`,
|
|
207
208
|
onlyIfParent: true,
|
|
208
209
|
});
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { subscribe } from '@ember/instrumentation';
|
|
2
2
|
import { scheduleOnce } from '@ember/runloop';
|
|
3
3
|
import type { EmberRunQueues } from '@ember/runloop/-private/types';
|
|
4
|
+
import { SENTRY_OP, UI_COMPONENT_NAME } from '@sentry/conventions/attributes';
|
|
5
|
+
import { BROWSER_UI_RENDER_SPAN_OP, BROWSER_UI_TASK_SPAN_OP, GENERAL_FUNCTION_SPAN_OP } from '@sentry/conventions/op';
|
|
4
6
|
import { getActiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startInactiveSpan } from '@sentry/browser';
|
|
5
7
|
import type { Span } from '@sentry/core';
|
|
6
8
|
import { browserPerformanceTimeOrigin, timestampInSeconds } from '@sentry/core';
|
|
@@ -13,13 +15,10 @@ type Payload = {
|
|
|
13
15
|
};
|
|
14
16
|
|
|
15
17
|
type RenderEntry = {
|
|
16
|
-
payload: Payload;
|
|
17
18
|
now: number;
|
|
18
19
|
};
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
[name: string]: RenderEntry;
|
|
22
|
-
}
|
|
21
|
+
export type RenderEntries = WeakMap<Payload, RenderEntry>;
|
|
23
22
|
|
|
24
23
|
/** This is global, so should only be run once in tests! */
|
|
25
24
|
export function instrumentGlobalsForPerformance(config: {
|
|
@@ -89,10 +88,11 @@ function _instrumentEmberRunloop(config: { minimumRunloopQueueDuration?: number
|
|
|
89
88
|
if ((now - currentQueueStart) * 1000 >= minQueueDuration) {
|
|
90
89
|
startInactiveSpan({
|
|
91
90
|
attributes: {
|
|
91
|
+
[SENTRY_OP]: BROWSER_UI_TASK_SPAN_OP,
|
|
92
92
|
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.ember',
|
|
93
|
+
'ember.runloop.queue': queue,
|
|
93
94
|
},
|
|
94
95
|
name: 'runloop',
|
|
95
|
-
op: `ui.ember.runloop.${queue}`,
|
|
96
96
|
startTime: currentQueueStart,
|
|
97
97
|
onlyIfParent: true,
|
|
98
98
|
})?.end(now);
|
|
@@ -124,36 +124,39 @@ function _instrumentEmberRunloop(config: { minimumRunloopQueueDuration?: number
|
|
|
124
124
|
});
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
function
|
|
128
|
-
|
|
129
|
-
payload,
|
|
130
|
-
now: timestampInSeconds(),
|
|
131
|
-
};
|
|
132
|
-
beforeEntries[payload.object] = info;
|
|
127
|
+
export function _processComponentRenderBefore(payload: Payload, beforeEntries: RenderEntries): void {
|
|
128
|
+
beforeEntries.set(payload, { now: timestampInSeconds() });
|
|
133
129
|
}
|
|
134
130
|
|
|
135
|
-
function
|
|
131
|
+
export function _processComponentRenderAfter(
|
|
136
132
|
payload: Payload,
|
|
137
133
|
beforeEntries: RenderEntries,
|
|
138
134
|
op: string,
|
|
139
135
|
minComponentDuration: number,
|
|
140
136
|
): void {
|
|
141
|
-
const begin = beforeEntries
|
|
137
|
+
const begin = beforeEntries.get(payload);
|
|
142
138
|
|
|
143
139
|
if (!begin) {
|
|
144
140
|
return;
|
|
145
141
|
}
|
|
146
142
|
|
|
143
|
+
// A WeakMap entry cannot outlive its payload, but delete promptly anyway
|
|
144
|
+
// so a long-lived payload doesn't keep the entry around between renders.
|
|
145
|
+
beforeEntries.delete(payload);
|
|
146
|
+
|
|
147
147
|
const now = timestampInSeconds();
|
|
148
148
|
const componentRenderDuration = now - begin.now;
|
|
149
149
|
|
|
150
|
+
const name = payload.containerKey || payload.object;
|
|
151
|
+
|
|
150
152
|
if (componentRenderDuration * 1000 >= minComponentDuration) {
|
|
151
153
|
startInactiveSpan({
|
|
152
|
-
name
|
|
153
|
-
op,
|
|
154
|
+
name,
|
|
154
155
|
startTime: begin.now,
|
|
155
156
|
attributes: {
|
|
157
|
+
[SENTRY_OP]: op,
|
|
156
158
|
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.ember',
|
|
159
|
+
[UI_COMPONENT_NAME]: name,
|
|
157
160
|
},
|
|
158
161
|
onlyIfParent: true,
|
|
159
162
|
})?.end(now);
|
|
@@ -168,27 +171,27 @@ function _instrumentComponents(config: {
|
|
|
168
171
|
|
|
169
172
|
const minComponentDuration = minimumComponentRenderDuration ?? 2;
|
|
170
173
|
|
|
171
|
-
const beforeEntries =
|
|
172
|
-
const beforeComponentDefinitionEntries =
|
|
174
|
+
const beforeEntries: RenderEntries = new WeakMap();
|
|
175
|
+
const beforeComponentDefinitionEntries: RenderEntries = new WeakMap();
|
|
173
176
|
|
|
174
177
|
function _subscribeToRenderEvents(): void {
|
|
175
178
|
subscribe('render.component', {
|
|
176
179
|
before(_name: string, _timestamp: number, payload: Payload) {
|
|
177
|
-
|
|
180
|
+
_processComponentRenderBefore(payload, beforeEntries);
|
|
178
181
|
},
|
|
179
182
|
|
|
180
183
|
after(_name: string, _timestamp: number, payload: Payload, _beganIndex: number) {
|
|
181
|
-
|
|
184
|
+
_processComponentRenderAfter(payload, beforeEntries, BROWSER_UI_RENDER_SPAN_OP, minComponentDuration);
|
|
182
185
|
},
|
|
183
186
|
});
|
|
184
187
|
if (enableComponentDefinitions) {
|
|
185
188
|
subscribe('render.getComponentDefinition', {
|
|
186
189
|
before(_name: string, _timestamp: number, payload: Payload) {
|
|
187
|
-
|
|
190
|
+
_processComponentRenderBefore(payload, beforeComponentDefinitionEntries);
|
|
188
191
|
},
|
|
189
192
|
|
|
190
193
|
after(_name: string, _timestamp: number, payload: Payload, _beganIndex: number) {
|
|
191
|
-
|
|
194
|
+
_processComponentRenderAfter(payload, beforeComponentDefinitionEntries, GENERAL_FUNCTION_SPAN_OP, 0);
|
|
192
195
|
},
|
|
193
196
|
});
|
|
194
197
|
}
|
|
@@ -230,9 +233,10 @@ function _instrumentInitialLoad(): void {
|
|
|
230
233
|
const endTime = startTime + measure.duration / 1000;
|
|
231
234
|
|
|
232
235
|
startInactiveSpan({
|
|
233
|
-
op: 'ui.ember.init',
|
|
234
236
|
name: 'init',
|
|
235
237
|
attributes: {
|
|
238
|
+
// TODO(v11): Replace with the `ui.mount` constant from `@sentry/conventions/op` once it is registered there.
|
|
239
|
+
[SENTRY_OP]: 'ui.mount',
|
|
236
240
|
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.ember',
|
|
237
241
|
},
|
|
238
242
|
startTime,
|
|
@@ -22,7 +22,7 @@ export function getSentryConfig(): EmberSentryConfig {
|
|
|
22
22
|
|
|
23
23
|
export function getBackburner(): Pick<ExtendedBackburner, 'on' | 'off'> {
|
|
24
24
|
if (_backburner) {
|
|
25
|
-
return _backburner
|
|
25
|
+
return _backburner;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
if ((run as unknown as { backburner?: Pick<ExtendedBackburner, 'on' | 'off'> }).backburner) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/ember",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "11.0.0-alpha.1",
|
|
4
4
|
"description": "Official Sentry SDK for Ember.js",
|
|
5
5
|
"repository": "git://github.com/getsentry/sentry-javascript.git",
|
|
6
6
|
"homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/ember",
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
"clean": "yarn rimraf sentry-ember-*.tgz dist tmp build .node_modules.ember-try package.json.ember-try instance-initializers index.d.ts runloop.d.ts types.d.ts",
|
|
22
22
|
"lint": "run-p lint:js lint:hbs lint:ts",
|
|
23
23
|
"lint:hbs": "ember-template-lint .",
|
|
24
|
-
"lint:js": "
|
|
24
|
+
"lint:js": "oxlint . --type-aware",
|
|
25
25
|
"lint:ts": "tsc",
|
|
26
|
-
"lint:fix": "
|
|
26
|
+
"lint:fix": "oxlint . --fix --type-aware",
|
|
27
27
|
"start": "ember serve",
|
|
28
28
|
"test": "ember b --prod && ember test",
|
|
29
29
|
"prepack": "ember ts:precompile",
|
|
@@ -32,9 +32,9 @@
|
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@babel/core": "^7.29.6",
|
|
34
34
|
"@embroider/macros": "^1.16.0",
|
|
35
|
-
"@sentry/browser": "
|
|
36
|
-
"@sentry/core": "
|
|
37
|
-
"@sentry/conventions": "^0.
|
|
35
|
+
"@sentry/browser": "11.0.0-alpha.1",
|
|
36
|
+
"@sentry/core": "11.0.0-alpha.1",
|
|
37
|
+
"@sentry/conventions": "^0.19.0",
|
|
38
38
|
"ember-auto-import": "^2.7.2",
|
|
39
39
|
"ember-cli-babel": "^8.2.0",
|
|
40
40
|
"ember-cli-htmlbars": "^6.1.1",
|
|
@@ -78,10 +78,11 @@
|
|
|
78
78
|
"qunit": "~2.22.0",
|
|
79
79
|
"qunit-dom": "~3.5.0",
|
|
80
80
|
"sinon": "21.0.1",
|
|
81
|
+
"typescript": "~5.8.0",
|
|
81
82
|
"webpack": "~5.104.1"
|
|
82
83
|
},
|
|
83
84
|
"engines": {
|
|
84
|
-
"node": ">=
|
|
85
|
+
"node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0"
|
|
85
86
|
},
|
|
86
87
|
"ember": {
|
|
87
88
|
"edition": "octane"
|
package/tsconfig.json
CHANGED
|
@@ -10,16 +10,15 @@
|
|
|
10
10
|
"strictPropertyInitialization": true,
|
|
11
11
|
"noEmitOnError": false,
|
|
12
12
|
"noEmit": true,
|
|
13
|
-
"baseUrl": ".",
|
|
14
13
|
"experimentalDecorators": true,
|
|
15
14
|
"paths": {
|
|
16
|
-
"dummy/tests/*": ["tests/*"],
|
|
17
|
-
"dummy/*": ["tests/dummy/app/*", "app/*"],
|
|
18
|
-
"@sentry/ember": ["addon"],
|
|
19
|
-
"@sentry/ember/*": ["addon/*"],
|
|
20
|
-
"@sentry/ember/test-support": ["addon-test-support"],
|
|
21
|
-
"@sentry/ember/test-support/*": ["addon-test-support/*"],
|
|
22
|
-
"*": ["types/*"]
|
|
15
|
+
"dummy/tests/*": ["./tests/*"],
|
|
16
|
+
"dummy/*": ["./tests/dummy/app/*", "./app/*"],
|
|
17
|
+
"@sentry/ember": ["./addon"],
|
|
18
|
+
"@sentry/ember/*": ["./addon/*"],
|
|
19
|
+
"@sentry/ember/test-support": ["./addon-test-support"],
|
|
20
|
+
"@sentry/ember/test-support/*": ["./addon-test-support/*"],
|
|
21
|
+
"*": ["./types/*"]
|
|
23
22
|
}
|
|
24
23
|
},
|
|
25
24
|
"include": ["app/**/*", "addon/**/*", "tests/**/*", "types/**/*", "test-support/**/*", "addon-test-support/**/*"]
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
type Payload = {
|
|
2
|
+
containerKey: string;
|
|
3
|
+
initialRender: true;
|
|
4
|
+
object: string;
|
|
5
|
+
};
|
|
6
|
+
type RenderEntry = {
|
|
7
|
+
now: number;
|
|
8
|
+
};
|
|
9
|
+
export type RenderEntries = WeakMap<Payload, RenderEntry>;
|
|
1
10
|
/** This is global, so should only be run once in tests! */
|
|
2
11
|
export declare function instrumentGlobalsForPerformance(config: {
|
|
3
12
|
disableRunloopPerformance?: boolean;
|
|
@@ -7,3 +16,6 @@ export declare function instrumentGlobalsForPerformance(config: {
|
|
|
7
16
|
enableComponentDefinitions?: boolean;
|
|
8
17
|
disableInitialLoadInstrumentation?: boolean;
|
|
9
18
|
}): void;
|
|
19
|
+
export declare function _processComponentRenderBefore(payload: Payload, beforeEntries: RenderEntries): void;
|
|
20
|
+
export declare function _processComponentRenderAfter(payload: Payload, beforeEntries: RenderEntries, op: string, minComponentDuration: number): void;
|
|
21
|
+
export {};
|