@sentry/ember 7.61.0 → 7.62.0
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/addon/index.ts +37 -27
- package/addon/instance-initializers/sentry-performance.ts +99 -81
- package/addon/runloop.d.ts +2 -2
- package/addon/types.ts +18 -3
- package/index.d.ts +6 -13
- package/index.js +2 -0
- package/instance-initializers/sentry-performance.d.ts +5 -4
- package/package.json +18 -12
- package/runloop.d.ts +2 -2
- package/tsconfig.json +2 -2
- package/types.d.ts +15 -3
package/addon/index.ts
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
|
-
import * as Sentry from '@sentry/browser';
|
|
2
|
-
import { SDK_VERSION, BrowserOptions } from '@sentry/browser';
|
|
3
|
-
import { macroCondition, isDevelopingApp, getOwnConfig } from '@embroider/macros';
|
|
4
|
-
import { next } from '@ember/runloop';
|
|
5
1
|
import { assert, warn } from '@ember/debug';
|
|
2
|
+
import type Route from '@ember/routing/route';
|
|
3
|
+
import { next } from '@ember/runloop';
|
|
4
|
+
import { getOwnConfig, isDevelopingApp, macroCondition } from '@embroider/macros';
|
|
5
|
+
import type { BrowserOptions } from '@sentry/browser';
|
|
6
|
+
import * as Sentry from '@sentry/browser';
|
|
7
|
+
import { SDK_VERSION } from '@sentry/browser';
|
|
8
|
+
import type { Transaction } from '@sentry/types';
|
|
9
|
+
import { GLOBAL_OBJ, timestampInSeconds } from '@sentry/utils';
|
|
6
10
|
import Ember from 'ember';
|
|
7
|
-
import { timestampInSeconds, GLOBAL_OBJ } from '@sentry/utils';
|
|
8
|
-
import { GlobalConfig, OwnConfig } from './types';
|
|
9
11
|
|
|
10
|
-
|
|
12
|
+
import type { EmberSentryConfig, GlobalConfig, OwnConfig } from './types';
|
|
13
|
+
|
|
14
|
+
function _getSentryInitConfig(): EmberSentryConfig['sentry'] {
|
|
11
15
|
const _global = GLOBAL_OBJ as typeof GLOBAL_OBJ & GlobalConfig;
|
|
12
16
|
_global.__sentryEmberConfig = _global.__sentryEmberConfig ?? {};
|
|
13
17
|
return _global.__sentryEmberConfig;
|
|
14
18
|
}
|
|
15
19
|
|
|
16
|
-
export function InitSentryForEmber(_runtimeConfig?: BrowserOptions) {
|
|
20
|
+
export function InitSentryForEmber(_runtimeConfig?: BrowserOptions): void {
|
|
17
21
|
const environmentConfig = getOwnConfig<OwnConfig>().sentryConfig;
|
|
18
22
|
|
|
19
23
|
assert('Missing configuration.', environmentConfig);
|
|
@@ -21,7 +25,7 @@ export function InitSentryForEmber(_runtimeConfig?: BrowserOptions) {
|
|
|
21
25
|
|
|
22
26
|
if (!environmentConfig.sentry) {
|
|
23
27
|
// If environment config is not specified but the above assertion passes, use runtime config.
|
|
24
|
-
environmentConfig.sentry = { ..._runtimeConfig }
|
|
28
|
+
environmentConfig.sentry = { ..._runtimeConfig };
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
// Merge runtime config into environment config, preferring runtime.
|
|
@@ -62,12 +66,20 @@ export function InitSentryForEmber(_runtimeConfig?: BrowserOptions) {
|
|
|
62
66
|
}
|
|
63
67
|
}
|
|
64
68
|
|
|
65
|
-
export const getActiveTransaction = () => {
|
|
69
|
+
export const getActiveTransaction = (): Transaction | undefined => {
|
|
66
70
|
return Sentry.getCurrentHub().getScope().getTransaction();
|
|
67
71
|
};
|
|
68
72
|
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
type RouteConstructor = new (...args: ConstructorParameters<typeof Route>) => Route;
|
|
74
|
+
|
|
75
|
+
export const instrumentRoutePerformance = <T extends RouteConstructor>(BaseRoute: T): T => {
|
|
76
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
77
|
+
const instrumentFunction = async <X extends (...args: unknown[]) => any>(
|
|
78
|
+
op: string,
|
|
79
|
+
description: string,
|
|
80
|
+
fn: X,
|
|
81
|
+
args: Parameters<X>,
|
|
82
|
+
): Promise<ReturnType<X>> => {
|
|
71
83
|
const startTimestamp = timestampInSeconds();
|
|
72
84
|
const result = await fn(...args);
|
|
73
85
|
|
|
@@ -79,40 +91,38 @@ export const instrumentRoutePerformance = (BaseRoute: any) => {
|
|
|
79
91
|
return result;
|
|
80
92
|
};
|
|
81
93
|
|
|
94
|
+
const routeName = BaseRoute.name;
|
|
95
|
+
|
|
82
96
|
return {
|
|
83
|
-
|
|
84
|
-
|
|
97
|
+
// @ts-expect-error TS2545 We do not need to redefine a constructor here
|
|
98
|
+
[routeName]: class extends BaseRoute {
|
|
99
|
+
public beforeModel(...args: unknown[]): void | Promise<unknown> {
|
|
85
100
|
return instrumentFunction(
|
|
86
101
|
'ui.ember.route.before_model',
|
|
87
|
-
|
|
102
|
+
this.fullRouteName,
|
|
88
103
|
super.beforeModel.bind(this),
|
|
89
104
|
args,
|
|
90
105
|
);
|
|
91
106
|
}
|
|
92
107
|
|
|
93
|
-
async model(...args:
|
|
94
|
-
return instrumentFunction('ui.ember.route.model',
|
|
108
|
+
public async model(...args: unknown[]): Promise<unknown> {
|
|
109
|
+
return instrumentFunction('ui.ember.route.model', this.fullRouteName, super.model.bind(this), args);
|
|
95
110
|
}
|
|
96
111
|
|
|
97
|
-
|
|
98
|
-
return instrumentFunction(
|
|
99
|
-
'ui.ember.route.after_model',
|
|
100
|
-
(<any>this).fullRouteName,
|
|
101
|
-
super.afterModel.bind(this),
|
|
102
|
-
args,
|
|
103
|
-
);
|
|
112
|
+
public afterModel(...args: unknown[]): void | Promise<unknown> {
|
|
113
|
+
return instrumentFunction('ui.ember.route.after_model', this.fullRouteName, super.afterModel.bind(this), args);
|
|
104
114
|
}
|
|
105
115
|
|
|
106
|
-
|
|
116
|
+
public setupController(...args: unknown[]): void | Promise<unknown> {
|
|
107
117
|
return instrumentFunction(
|
|
108
118
|
'ui.ember.route.setup_controller',
|
|
109
|
-
|
|
119
|
+
this.fullRouteName,
|
|
110
120
|
super.setupController.bind(this),
|
|
111
121
|
args,
|
|
112
122
|
);
|
|
113
123
|
}
|
|
114
124
|
},
|
|
115
|
-
}[
|
|
125
|
+
}[routeName] as T;
|
|
116
126
|
};
|
|
117
127
|
|
|
118
128
|
export * from '@sentry/browser';
|
|
@@ -1,18 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
1
|
+
/* eslint-disable max-lines */
|
|
2
|
+
import type ApplicationInstance from '@ember/application/instance';
|
|
3
3
|
import { subscribe } from '@ember/instrumentation';
|
|
4
|
+
import type Transition from '@ember/routing/-private/transition';
|
|
5
|
+
import type RouterService from '@ember/routing/router-service';
|
|
6
|
+
import { _backburner, run, scheduleOnce } from '@ember/runloop';
|
|
7
|
+
import type { EmberRunQueues } from '@ember/runloop/-private/types';
|
|
8
|
+
import { getOwnConfig, isTesting, macroCondition } from '@embroider/macros';
|
|
4
9
|
import * as Sentry from '@sentry/browser';
|
|
5
|
-
import { ExtendedBackburner } from '@sentry/ember/runloop';
|
|
6
|
-
import { Span, Transaction } from '@sentry/types';
|
|
7
|
-
import { EmberRunQueues } from '@ember/runloop/-private/types';
|
|
8
|
-
import { getActiveTransaction } from '..';
|
|
10
|
+
import type { ExtendedBackburner } from '@sentry/ember/runloop';
|
|
11
|
+
import type { Span, Transaction } from '@sentry/types';
|
|
9
12
|
import { browserPerformanceTimeOrigin, GLOBAL_OBJ, timestampInSeconds } from '@sentry/utils';
|
|
10
|
-
import { macroCondition, isTesting, getOwnConfig } from '@embroider/macros';
|
|
11
|
-
import { EmberSentryConfig, GlobalConfig, OwnConfig } from '../types';
|
|
12
|
-
import RouterService from '@ember/routing/router-service';
|
|
13
|
-
import type { BaseClient } from '@sentry/core';
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
import type { BrowserClient } from '..';
|
|
15
|
+
import { getActiveTransaction } from '..';
|
|
16
|
+
import type { EmberRouterMain, EmberSentryConfig, GlobalConfig, OwnConfig, StartTransactionFunction } from '../types';
|
|
17
|
+
|
|
18
|
+
type SentryTestRouterService = RouterService & {
|
|
19
|
+
_startTransaction?: StartTransactionFunction;
|
|
20
|
+
_sentryInstrumented?: boolean;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function getSentryConfig(): EmberSentryConfig {
|
|
16
24
|
const _global = GLOBAL_OBJ as typeof GLOBAL_OBJ & GlobalConfig;
|
|
17
25
|
_global.__sentryEmberConfig = _global.__sentryEmberConfig ?? {};
|
|
18
26
|
const environmentConfig = getOwnConfig<OwnConfig>().sentryConfig;
|
|
@@ -27,7 +35,7 @@ function getSentryConfig() {
|
|
|
27
35
|
|
|
28
36
|
export function initialize(appInstance: ApplicationInstance): void {
|
|
29
37
|
// Disable in fastboot - we only want to run Sentry client-side
|
|
30
|
-
const fastboot = appInstance.lookup('service:fastboot') as { isFastBoot: boolean } | undefined;
|
|
38
|
+
const fastboot = appInstance.lookup('service:fastboot') as unknown as { isFastBoot: boolean } | undefined;
|
|
31
39
|
if (fastboot?.isFastBoot) {
|
|
32
40
|
return;
|
|
33
41
|
}
|
|
@@ -38,35 +46,42 @@ export function initialize(appInstance: ApplicationInstance): void {
|
|
|
38
46
|
}
|
|
39
47
|
const performancePromise = instrumentForPerformance(appInstance);
|
|
40
48
|
if (macroCondition(isTesting())) {
|
|
41
|
-
(<
|
|
49
|
+
(window as typeof window & { _sentryPerformanceLoad?: Promise<void> })._sentryPerformanceLoad = performancePromise;
|
|
42
50
|
}
|
|
43
51
|
}
|
|
44
52
|
|
|
45
53
|
function getBackburner(): Pick<ExtendedBackburner, 'on' | 'off'> {
|
|
46
54
|
if (_backburner) {
|
|
47
|
-
return _backburner
|
|
55
|
+
return _backburner as unknown as Pick<ExtendedBackburner, 'on' | 'off'>;
|
|
48
56
|
}
|
|
49
57
|
|
|
50
|
-
if (run.backburner) {
|
|
51
|
-
return run.backburner;
|
|
58
|
+
if ((run as unknown as { backburner?: Pick<ExtendedBackburner, 'on' | 'off'> }).backburner) {
|
|
59
|
+
return (run as unknown as { backburner: Pick<ExtendedBackburner, 'on' | 'off'> }).backburner;
|
|
52
60
|
}
|
|
53
61
|
|
|
54
62
|
return {
|
|
55
|
-
on() {
|
|
56
|
-
|
|
63
|
+
on() {
|
|
64
|
+
// noop
|
|
65
|
+
},
|
|
66
|
+
off() {
|
|
67
|
+
// noop
|
|
68
|
+
},
|
|
57
69
|
};
|
|
58
70
|
}
|
|
59
71
|
|
|
60
|
-
function getTransitionInformation(
|
|
72
|
+
function getTransitionInformation(
|
|
73
|
+
transition: Transition | undefined,
|
|
74
|
+
router: RouterService,
|
|
75
|
+
): { fromRoute?: string; toRoute?: string } {
|
|
61
76
|
const fromRoute = transition?.from?.name;
|
|
62
|
-
const toRoute = transition
|
|
77
|
+
const toRoute = transition?.to?.name || router.currentRouteName;
|
|
63
78
|
return {
|
|
64
79
|
fromRoute,
|
|
65
80
|
toRoute,
|
|
66
81
|
};
|
|
67
82
|
}
|
|
68
83
|
|
|
69
|
-
function getLocationURL(location:
|
|
84
|
+
function getLocationURL(location: EmberRouterMain['location']): string {
|
|
70
85
|
if (!location || !location.getURL || !location.formatURL) {
|
|
71
86
|
return '';
|
|
72
87
|
}
|
|
@@ -79,22 +94,24 @@ function getLocationURL(location: any) {
|
|
|
79
94
|
}
|
|
80
95
|
|
|
81
96
|
export function _instrumentEmberRouter(
|
|
82
|
-
routerService:
|
|
83
|
-
routerMain:
|
|
97
|
+
routerService: RouterService,
|
|
98
|
+
routerMain: EmberRouterMain,
|
|
84
99
|
config: EmberSentryConfig,
|
|
85
|
-
startTransaction:
|
|
100
|
+
startTransaction: StartTransactionFunction,
|
|
86
101
|
startTransactionOnPageLoad?: boolean,
|
|
87
|
-
) {
|
|
102
|
+
): {
|
|
103
|
+
startTransaction: StartTransactionFunction;
|
|
104
|
+
} {
|
|
88
105
|
const { disableRunloopPerformance } = config;
|
|
89
106
|
const location = routerMain.location;
|
|
90
|
-
let activeTransaction: Transaction;
|
|
91
|
-
let transitionSpan: Span;
|
|
107
|
+
let activeTransaction: Transaction | undefined;
|
|
108
|
+
let transitionSpan: Span | undefined;
|
|
92
109
|
|
|
93
110
|
const url = getLocationURL(location);
|
|
94
111
|
|
|
95
112
|
if (macroCondition(isTesting())) {
|
|
96
|
-
routerService._sentryInstrumented = true;
|
|
97
|
-
routerService._startTransaction = startTransaction;
|
|
113
|
+
(routerService as SentryTestRouterService)._sentryInstrumented = true;
|
|
114
|
+
(routerService as SentryTestRouterService)._startTransaction = startTransaction;
|
|
98
115
|
}
|
|
99
116
|
|
|
100
117
|
if (startTransactionOnPageLoad && url) {
|
|
@@ -110,15 +127,15 @@ export function _instrumentEmberRouter(
|
|
|
110
127
|
});
|
|
111
128
|
}
|
|
112
129
|
|
|
113
|
-
const finishActiveTransaction =
|
|
130
|
+
const finishActiveTransaction = (_: unknown, nextInstance: unknown): void => {
|
|
114
131
|
if (nextInstance) {
|
|
115
132
|
return;
|
|
116
133
|
}
|
|
117
|
-
activeTransaction
|
|
134
|
+
activeTransaction?.finish();
|
|
118
135
|
getBackburner().off('end', finishActiveTransaction);
|
|
119
136
|
};
|
|
120
137
|
|
|
121
|
-
routerService.on('routeWillChange', (transition:
|
|
138
|
+
routerService.on('routeWillChange', (transition: Transition) => {
|
|
122
139
|
const { fromRoute, toRoute } = getTransitionInformation(transition, routerService);
|
|
123
140
|
activeTransaction?.finish();
|
|
124
141
|
activeTransaction = startTransaction({
|
|
@@ -130,7 +147,7 @@ export function _instrumentEmberRouter(
|
|
|
130
147
|
'routing.instrumentation': '@sentry/ember',
|
|
131
148
|
},
|
|
132
149
|
});
|
|
133
|
-
transitionSpan = activeTransaction
|
|
150
|
+
transitionSpan = activeTransaction?.startChild({
|
|
134
151
|
op: 'ui.ember.transition',
|
|
135
152
|
description: `route:${fromRoute} -> route:${toRoute}`,
|
|
136
153
|
});
|
|
@@ -155,7 +172,7 @@ export function _instrumentEmberRouter(
|
|
|
155
172
|
};
|
|
156
173
|
}
|
|
157
174
|
|
|
158
|
-
function _instrumentEmberRunloop(config: EmberSentryConfig) {
|
|
175
|
+
function _instrumentEmberRunloop(config: EmberSentryConfig): void {
|
|
159
176
|
const { disableRunloopPerformance, minimumRunloopQueueDuration } = config;
|
|
160
177
|
if (disableRunloopPerformance) {
|
|
161
178
|
return;
|
|
@@ -171,7 +188,7 @@ function _instrumentEmberRunloop(config: EmberSentryConfig) {
|
|
|
171
188
|
'destroy',
|
|
172
189
|
] as EmberRunQueues[];
|
|
173
190
|
|
|
174
|
-
getBackburner().on('begin', (_:
|
|
191
|
+
getBackburner().on('begin', (_: unknown, previousInstance: unknown) => {
|
|
175
192
|
if (previousInstance) {
|
|
176
193
|
return;
|
|
177
194
|
}
|
|
@@ -184,38 +201,38 @@ function _instrumentEmberRunloop(config: EmberSentryConfig) {
|
|
|
184
201
|
}
|
|
185
202
|
currentQueueStart = timestampInSeconds();
|
|
186
203
|
|
|
204
|
+
const processQueue = (queue: EmberRunQueues): void => {
|
|
205
|
+
// Process this queue using the end of the previous queue.
|
|
206
|
+
if (currentQueueStart) {
|
|
207
|
+
const now = timestampInSeconds();
|
|
208
|
+
const minQueueDuration = minimumRunloopQueueDuration ?? 5;
|
|
209
|
+
|
|
210
|
+
if ((now - currentQueueStart) * 1000 >= minQueueDuration) {
|
|
211
|
+
activeTransaction
|
|
212
|
+
?.startChild({
|
|
213
|
+
op: `ui.ember.runloop.${queue}`,
|
|
214
|
+
startTimestamp: currentQueueStart,
|
|
215
|
+
endTimestamp: now,
|
|
216
|
+
})
|
|
217
|
+
.finish();
|
|
218
|
+
}
|
|
219
|
+
currentQueueStart = undefined;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Setup for next queue
|
|
223
|
+
|
|
224
|
+
const stillActiveTransaction = getActiveTransaction();
|
|
225
|
+
if (!stillActiveTransaction) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
currentQueueStart = timestampInSeconds();
|
|
229
|
+
};
|
|
230
|
+
|
|
187
231
|
instrumentedEmberQueues.forEach(queue => {
|
|
188
|
-
scheduleOnce(queue, null,
|
|
189
|
-
scheduleOnce(queue, null, () => {
|
|
190
|
-
// Process this queue using the end of the previous queue.
|
|
191
|
-
if (currentQueueStart) {
|
|
192
|
-
const now = timestampInSeconds();
|
|
193
|
-
const minQueueDuration = minimumRunloopQueueDuration ?? 5;
|
|
194
|
-
|
|
195
|
-
if ((now - currentQueueStart) * 1000 >= minQueueDuration) {
|
|
196
|
-
activeTransaction
|
|
197
|
-
?.startChild({
|
|
198
|
-
op: `ui.ember.runloop.${queue}`,
|
|
199
|
-
startTimestamp: currentQueueStart,
|
|
200
|
-
endTimestamp: now,
|
|
201
|
-
})
|
|
202
|
-
.finish();
|
|
203
|
-
}
|
|
204
|
-
currentQueueStart = undefined;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// Setup for next queue
|
|
208
|
-
|
|
209
|
-
const stillActiveTransaction = getActiveTransaction();
|
|
210
|
-
if (!stillActiveTransaction) {
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
currentQueueStart = timestampInSeconds();
|
|
214
|
-
});
|
|
215
|
-
});
|
|
232
|
+
scheduleOnce(queue, null, processQueue, queue);
|
|
216
233
|
});
|
|
217
234
|
});
|
|
218
|
-
getBackburner().on('end', (_:
|
|
235
|
+
getBackburner().on('end', (_: unknown, nextInstance: unknown) => {
|
|
219
236
|
if (nextInstance) {
|
|
220
237
|
return;
|
|
221
238
|
}
|
|
@@ -241,7 +258,7 @@ interface RenderEntries {
|
|
|
241
258
|
[name: string]: RenderEntry;
|
|
242
259
|
}
|
|
243
260
|
|
|
244
|
-
function processComponentRenderBefore(payload: Payload, beforeEntries: RenderEntries) {
|
|
261
|
+
function processComponentRenderBefore(payload: Payload, beforeEntries: RenderEntries): void {
|
|
245
262
|
const info = {
|
|
246
263
|
payload,
|
|
247
264
|
now: timestampInSeconds(),
|
|
@@ -254,7 +271,7 @@ function processComponentRenderAfter(
|
|
|
254
271
|
beforeEntries: RenderEntries,
|
|
255
272
|
op: string,
|
|
256
273
|
minComponentDuration: number,
|
|
257
|
-
) {
|
|
274
|
+
): void {
|
|
258
275
|
const begin = beforeEntries[payload.object];
|
|
259
276
|
|
|
260
277
|
if (!begin) {
|
|
@@ -276,7 +293,7 @@ function processComponentRenderAfter(
|
|
|
276
293
|
}
|
|
277
294
|
}
|
|
278
295
|
|
|
279
|
-
function _instrumentComponents(config: EmberSentryConfig) {
|
|
296
|
+
function _instrumentComponents(config: EmberSentryConfig): void {
|
|
280
297
|
const { disableInstrumentComponents, minimumComponentRenderDuration, enableComponentDefinitions } = config;
|
|
281
298
|
if (disableInstrumentComponents) {
|
|
282
299
|
return;
|
|
@@ -287,13 +304,13 @@ function _instrumentComponents(config: EmberSentryConfig) {
|
|
|
287
304
|
const beforeEntries = {} as RenderEntries;
|
|
288
305
|
const beforeComponentDefinitionEntries = {} as RenderEntries;
|
|
289
306
|
|
|
290
|
-
function _subscribeToRenderEvents() {
|
|
307
|
+
function _subscribeToRenderEvents(): void {
|
|
291
308
|
subscribe('render.component', {
|
|
292
309
|
before(_name: string, _timestamp: number, payload: Payload) {
|
|
293
310
|
processComponentRenderBefore(payload, beforeEntries);
|
|
294
311
|
},
|
|
295
312
|
|
|
296
|
-
after(_name: string, _timestamp: number, payload:
|
|
313
|
+
after(_name: string, _timestamp: number, payload: Payload, _beganIndex: number) {
|
|
297
314
|
processComponentRenderAfter(payload, beforeEntries, 'ui.ember.component.render', minComponentDuration);
|
|
298
315
|
},
|
|
299
316
|
});
|
|
@@ -303,7 +320,7 @@ function _instrumentComponents(config: EmberSentryConfig) {
|
|
|
303
320
|
processComponentRenderBefore(payload, beforeComponentDefinitionEntries);
|
|
304
321
|
},
|
|
305
322
|
|
|
306
|
-
after(_name: string, _timestamp: number, payload:
|
|
323
|
+
after(_name: string, _timestamp: number, payload: Payload, _beganIndex: number) {
|
|
307
324
|
processComponentRenderAfter(payload, beforeComponentDefinitionEntries, 'ui.ember.component.definition', 0);
|
|
308
325
|
},
|
|
309
326
|
});
|
|
@@ -312,11 +329,11 @@ function _instrumentComponents(config: EmberSentryConfig) {
|
|
|
312
329
|
_subscribeToRenderEvents();
|
|
313
330
|
}
|
|
314
331
|
|
|
315
|
-
function _instrumentInitialLoad(config: EmberSentryConfig) {
|
|
332
|
+
function _instrumentInitialLoad(config: EmberSentryConfig): void {
|
|
316
333
|
const startName = '@sentry/ember:initial-load-start';
|
|
317
334
|
const endName = '@sentry/ember:initial-load-end';
|
|
318
335
|
|
|
319
|
-
|
|
336
|
+
const { HAS_PERFORMANCE, HAS_PERFORMANCE_TIMING } = _hasPerformanceSupport();
|
|
320
337
|
|
|
321
338
|
if (!HAS_PERFORMANCE) {
|
|
322
339
|
return;
|
|
@@ -331,7 +348,7 @@ function _instrumentInitialLoad(config: EmberSentryConfig) {
|
|
|
331
348
|
}
|
|
332
349
|
|
|
333
350
|
// Split performance check in two so clearMarks still happens even if timeOrigin isn't available.
|
|
334
|
-
if (!HAS_PERFORMANCE_TIMING) {
|
|
351
|
+
if (!HAS_PERFORMANCE_TIMING || browserPerformanceTimeOrigin === undefined) {
|
|
335
352
|
return;
|
|
336
353
|
}
|
|
337
354
|
const measureName = '@sentry/ember:initial-load';
|
|
@@ -344,9 +361,10 @@ function _instrumentInitialLoad(config: EmberSentryConfig) {
|
|
|
344
361
|
|
|
345
362
|
performance.measure(measureName, startName, endName);
|
|
346
363
|
const measures = performance.getEntriesByName(measureName);
|
|
347
|
-
|
|
364
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
365
|
+
const measure = measures[0]!;
|
|
348
366
|
|
|
349
|
-
const startTimestamp = (measure.startTime + browserPerformanceTimeOrigin
|
|
367
|
+
const startTimestamp = (measure.startTime + browserPerformanceTimeOrigin) / 1000;
|
|
350
368
|
const endTimestamp = startTimestamp + measure.duration / 1000;
|
|
351
369
|
|
|
352
370
|
const transaction = getActiveTransaction();
|
|
@@ -361,7 +379,7 @@ function _instrumentInitialLoad(config: EmberSentryConfig) {
|
|
|
361
379
|
performance.clearMeasures(measureName);
|
|
362
380
|
}
|
|
363
381
|
|
|
364
|
-
function _hasPerformanceSupport() {
|
|
382
|
+
function _hasPerformanceSupport(): { HAS_PERFORMANCE: boolean; HAS_PERFORMANCE_TIMING: boolean } {
|
|
365
383
|
// TS says that all of these methods are always available, but some of them may not be supported in older browsers
|
|
366
384
|
// So we "pretend" they are all optional in order to be able to check this properly without TS complaining
|
|
367
385
|
const _performance = window.performance as {
|
|
@@ -381,9 +399,8 @@ function _hasPerformanceSupport() {
|
|
|
381
399
|
};
|
|
382
400
|
}
|
|
383
401
|
|
|
384
|
-
export async function instrumentForPerformance(appInstance: ApplicationInstance) {
|
|
402
|
+
export async function instrumentForPerformance(appInstance: ApplicationInstance): Promise<void> {
|
|
385
403
|
const config = getSentryConfig();
|
|
386
|
-
const sentryConfig = config.sentry;
|
|
387
404
|
// Maintaining backwards compatibility with config.browserTracingOptions, but passing it with Sentry options is preferred.
|
|
388
405
|
const browserTracingOptions = config.browserTracingOptions || config.sentry.browserTracingOptions || {};
|
|
389
406
|
|
|
@@ -393,7 +410,8 @@ export async function instrumentForPerformance(appInstance: ApplicationInstance)
|
|
|
393
410
|
|
|
394
411
|
const browserTracing = new BrowserTracing({
|
|
395
412
|
routingInstrumentation: (customStartTransaction, startTransactionOnPageLoad) => {
|
|
396
|
-
|
|
413
|
+
// eslint-disable-next-line ember/no-private-routing-service
|
|
414
|
+
const routerMain = appInstance.lookup('router:main') as EmberRouterMain;
|
|
397
415
|
let routerService = appInstance.lookup('service:router') as
|
|
398
416
|
| RouterService & { externalRouter?: RouterService; _hasMountedSentryPerformanceRouting?: boolean };
|
|
399
417
|
|
|
@@ -421,8 +439,8 @@ export async function instrumentForPerformance(appInstance: ApplicationInstance)
|
|
|
421
439
|
|
|
422
440
|
if (
|
|
423
441
|
client &&
|
|
424
|
-
(client as
|
|
425
|
-
(client as
|
|
442
|
+
(client as BrowserClient).getIntegrationById &&
|
|
443
|
+
(client as BrowserClient).getIntegrationById('BrowserTracing')
|
|
426
444
|
) {
|
|
427
445
|
// Initializers are called more than once in tests, causing the integrations to not be setup correctly.
|
|
428
446
|
return;
|
package/addon/runloop.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { Backburner } from '@ember/runloop/-private/backburner';
|
|
1
|
+
import type { Backburner } from '@ember/runloop/-private/backburner';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Backburner needs to be extended as it's missing the 'off' method.
|
|
5
5
|
*/
|
|
6
6
|
interface ExtendedBackburner extends Backburner {
|
|
7
|
-
off(...args:
|
|
7
|
+
off(...args: unknown[]): void;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
/**
|
package/addon/types.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import { BrowserOptions } from '@sentry/browser';
|
|
1
|
+
import type { BrowserOptions, BrowserTracing } from '@sentry/browser';
|
|
2
|
+
import type { Transaction, TransactionContext } from '@sentry/types';
|
|
3
|
+
|
|
4
|
+
type BrowserTracingOptions = ConstructorParameters<typeof BrowserTracing>[0];
|
|
2
5
|
|
|
3
6
|
export type EmberSentryConfig = {
|
|
4
|
-
sentry: BrowserOptions & { browserTracingOptions
|
|
7
|
+
sentry: BrowserOptions & { browserTracingOptions?: BrowserTracingOptions };
|
|
5
8
|
transitionTimeout: number;
|
|
6
9
|
ignoreEmberOnErrorWarning: boolean;
|
|
7
10
|
disableInstrumentComponents: boolean;
|
|
@@ -12,13 +15,25 @@ export type EmberSentryConfig = {
|
|
|
12
15
|
enableComponentDefinitions: boolean;
|
|
13
16
|
minimumRunloopQueueDuration: number;
|
|
14
17
|
minimumComponentRenderDuration: number;
|
|
15
|
-
browserTracingOptions:
|
|
18
|
+
browserTracingOptions: BrowserTracingOptions;
|
|
16
19
|
};
|
|
17
20
|
|
|
18
21
|
export type OwnConfig = {
|
|
19
22
|
sentryConfig: EmberSentryConfig;
|
|
20
23
|
};
|
|
21
24
|
|
|
25
|
+
// This is private in Ember and not really exported, so we "mock" these types here.
|
|
26
|
+
export interface EmberRouterMain {
|
|
27
|
+
location: {
|
|
28
|
+
getURL?: () => string;
|
|
29
|
+
formatURL?: (url: string) => string;
|
|
30
|
+
implementation: string;
|
|
31
|
+
rootURL: string;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type StartTransactionFunction = (context: TransactionContext) => Transaction | undefined;
|
|
36
|
+
|
|
22
37
|
export type GlobalConfig = {
|
|
23
38
|
__sentryEmberConfig: EmberSentryConfig['sentry'];
|
|
24
39
|
};
|
package/index.d.ts
CHANGED
|
@@ -1,16 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { BrowserOptions } from '@sentry/browser';
|
|
1
|
+
import type Route from '@ember/routing/route';
|
|
2
|
+
import type { BrowserOptions } from '@sentry/browser';
|
|
3
|
+
import type { Transaction } from '@sentry/types';
|
|
3
4
|
export declare function InitSentryForEmber(_runtimeConfig?: BrowserOptions): void;
|
|
4
|
-
export declare const getActiveTransaction: () =>
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
[x: string]: any;
|
|
8
|
-
beforeModel(...args: any[]): Promise<any>;
|
|
9
|
-
model(...args: any[]): Promise<any>;
|
|
10
|
-
afterModel(...args: any[]): Promise<any>;
|
|
11
|
-
setupController(...args: any[]): Promise<any>;
|
|
12
|
-
};
|
|
13
|
-
[x: string]: any;
|
|
14
|
-
};
|
|
5
|
+
export declare const getActiveTransaction: () => Transaction | undefined;
|
|
6
|
+
type RouteConstructor = new (...args: ConstructorParameters<typeof Route>) => Route;
|
|
7
|
+
export declare const instrumentRoutePerformance: <T extends RouteConstructor>(BaseRoute: T) => T;
|
|
15
8
|
export * from '@sentry/browser';
|
|
16
9
|
export declare const init: typeof InitSentryForEmber;
|
package/index.js
CHANGED
|
@@ -33,6 +33,7 @@ module.exports = {
|
|
|
33
33
|
const addonConfig = config['@sentry/ember'] || {};
|
|
34
34
|
|
|
35
35
|
if (!isSerializable(addonConfig)) {
|
|
36
|
+
// eslint-disable-next-line no-console
|
|
36
37
|
console.warn(
|
|
37
38
|
`Warning: You passed a non-serializable config to \`ENV['@sentry/ember'].sentry\`.
|
|
38
39
|
Non-serializable config (e.g. RegExp, ...) can only be passed directly to \`Sentry.init()\`, which is usually defined in app/app.js.
|
|
@@ -73,6 +74,7 @@ function isSerializable(obj) {
|
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
if (isPlainObject(obj)) {
|
|
77
|
+
// eslint-disable-next-line guard-for-in
|
|
76
78
|
for (let property in obj) {
|
|
77
79
|
let value = obj[property];
|
|
78
80
|
if (!isSerializable(value)) {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import ApplicationInstance from '@ember/application/instance';
|
|
2
|
-
import
|
|
1
|
+
import type ApplicationInstance from '@ember/application/instance';
|
|
2
|
+
import type RouterService from '@ember/routing/router-service';
|
|
3
|
+
import type { EmberRouterMain, EmberSentryConfig, StartTransactionFunction } from '../types';
|
|
3
4
|
export declare function initialize(appInstance: ApplicationInstance): void;
|
|
4
|
-
export declare function _instrumentEmberRouter(routerService:
|
|
5
|
-
startTransaction:
|
|
5
|
+
export declare function _instrumentEmberRouter(routerService: RouterService, routerMain: EmberRouterMain, config: EmberSentryConfig, startTransaction: StartTransactionFunction, startTransactionOnPageLoad?: boolean): {
|
|
6
|
+
startTransaction: StartTransactionFunction;
|
|
6
7
|
};
|
|
7
8
|
export declare function instrumentForPerformance(appInstance: ApplicationInstance): Promise<void>;
|
|
8
9
|
declare const _default: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/ember",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.62.0",
|
|
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",
|
|
@@ -23,15 +23,20 @@
|
|
|
23
23
|
"lint:hbs": "ember-template-lint .",
|
|
24
24
|
"lint:js": "eslint .",
|
|
25
25
|
"lint:ts": "tsc",
|
|
26
|
+
"fix": "run-s fix:eslint fix:prettier",
|
|
27
|
+
"fix:eslint": "eslint . --format stylish --fix",
|
|
28
|
+
"fix:prettier": "prettier --write \"{addon,app,tests,config}/**/**.{ts,js}\"",
|
|
26
29
|
"start": "ember serve",
|
|
27
30
|
"test": "ember test",
|
|
28
|
-
"test:all": "ember try:each"
|
|
31
|
+
"test:all": "ember try:each",
|
|
32
|
+
"prepack": "ember ts:precompile",
|
|
33
|
+
"postpack": "ember ts:clean"
|
|
29
34
|
},
|
|
30
35
|
"dependencies": {
|
|
31
36
|
"@embroider/macros": "^1.9.0",
|
|
32
|
-
"@sentry/browser": "7.
|
|
33
|
-
"@sentry/types": "7.
|
|
34
|
-
"@sentry/utils": "7.
|
|
37
|
+
"@sentry/browser": "7.62.0",
|
|
38
|
+
"@sentry/types": "7.62.0",
|
|
39
|
+
"@sentry/utils": "7.62.0",
|
|
35
40
|
"ember-auto-import": "^1.12.1 || ^2.4.3",
|
|
36
41
|
"ember-cli-babel": "^7.26.11",
|
|
37
42
|
"ember-cli-htmlbars": "^6.1.1",
|
|
@@ -39,14 +44,14 @@
|
|
|
39
44
|
},
|
|
40
45
|
"devDependencies": {
|
|
41
46
|
"@ember/optional-features": "~1.3.0",
|
|
42
|
-
"@ember/test-helpers": "
|
|
47
|
+
"@ember/test-helpers": "2.9.4",
|
|
43
48
|
"@embroider/test-setup": "~1.8.3",
|
|
44
49
|
"@glimmer/component": "~1.1.2",
|
|
45
50
|
"@glimmer/tracking": "~1.1.2",
|
|
46
51
|
"@types/ember": "~3.16.5",
|
|
47
52
|
"@types/ember-qunit": "~3.4.9",
|
|
53
|
+
"@types/ember-resolver": "5.0.13",
|
|
48
54
|
"@types/ember__debug": "^3.16.5",
|
|
49
|
-
"@types/ember__test-helpers": "~1.7.0",
|
|
50
55
|
"@types/qunit": "~2.9.1",
|
|
51
56
|
"@types/rsvp": "~4.0.3",
|
|
52
57
|
"babel-eslint": "~10.1.0",
|
|
@@ -61,20 +66,21 @@
|
|
|
61
66
|
"ember-load-initializers": "~2.1.1",
|
|
62
67
|
"ember-maybe-import-regenerator": "~1.0.0",
|
|
63
68
|
"ember-qunit": "~6.0.0",
|
|
64
|
-
"ember-resolver": "
|
|
65
|
-
"ember-sinon-qunit": "
|
|
69
|
+
"ember-resolver": "11.0.0",
|
|
70
|
+
"ember-sinon-qunit": "7.1.4",
|
|
66
71
|
"ember-source": "~4.8.0",
|
|
67
72
|
"ember-source-channel-url": "~2.0.1",
|
|
68
73
|
"ember-template-lint": "~4.16.1",
|
|
69
74
|
"ember-test-selectors": "~6.0.0",
|
|
70
75
|
"ember-try": "~2.0.0",
|
|
71
76
|
"ember-window-mock": "~0.8.1",
|
|
72
|
-
"eslint-plugin-ember": "
|
|
73
|
-
"eslint-plugin-
|
|
74
|
-
"eslint-plugin-qunit": "
|
|
77
|
+
"eslint-plugin-ember": "11.9.0",
|
|
78
|
+
"eslint-plugin-n": "16.0.1",
|
|
79
|
+
"eslint-plugin-qunit": "8.0.0",
|
|
75
80
|
"loader.js": "~4.7.0",
|
|
76
81
|
"qunit": "~2.19.2",
|
|
77
82
|
"qunit-dom": "~2.0.0",
|
|
83
|
+
"sinon": "15.2.0",
|
|
78
84
|
"webpack": "~5.74.0"
|
|
79
85
|
},
|
|
80
86
|
"engines": {
|
package/runloop.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { Backburner } from '@ember/runloop/-private/backburner';
|
|
1
|
+
import type { Backburner } from '@ember/runloop/-private/backburner';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Backburner needs to be extended as it's missing the 'off' method.
|
|
5
5
|
*/
|
|
6
6
|
interface ExtendedBackburner extends Backburner {
|
|
7
|
-
off(...args:
|
|
7
|
+
off(...args: unknown[]): void;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
/**
|
package/tsconfig.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"extends": "../../tsconfig.json",
|
|
3
3
|
"compilerOptions": {
|
|
4
|
-
"target": "
|
|
4
|
+
"target": "es2022",
|
|
5
5
|
"allowJs": true,
|
|
6
6
|
"moduleResolution": "node",
|
|
7
7
|
"allowSyntheticDefaultImports": true,
|
|
@@ -24,5 +24,5 @@
|
|
|
24
24
|
"*": ["types/*"]
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
|
-
"include": ["app/**/*", "addon/**/*", "types/**/*", "addon-test-support/**/*"]
|
|
27
|
+
"include": ["app/**/*", "addon/**/*", "tests/**/*", "types/**/*", "test-support/**/*", "addon-test-support/**/*"]
|
|
28
28
|
}
|
package/types.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { BrowserOptions } from '@sentry/browser';
|
|
1
|
+
import type { BrowserOptions, BrowserTracing } from '@sentry/browser';
|
|
2
|
+
import type { Transaction, TransactionContext } from '@sentry/types';
|
|
3
|
+
type BrowserTracingOptions = ConstructorParameters<typeof BrowserTracing>[0];
|
|
2
4
|
export type EmberSentryConfig = {
|
|
3
5
|
sentry: BrowserOptions & {
|
|
4
|
-
browserTracingOptions
|
|
6
|
+
browserTracingOptions?: BrowserTracingOptions;
|
|
5
7
|
};
|
|
6
8
|
transitionTimeout: number;
|
|
7
9
|
ignoreEmberOnErrorWarning: boolean;
|
|
@@ -13,11 +15,21 @@ export type EmberSentryConfig = {
|
|
|
13
15
|
enableComponentDefinitions: boolean;
|
|
14
16
|
minimumRunloopQueueDuration: number;
|
|
15
17
|
minimumComponentRenderDuration: number;
|
|
16
|
-
browserTracingOptions:
|
|
18
|
+
browserTracingOptions: BrowserTracingOptions;
|
|
17
19
|
};
|
|
18
20
|
export type OwnConfig = {
|
|
19
21
|
sentryConfig: EmberSentryConfig;
|
|
20
22
|
};
|
|
23
|
+
export interface EmberRouterMain {
|
|
24
|
+
location: {
|
|
25
|
+
getURL?: () => string;
|
|
26
|
+
formatURL?: (url: string) => string;
|
|
27
|
+
implementation: string;
|
|
28
|
+
rootURL: string;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export type StartTransactionFunction = (context: TransactionContext) => Transaction | undefined;
|
|
21
32
|
export type GlobalConfig = {
|
|
22
33
|
__sentryEmberConfig: EmberSentryConfig['sentry'];
|
|
23
34
|
};
|
|
35
|
+
export {};
|