@sentry/ember 7.2.0 → 7.4.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/README.md +36 -29
- package/addon/ember.d.ts +6 -0
- package/addon/index.ts +122 -0
- package/addon/instance-initializers/sentry-performance.ts +412 -0
- package/addon/runloop.d.ts +19 -0
- package/addon/types.ts +24 -0
- package/app/instance-initializers/sentry-performance.js +1 -0
- package/config/environment.js +5 -0
- package/ember.d.ts +6 -0
- package/index.d.ts +15 -0
- package/index.js +52 -0
- package/instance-initializers/sentry-performance.d.ts +11 -0
- package/package.json +5 -5
- package/runloop.d.ts +19 -0
- package/scripts/run-CI-tests.js +17 -0
- package/tsconfig.json +28 -0
- package/types.d.ts +23 -0
- package/vendor/initial-load-body.js +3 -0
- package/vendor/initial-load-head.js +3 -0
package/README.md
CHANGED
|
@@ -21,28 +21,41 @@ This package is an Ember addon that wraps `@sentry/browser`, with added function
|
|
|
21
21
|
As with other Ember addons, run:
|
|
22
22
|
`ember install @sentry/ember`
|
|
23
23
|
|
|
24
|
-
Then add the following
|
|
24
|
+
Then add the following to your `<your-app>/app.js`
|
|
25
25
|
|
|
26
26
|
```javascript
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
import * as Sentry from "@sentry/ember";
|
|
28
|
+
|
|
29
|
+
Sentry.init({
|
|
30
|
+
dsn: '__DSN__' // replace __DSN__ with your DSN,
|
|
31
|
+
|
|
32
|
+
// Set tracesSampleRate to 1.0 to capture 100%
|
|
33
|
+
// of transactions for performance monitoring.
|
|
34
|
+
// We recommend adjusting this value in production,
|
|
35
|
+
tracesSampleRate: 1.0,
|
|
36
|
+
});
|
|
33
37
|
```
|
|
38
|
+
|
|
34
39
|
### Usage
|
|
35
40
|
|
|
36
|
-
To use this SDK, call `
|
|
41
|
+
To use this SDK, call `Sentry.init` before the application is initialized, in `app.js`. This will allow Sentry to capture information while your app is starting.
|
|
42
|
+
Any additional SDK settings can be modified via the usual config in `environment.js` for you, see the Additional Configuration section for more details.
|
|
37
43
|
|
|
38
44
|
```javascript
|
|
39
45
|
import Application from '@ember/application';
|
|
40
46
|
import Resolver from 'ember-resolver';
|
|
41
47
|
import loadInitializers from 'ember-load-initializers';
|
|
42
48
|
import config from './config/environment';
|
|
43
|
-
import
|
|
49
|
+
import * as Sentry from "@sentry/ember";
|
|
44
50
|
|
|
45
|
-
|
|
51
|
+
Sentry.init({
|
|
52
|
+
dsn: '__DSN__' // replace __DSN__ with your DSN,
|
|
53
|
+
|
|
54
|
+
// Set tracesSampleRate to 1.0 to capture 100%
|
|
55
|
+
// of transactions for performance monitoring.
|
|
56
|
+
// We recommend adjusting this value in production,
|
|
57
|
+
tracesSampleRate: 1.0,
|
|
58
|
+
});
|
|
46
59
|
|
|
47
60
|
export default class App extends Application {
|
|
48
61
|
modulePrefix = config.modulePrefix;
|
|
@@ -75,27 +88,12 @@ ENV['@sentry/ember'] = {
|
|
|
75
88
|
|
|
76
89
|
// All component definitions will be added as spans.
|
|
77
90
|
enableComponentDefinition: true,
|
|
78
|
-
|
|
79
|
-
// See sentry-javascript configuration https://docs.sentry.io/error-reporting/configuration/?platform=javascript
|
|
80
|
-
sentry: {}
|
|
81
91
|
};
|
|
82
92
|
```
|
|
83
93
|
|
|
84
|
-
You can also pass additional configuration for sentry-javascript directly to the `InitSentryForEmber` method.
|
|
85
|
-
This configuration will be merged with `ENV['@sentry/ember'].sentry`:
|
|
86
|
-
|
|
87
|
-
```javascript
|
|
88
|
-
InitSentryForEmber({
|
|
89
|
-
ignoreErrors: [
|
|
90
|
-
/You appear to be offline/,
|
|
91
|
-
],
|
|
92
|
-
})
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
It is recommended to pass all static sentry-javascript configuration directly to `InitSentryForEmber`, and only keeping configuration that depends on the build environment/secrets in `config/environment.js`. Please note that due to how the environment config is serialized, any non-JSON-serializable config (like a regex) will not work properly when being kept in `config/environment.js`.
|
|
96
|
-
|
|
97
94
|
#### Disabling Performance
|
|
98
95
|
|
|
96
|
+
|
|
99
97
|
`@sentry/ember` captures performance by default, if you would like to disable the automatic performance instrumentation, you can add the following to your `config/environment.js`:
|
|
100
98
|
|
|
101
99
|
```javascript
|
|
@@ -106,7 +104,9 @@ ENV['@sentry/ember'] = {
|
|
|
106
104
|
|
|
107
105
|
|
|
108
106
|
### Performance
|
|
107
|
+
|
|
109
108
|
#### Routes
|
|
109
|
+
|
|
110
110
|
If you would like to capture `beforeModel`, `model`, `afterModel` and `setupController` times for one of your routes,
|
|
111
111
|
you can import `instrumentRoutePerformance` and wrap your route with it.
|
|
112
112
|
|
|
@@ -124,11 +124,13 @@ export default instrumentRoutePerformance(MyRoute);
|
|
|
124
124
|
```
|
|
125
125
|
|
|
126
126
|
#### Runloop
|
|
127
|
+
|
|
127
128
|
The runloop queue durations are instrumented by default, as long as they are longer than a threshold (by default 5ms).
|
|
128
129
|
This helps (via the render queue) capturing the entire render in case component render times aren't fully instrumented,
|
|
129
130
|
such as when using glimmer components.
|
|
130
131
|
|
|
131
132
|
If you would like to change the runloop queue threshold, add the following to your config:
|
|
133
|
+
|
|
132
134
|
```javascript
|
|
133
135
|
ENV['@sentry/ember'] = {
|
|
134
136
|
minimumRunloopQueueDuration: 0, // All runloop queue durations will be added as spans.
|
|
@@ -136,9 +138,11 @@ ENV['@sentry/ember'] = {
|
|
|
136
138
|
```
|
|
137
139
|
|
|
138
140
|
#### Components
|
|
141
|
+
|
|
139
142
|
Non-glimmer component render times will automatically get captured.
|
|
140
143
|
|
|
141
144
|
If you would like to disable component render being instrumented, add the following to your config:
|
|
145
|
+
|
|
142
146
|
```javascript
|
|
143
147
|
ENV['@sentry/ember'] = {
|
|
144
148
|
disableInstrumentComponents: true, // Will disable automatic instrumentation for components.
|
|
@@ -147,6 +151,7 @@ ENV['@sentry/ember'] = {
|
|
|
147
151
|
|
|
148
152
|
Additionally, components whose render time is below a threshold (by default 2ms) will not be included as spans.
|
|
149
153
|
If you would like to change this threshold, add the following to your config:
|
|
154
|
+
|
|
150
155
|
```javascript
|
|
151
156
|
ENV['@sentry/ember'] = {
|
|
152
157
|
minimumComponentRenderDuration: 0, // All (non-glimmer) component render durations will be added as spans.
|
|
@@ -154,9 +159,11 @@ ENV['@sentry/ember'] = {
|
|
|
154
159
|
```
|
|
155
160
|
|
|
156
161
|
#### Glimmer components
|
|
162
|
+
|
|
157
163
|
Currently glimmer component render durations can only be captured indirectly via the runloop instrumentation. You can
|
|
158
164
|
optionally enable a setting to show component definitions (which will indicate which components are being rendered) be
|
|
159
165
|
adding the following to your config:
|
|
166
|
+
|
|
160
167
|
```javascript
|
|
161
168
|
ENV['@sentry/ember'] = {
|
|
162
169
|
enableComponentDefinition: true, // All component definitions will be added as spans.
|
|
@@ -165,7 +172,7 @@ ENV['@sentry/ember'] = {
|
|
|
165
172
|
|
|
166
173
|
### Supported Versions
|
|
167
174
|
|
|
168
|
-
`@sentry/ember` currently supports Ember **
|
|
175
|
+
`@sentry/ember` currently supports Ember **4.0+** for error monitoring.
|
|
169
176
|
|
|
170
177
|
### Previous Integration
|
|
171
178
|
|
|
@@ -174,8 +181,8 @@ this Ember addon to offer more Ember-specific error and performancing monitoring
|
|
|
174
181
|
|
|
175
182
|
## Testing
|
|
176
183
|
|
|
177
|
-
|
|
178
|
-
application, you must pass the dsn as an environment variable.
|
|
184
|
+
For this package itself, you can find example instrumentation in the `dummy` application, which is also used for testing.
|
|
185
|
+
To test with the dummy application, you must pass the dsn as an environment variable.
|
|
179
186
|
|
|
180
187
|
```javascript
|
|
181
188
|
SENTRY_DSN=__DSN__ ember serve
|
package/addon/ember.d.ts
ADDED
package/addon/index.ts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
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
|
+
import { assert, warn } from '@ember/debug';
|
|
6
|
+
import Ember from 'ember';
|
|
7
|
+
import { timestampWithMs } from '@sentry/utils';
|
|
8
|
+
import { GlobalConfig, OwnConfig } from './types';
|
|
9
|
+
import { getGlobalObject } from '@sentry/utils';
|
|
10
|
+
|
|
11
|
+
function _getSentryInitConfig() {
|
|
12
|
+
const _global = getGlobalObject<GlobalConfig>();
|
|
13
|
+
_global.__sentryEmberConfig = _global.__sentryEmberConfig ?? {};
|
|
14
|
+
return _global.__sentryEmberConfig;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function InitSentryForEmber(_runtimeConfig?: BrowserOptions) {
|
|
18
|
+
const environmentConfig = getOwnConfig<OwnConfig>().sentryConfig;
|
|
19
|
+
|
|
20
|
+
assert('Missing configuration.', environmentConfig);
|
|
21
|
+
assert('Missing configuration for Sentry.', environmentConfig.sentry || _runtimeConfig);
|
|
22
|
+
|
|
23
|
+
if (!environmentConfig.sentry) {
|
|
24
|
+
// If environment config is not specified but the above assertion passes, use runtime config.
|
|
25
|
+
environmentConfig.sentry = { ..._runtimeConfig } as any;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Merge runtime config into environment config, preferring runtime.
|
|
29
|
+
Object.assign(environmentConfig.sentry, _runtimeConfig || {});
|
|
30
|
+
const initConfig = Object.assign({}, environmentConfig.sentry);
|
|
31
|
+
|
|
32
|
+
initConfig._metadata = initConfig._metadata || {};
|
|
33
|
+
initConfig._metadata.sdk = {
|
|
34
|
+
name: 'sentry.javascript.ember',
|
|
35
|
+
packages: [
|
|
36
|
+
{
|
|
37
|
+
name: 'npm:@sentry/ember',
|
|
38
|
+
version: SDK_VERSION,
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
version: SDK_VERSION,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Persist Sentry init options so they are identical when performance initializers call init again.
|
|
45
|
+
const sentryInitConfig = _getSentryInitConfig();
|
|
46
|
+
Object.assign(sentryInitConfig, initConfig);
|
|
47
|
+
|
|
48
|
+
Sentry.init(initConfig);
|
|
49
|
+
|
|
50
|
+
if (macroCondition(isDevelopingApp())) {
|
|
51
|
+
if (environmentConfig.ignoreEmberOnErrorWarning) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
next(null, function () {
|
|
55
|
+
warn(
|
|
56
|
+
'Ember.onerror found. Using Ember.onerror can hide some errors (such as flushed runloop errors) from Sentry. Use Sentry.captureException to capture errors within Ember.onError or remove it to have errors caught by Sentry directly. This error can be silenced via addon configuration.',
|
|
57
|
+
!Ember.onerror,
|
|
58
|
+
{
|
|
59
|
+
id: '@sentry/ember.ember-onerror-detected',
|
|
60
|
+
},
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export const getActiveTransaction = () => {
|
|
67
|
+
return Sentry.getCurrentHub()?.getScope()?.getTransaction();
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export const instrumentRoutePerformance = (BaseRoute: any) => {
|
|
71
|
+
const instrumentFunction = async (op: string, description: string, fn: Function, args: any) => {
|
|
72
|
+
const startTimestamp = timestampWithMs();
|
|
73
|
+
const result = await fn(...args);
|
|
74
|
+
|
|
75
|
+
const currentTransaction = getActiveTransaction();
|
|
76
|
+
if (!currentTransaction) {
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
currentTransaction.startChild({ op, description, startTimestamp }).finish();
|
|
80
|
+
return result;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
[BaseRoute.name]: class extends BaseRoute {
|
|
85
|
+
beforeModel(...args: any[]) {
|
|
86
|
+
return instrumentFunction(
|
|
87
|
+
'ember.route.beforeModel',
|
|
88
|
+
(<any>this).fullRouteName,
|
|
89
|
+
super.beforeModel.bind(this),
|
|
90
|
+
args,
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async model(...args: any[]) {
|
|
95
|
+
return instrumentFunction('ember.route.model', (<any>this).fullRouteName, super.model.bind(this), args);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async afterModel(...args: any[]) {
|
|
99
|
+
return instrumentFunction(
|
|
100
|
+
'ember.route.afterModel',
|
|
101
|
+
(<any>this).fullRouteName,
|
|
102
|
+
super.afterModel.bind(this),
|
|
103
|
+
args,
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async setupController(...args: any[]) {
|
|
108
|
+
return instrumentFunction(
|
|
109
|
+
'ember.route.setupController',
|
|
110
|
+
(<any>this).fullRouteName,
|
|
111
|
+
super.setupController.bind(this),
|
|
112
|
+
args,
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
}[BaseRoute.name];
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export * from '@sentry/browser';
|
|
120
|
+
|
|
121
|
+
// init is now the preferred way to call initialization for this addon.
|
|
122
|
+
export const init = InitSentryForEmber;
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
import ApplicationInstance from '@ember/application/instance';
|
|
2
|
+
import Ember from 'ember';
|
|
3
|
+
import { run, _backburner, scheduleOnce } from '@ember/runloop';
|
|
4
|
+
import * as Sentry from '@sentry/browser';
|
|
5
|
+
import { ExtendedBackburner } from '@sentry/ember/runloop';
|
|
6
|
+
import { Span, Transaction, Integration } from '@sentry/types';
|
|
7
|
+
import { EmberRunQueues } from '@ember/runloop/-private/types';
|
|
8
|
+
import { getActiveTransaction } from '..';
|
|
9
|
+
import { browserPerformanceTimeOrigin, getGlobalObject, timestampWithMs } from '@sentry/utils';
|
|
10
|
+
import { macroCondition, isTesting, getOwnConfig } from '@embroider/macros';
|
|
11
|
+
import { EmberSentryConfig, GlobalConfig, OwnConfig } from '../types';
|
|
12
|
+
|
|
13
|
+
function getSentryConfig() {
|
|
14
|
+
const _global = getGlobalObject<GlobalConfig>();
|
|
15
|
+
_global.__sentryEmberConfig = _global.__sentryEmberConfig ?? {};
|
|
16
|
+
const environmentConfig = getOwnConfig<OwnConfig>().sentryConfig;
|
|
17
|
+
if (!environmentConfig.sentry) {
|
|
18
|
+
environmentConfig.sentry = {
|
|
19
|
+
browserTracingOptions: {},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
Object.assign(environmentConfig.sentry, _global.__sentryEmberConfig);
|
|
23
|
+
return environmentConfig;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function initialize(appInstance: ApplicationInstance): void {
|
|
27
|
+
const config = getSentryConfig();
|
|
28
|
+
if (config['disablePerformance']) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const performancePromise = instrumentForPerformance(appInstance);
|
|
32
|
+
if (macroCondition(isTesting())) {
|
|
33
|
+
(<any>window)._sentryPerformanceLoad = performancePromise;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function getBackburner(): Pick<ExtendedBackburner, 'on' | 'off'> {
|
|
38
|
+
if (_backburner) {
|
|
39
|
+
return _backburner;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (run.backburner) {
|
|
43
|
+
return run.backburner;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
on() {},
|
|
48
|
+
off() {},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function getTransitionInformation(transition: any, router: any) {
|
|
53
|
+
const fromRoute = transition?.from?.name;
|
|
54
|
+
const toRoute = transition && transition.to ? transition.to.name : router.currentRouteName;
|
|
55
|
+
return {
|
|
56
|
+
fromRoute,
|
|
57
|
+
toRoute,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getLocationURL(location: any) {
|
|
62
|
+
if (!location || !location.getURL || !location.formatURL) {
|
|
63
|
+
return '';
|
|
64
|
+
}
|
|
65
|
+
const url = location.formatURL(location.getURL());
|
|
66
|
+
|
|
67
|
+
if (location.implementation === 'hash') {
|
|
68
|
+
return `${location.rootURL}${url}`;
|
|
69
|
+
}
|
|
70
|
+
return url;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function _instrumentEmberRouter(
|
|
74
|
+
routerService: any,
|
|
75
|
+
routerMain: any,
|
|
76
|
+
config: EmberSentryConfig,
|
|
77
|
+
startTransaction: Function,
|
|
78
|
+
startTransactionOnPageLoad?: boolean,
|
|
79
|
+
) {
|
|
80
|
+
const { disableRunloopPerformance } = config;
|
|
81
|
+
const location = routerMain.location;
|
|
82
|
+
let activeTransaction: Transaction;
|
|
83
|
+
let transitionSpan: Span;
|
|
84
|
+
|
|
85
|
+
const url = getLocationURL(location);
|
|
86
|
+
|
|
87
|
+
if (macroCondition(isTesting())) {
|
|
88
|
+
routerService._sentryInstrumented = true;
|
|
89
|
+
routerService._startTransaction = startTransaction;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (startTransactionOnPageLoad && url) {
|
|
93
|
+
const routeInfo = routerService.recognize(url);
|
|
94
|
+
activeTransaction = startTransaction({
|
|
95
|
+
name: `route:${routeInfo.name}`,
|
|
96
|
+
op: 'pageload',
|
|
97
|
+
tags: {
|
|
98
|
+
url,
|
|
99
|
+
toRoute: routeInfo.name,
|
|
100
|
+
'routing.instrumentation': '@sentry/ember',
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const finishActiveTransaction = function (_: any, nextInstance: any) {
|
|
106
|
+
if (nextInstance) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
activeTransaction.finish();
|
|
110
|
+
getBackburner().off('end', finishActiveTransaction);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
routerService.on('routeWillChange', (transition: any) => {
|
|
114
|
+
const { fromRoute, toRoute } = getTransitionInformation(transition, routerService);
|
|
115
|
+
activeTransaction?.finish();
|
|
116
|
+
activeTransaction = startTransaction({
|
|
117
|
+
name: `route:${toRoute}`,
|
|
118
|
+
op: 'navigation',
|
|
119
|
+
tags: {
|
|
120
|
+
fromRoute,
|
|
121
|
+
toRoute,
|
|
122
|
+
'routing.instrumentation': '@sentry/ember',
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
transitionSpan = activeTransaction.startChild({
|
|
126
|
+
op: 'ui.ember.transition',
|
|
127
|
+
description: `route:${fromRoute} -> route:${toRoute}`,
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
routerService.on('routeDidChange', () => {
|
|
132
|
+
if (!transitionSpan || !activeTransaction) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
transitionSpan.finish();
|
|
136
|
+
|
|
137
|
+
if (disableRunloopPerformance) {
|
|
138
|
+
activeTransaction.finish();
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
getBackburner().on('end', finishActiveTransaction);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
startTransaction,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function _instrumentEmberRunloop(config: EmberSentryConfig) {
|
|
151
|
+
const { disableRunloopPerformance, minimumRunloopQueueDuration } = config;
|
|
152
|
+
if (disableRunloopPerformance) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
let currentQueueStart: number | undefined;
|
|
157
|
+
let currentQueueSpan: Span | undefined;
|
|
158
|
+
const instrumentedEmberQueues = [
|
|
159
|
+
'actions',
|
|
160
|
+
'routerTransitions',
|
|
161
|
+
'render',
|
|
162
|
+
'afterRender',
|
|
163
|
+
'destroy',
|
|
164
|
+
] as EmberRunQueues[];
|
|
165
|
+
|
|
166
|
+
getBackburner().on('begin', (_: any, previousInstance: any) => {
|
|
167
|
+
if (previousInstance) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const activeTransaction = getActiveTransaction();
|
|
171
|
+
if (!activeTransaction) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (currentQueueSpan) {
|
|
175
|
+
currentQueueSpan.finish();
|
|
176
|
+
}
|
|
177
|
+
currentQueueStart = timestampWithMs();
|
|
178
|
+
|
|
179
|
+
instrumentedEmberQueues.forEach(queue => {
|
|
180
|
+
scheduleOnce(queue, null, () => {
|
|
181
|
+
scheduleOnce(queue, null, () => {
|
|
182
|
+
// Process this queue using the end of the previous queue.
|
|
183
|
+
if (currentQueueStart) {
|
|
184
|
+
const now = timestampWithMs();
|
|
185
|
+
const minQueueDuration = minimumRunloopQueueDuration ?? 5;
|
|
186
|
+
|
|
187
|
+
if ((now - currentQueueStart) * 1000 >= minQueueDuration) {
|
|
188
|
+
activeTransaction
|
|
189
|
+
?.startChild({
|
|
190
|
+
op: `ui.ember.runloop.${queue}`,
|
|
191
|
+
startTimestamp: currentQueueStart,
|
|
192
|
+
endTimestamp: now,
|
|
193
|
+
})
|
|
194
|
+
.finish();
|
|
195
|
+
}
|
|
196
|
+
currentQueueStart = undefined;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Setup for next queue
|
|
200
|
+
|
|
201
|
+
const stillActiveTransaction = getActiveTransaction();
|
|
202
|
+
if (!stillActiveTransaction) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
currentQueueStart = timestampWithMs();
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
getBackburner().on('end', (_: any, nextInstance: any) => {
|
|
211
|
+
if (nextInstance) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (currentQueueSpan) {
|
|
215
|
+
currentQueueSpan.finish();
|
|
216
|
+
currentQueueSpan = undefined;
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
type Payload = {
|
|
222
|
+
containerKey: string;
|
|
223
|
+
initialRender: true;
|
|
224
|
+
object: string;
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
type RenderEntry = {
|
|
228
|
+
payload: Payload;
|
|
229
|
+
now: number;
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
interface RenderEntries {
|
|
233
|
+
[name: string]: RenderEntry;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function processComponentRenderBefore(payload: Payload, beforeEntries: RenderEntries) {
|
|
237
|
+
const info = {
|
|
238
|
+
payload,
|
|
239
|
+
now: timestampWithMs(),
|
|
240
|
+
};
|
|
241
|
+
beforeEntries[payload.object] = info;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function processComponentRenderAfter(
|
|
245
|
+
payload: Payload,
|
|
246
|
+
beforeEntries: RenderEntries,
|
|
247
|
+
op: string,
|
|
248
|
+
minComponentDuration: number,
|
|
249
|
+
) {
|
|
250
|
+
const begin = beforeEntries[payload.object];
|
|
251
|
+
|
|
252
|
+
if (!begin) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const now = timestampWithMs();
|
|
257
|
+
const componentRenderDuration = now - begin.now;
|
|
258
|
+
|
|
259
|
+
if (componentRenderDuration * 1000 >= minComponentDuration) {
|
|
260
|
+
const activeTransaction = getActiveTransaction();
|
|
261
|
+
|
|
262
|
+
activeTransaction?.startChild({
|
|
263
|
+
op,
|
|
264
|
+
description: payload.containerKey || payload.object,
|
|
265
|
+
startTimestamp: begin.now,
|
|
266
|
+
endTimestamp: now,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function _instrumentComponents(config: EmberSentryConfig) {
|
|
272
|
+
const { disableInstrumentComponents, minimumComponentRenderDuration, enableComponentDefinitions } = config;
|
|
273
|
+
if (disableInstrumentComponents) {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const minComponentDuration = minimumComponentRenderDuration ?? 2;
|
|
278
|
+
|
|
279
|
+
const beforeEntries = {} as RenderEntries;
|
|
280
|
+
const beforeComponentDefinitionEntries = {} as RenderEntries;
|
|
281
|
+
|
|
282
|
+
const subscribe = Ember.subscribe;
|
|
283
|
+
function _subscribeToRenderEvents() {
|
|
284
|
+
subscribe('render.component', {
|
|
285
|
+
before(_name: string, _timestamp: number, payload: Payload) {
|
|
286
|
+
processComponentRenderBefore(payload, beforeEntries);
|
|
287
|
+
},
|
|
288
|
+
|
|
289
|
+
after(_name: string, _timestamp: number, payload: any, _beganIndex: number) {
|
|
290
|
+
processComponentRenderAfter(payload, beforeEntries, 'ui.ember.component.render', minComponentDuration);
|
|
291
|
+
},
|
|
292
|
+
});
|
|
293
|
+
if (enableComponentDefinitions) {
|
|
294
|
+
subscribe('render.getComponentDefinition', {
|
|
295
|
+
before(_name: string, _timestamp: number, payload: Payload) {
|
|
296
|
+
processComponentRenderBefore(payload, beforeComponentDefinitionEntries);
|
|
297
|
+
},
|
|
298
|
+
|
|
299
|
+
after(_name: string, _timestamp: number, payload: any, _beganIndex: number) {
|
|
300
|
+
processComponentRenderAfter(payload, beforeComponentDefinitionEntries, 'ui.ember.component.definition', 0);
|
|
301
|
+
},
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
_subscribeToRenderEvents();
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function _instrumentInitialLoad(config: EmberSentryConfig) {
|
|
309
|
+
const startName = '@sentry/ember:initial-load-start';
|
|
310
|
+
const endName = '@sentry/ember:initial-load-end';
|
|
311
|
+
|
|
312
|
+
const { performance } = window;
|
|
313
|
+
const HAS_PERFORMANCE = performance && performance.clearMarks && performance.clearMeasures;
|
|
314
|
+
|
|
315
|
+
if (!HAS_PERFORMANCE) {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (config.disableInitialLoadInstrumentation) {
|
|
320
|
+
performance.clearMarks(startName);
|
|
321
|
+
performance.clearMarks(endName);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Split performance check in two so clearMarks still happens even if timeOrigin isn't available.
|
|
326
|
+
const HAS_PERFORMANCE_TIMING =
|
|
327
|
+
performance.measure && performance.getEntriesByName && browserPerformanceTimeOrigin !== undefined;
|
|
328
|
+
if (!HAS_PERFORMANCE_TIMING) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
const measureName = '@sentry/ember:initial-load';
|
|
332
|
+
|
|
333
|
+
const startMarkExists = performance.getEntriesByName(startName).length > 0;
|
|
334
|
+
const endMarkExists = performance.getEntriesByName(endName).length > 0;
|
|
335
|
+
if (!startMarkExists || !endMarkExists) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
performance.measure(measureName, startName, endName);
|
|
340
|
+
const measures = performance.getEntriesByName(measureName);
|
|
341
|
+
const measure = measures[0];
|
|
342
|
+
|
|
343
|
+
const startTimestamp = (measure.startTime + browserPerformanceTimeOrigin!) / 1000;
|
|
344
|
+
const endTimestamp = startTimestamp + measure.duration / 1000;
|
|
345
|
+
|
|
346
|
+
const transaction = getActiveTransaction();
|
|
347
|
+
const span = transaction?.startChild({
|
|
348
|
+
op: 'ui.ember.init',
|
|
349
|
+
startTimestamp,
|
|
350
|
+
});
|
|
351
|
+
span?.finish(endTimestamp);
|
|
352
|
+
performance.clearMarks(startName);
|
|
353
|
+
performance.clearMarks(endName);
|
|
354
|
+
|
|
355
|
+
performance.clearMeasures(measureName);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export async function instrumentForPerformance(appInstance: ApplicationInstance) {
|
|
359
|
+
const config = getSentryConfig();
|
|
360
|
+
const sentryConfig = config.sentry;
|
|
361
|
+
// Maintaining backwards compatibility with config.browserTracingOptions, but passing it with Sentry options is preferred.
|
|
362
|
+
const browserTracingOptions = config.browserTracingOptions || config.sentry.browserTracingOptions || {};
|
|
363
|
+
|
|
364
|
+
const tracing = await import('@sentry/tracing');
|
|
365
|
+
|
|
366
|
+
const idleTimeout = config.transitionTimeout || 5000;
|
|
367
|
+
|
|
368
|
+
const existingIntegrations = (sentryConfig['integrations'] || []) as Integration[];
|
|
369
|
+
|
|
370
|
+
sentryConfig['integrations'] = [
|
|
371
|
+
...existingIntegrations,
|
|
372
|
+
new tracing.Integrations.BrowserTracing({
|
|
373
|
+
routingInstrumentation: (customStartTransaction, startTransactionOnPageLoad) => {
|
|
374
|
+
const routerMain = appInstance.lookup('router:main');
|
|
375
|
+
const routerService = appInstance.lookup('service:router');
|
|
376
|
+
_instrumentEmberRouter(routerService, routerMain, config, customStartTransaction, startTransactionOnPageLoad);
|
|
377
|
+
},
|
|
378
|
+
idleTimeout,
|
|
379
|
+
...browserTracingOptions,
|
|
380
|
+
}),
|
|
381
|
+
];
|
|
382
|
+
|
|
383
|
+
class FakeBrowserTracingClass {
|
|
384
|
+
static id = tracing.BROWSER_TRACING_INTEGRATION_ID;
|
|
385
|
+
public name = FakeBrowserTracingClass.id;
|
|
386
|
+
setupOnce() {
|
|
387
|
+
// noop - We're just faking this class for a lookup
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (
|
|
392
|
+
isTesting() &&
|
|
393
|
+
Sentry.getCurrentHub()?.getIntegration(
|
|
394
|
+
// This is a temporary hack because the BrowserTracing integration cannot have a static `id` field for tree
|
|
395
|
+
// shaking reasons. However, `getIntegration` needs that field.
|
|
396
|
+
FakeBrowserTracingClass,
|
|
397
|
+
)
|
|
398
|
+
) {
|
|
399
|
+
// Initializers are called more than once in tests, causing the integrations to not be setup correctly.
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
Sentry.init(sentryConfig); // Call init again to rebind client with new integration list in addition to the defaults
|
|
404
|
+
|
|
405
|
+
_instrumentEmberRunloop(config);
|
|
406
|
+
_instrumentComponents(config);
|
|
407
|
+
_instrumentInitialLoad(config);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
export default {
|
|
411
|
+
initialize,
|
|
412
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Backburner } from '@ember/runloop/-private/backburner';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Backburner needs to be extended as it's missing the 'off' method.
|
|
5
|
+
*/
|
|
6
|
+
interface ExtendedBackburner extends Backburner {
|
|
7
|
+
off(...args: any[]): void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Runloop needs to be extended to expose backburner as suggested here:
|
|
12
|
+
* https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/ember__runloop/ember__runloop-tests.ts#L9
|
|
13
|
+
*/
|
|
14
|
+
declare module '@ember/runloop' {
|
|
15
|
+
interface RunNamespace {
|
|
16
|
+
backburner?: ExtendedBackburner;
|
|
17
|
+
}
|
|
18
|
+
export const _backburner: ExtendedBackburner; // Ember 4.0
|
|
19
|
+
}
|
package/addon/types.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { BrowserOptions } from '@sentry/browser';
|
|
2
|
+
|
|
3
|
+
export type EmberSentryConfig = {
|
|
4
|
+
sentry: BrowserOptions & { browserTracingOptions: Object };
|
|
5
|
+
transitionTimeout: number;
|
|
6
|
+
ignoreEmberOnErrorWarning: boolean;
|
|
7
|
+
disableInstrumentComponents: boolean;
|
|
8
|
+
disablePerformance: boolean;
|
|
9
|
+
disablePostTransitionRender: boolean;
|
|
10
|
+
disableRunloopPerformance: boolean;
|
|
11
|
+
disableInitialLoadInstrumentation: boolean;
|
|
12
|
+
enableComponentDefinitions: boolean;
|
|
13
|
+
minimumRunloopQueueDuration: number;
|
|
14
|
+
minimumComponentRenderDuration: number;
|
|
15
|
+
browserTracingOptions: Object;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type OwnConfig = {
|
|
19
|
+
sentryConfig: EmberSentryConfig;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type GlobalConfig = {
|
|
23
|
+
__sentryEmberConfig: EmberSentryConfig['sentry'];
|
|
24
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default, initialize } from '@sentry/ember/instance-initializers/sentry-performance';
|
package/ember.d.ts
ADDED
package/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BrowserOptions } from '@sentry/browser';
|
|
2
|
+
export declare function InitSentryForEmber(_runtimeConfig?: BrowserOptions): void;
|
|
3
|
+
export declare const getActiveTransaction: () => import("@sentry/types").Transaction | undefined;
|
|
4
|
+
export declare const instrumentRoutePerformance: (BaseRoute: any) => {
|
|
5
|
+
new (): {
|
|
6
|
+
[x: string]: any;
|
|
7
|
+
beforeModel(...args: any[]): Promise<any>;
|
|
8
|
+
model(...args: any[]): Promise<any>;
|
|
9
|
+
afterModel(...args: any[]): Promise<any>;
|
|
10
|
+
setupController(...args: any[]): Promise<any>;
|
|
11
|
+
};
|
|
12
|
+
[x: string]: any;
|
|
13
|
+
};
|
|
14
|
+
export * from '@sentry/browser';
|
|
15
|
+
export declare const init: typeof InitSentryForEmber;
|
package/index.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const crypto = require('crypto');
|
|
4
|
+
|
|
5
|
+
function readSnippet(fileName) {
|
|
6
|
+
return fs.readFileSync(`${__dirname}/vendor/${fileName}`, 'utf8');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function hashSha256base64(string) {
|
|
10
|
+
return crypto.createHash('sha256').update(string).digest('base64');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const initialLoadHeadSnippet = readSnippet('initial-load-head.js');
|
|
14
|
+
const initialLoadBodySnippet = readSnippet('initial-load-body.js');
|
|
15
|
+
|
|
16
|
+
const initialLoadHeadSnippetHash = hashSha256base64(initialLoadHeadSnippet);
|
|
17
|
+
const initialLoadBodySnippetHash = hashSha256base64(initialLoadBodySnippet);
|
|
18
|
+
|
|
19
|
+
module.exports = {
|
|
20
|
+
name: require('./package').name,
|
|
21
|
+
options: {
|
|
22
|
+
babel: {
|
|
23
|
+
plugins: [require.resolve('ember-auto-import/babel-plugin')],
|
|
24
|
+
},
|
|
25
|
+
'@embroider/macros': {
|
|
26
|
+
setOwnConfig: {},
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
config(_, appConfig) {
|
|
31
|
+
const addonConfig = appConfig['@sentry/ember'];
|
|
32
|
+
this.options['@embroider/macros'].setOwnConfig.sentryConfig = { ...addonConfig };
|
|
33
|
+
return this._super(...arguments);
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
contentFor(type, config) {
|
|
37
|
+
const addonConfig = config['@sentry/ember'] || {};
|
|
38
|
+
const { disablePerformance, disableInitialLoadInstrumentation } = addonConfig;
|
|
39
|
+
|
|
40
|
+
if (disablePerformance || disableInitialLoadInstrumentation) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (type === 'head') {
|
|
45
|
+
return `<script type="text/javascript">${initialLoadHeadSnippet}</script>`;
|
|
46
|
+
} else if (type === 'body-footer') {
|
|
47
|
+
return `<script type="text/javascript">${initialLoadBodySnippet}</script>`;
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
injectedScriptHashes: [initialLoadHeadSnippetHash, initialLoadBodySnippetHash],
|
|
52
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import ApplicationInstance from '@ember/application/instance';
|
|
2
|
+
import { EmberSentryConfig } from '../types';
|
|
3
|
+
export declare function initialize(appInstance: ApplicationInstance): void;
|
|
4
|
+
export declare function _instrumentEmberRouter(routerService: any, routerMain: any, config: EmberSentryConfig, startTransaction: Function, startTransactionOnPageLoad?: boolean): {
|
|
5
|
+
startTransaction: Function;
|
|
6
|
+
};
|
|
7
|
+
export declare function instrumentForPerformance(appInstance: ApplicationInstance): Promise<void>;
|
|
8
|
+
declare const _default: {
|
|
9
|
+
initialize: typeof initialize;
|
|
10
|
+
};
|
|
11
|
+
export default _default;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/ember",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.4.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",
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@embroider/macros": "~0.47.2",
|
|
33
|
-
"@sentry/browser": "7.
|
|
34
|
-
"@sentry/tracing": "7.
|
|
35
|
-
"@sentry/types": "7.
|
|
36
|
-
"@sentry/utils": "7.
|
|
33
|
+
"@sentry/browser": "7.4.0",
|
|
34
|
+
"@sentry/tracing": "7.4.0",
|
|
35
|
+
"@sentry/types": "7.4.0",
|
|
36
|
+
"@sentry/utils": "7.4.0",
|
|
37
37
|
"ember-auto-import": "~1.12.1 || ~2.2.0",
|
|
38
38
|
"ember-cli-babel": "~7.26.6",
|
|
39
39
|
"ember-cli-htmlbars": "^6.0.1",
|
package/runloop.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Backburner } from '@ember/runloop/-private/backburner';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Backburner needs to be extended as it's missing the 'off' method.
|
|
5
|
+
*/
|
|
6
|
+
interface ExtendedBackburner extends Backburner {
|
|
7
|
+
off(...args: any[]): void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Runloop needs to be extended to expose backburner as suggested here:
|
|
12
|
+
* https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/ember__runloop/ember__runloop-tests.ts#L9
|
|
13
|
+
*/
|
|
14
|
+
declare module '@ember/runloop' {
|
|
15
|
+
interface RunNamespace {
|
|
16
|
+
backburner?: ExtendedBackburner;
|
|
17
|
+
}
|
|
18
|
+
export const _backburner: ExtendedBackburner; // Ember 4.0
|
|
19
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/*eslint-env node*/
|
|
2
|
+
const { spawnSync } = require('child_process');
|
|
3
|
+
|
|
4
|
+
console.log('Mimicking the CI environment in order to run tests against multiple versions of Ember');
|
|
5
|
+
|
|
6
|
+
const result = spawnSync('yarn test', {
|
|
7
|
+
shell: true,
|
|
8
|
+
stdio: 'inherit',
|
|
9
|
+
env: {
|
|
10
|
+
...process.env,
|
|
11
|
+
GITHUB_ACTIONS: true,
|
|
12
|
+
GITHUB_EVENT_NAME: 'push',
|
|
13
|
+
GITHUB_HEAD_REF: 'master',
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
process.exit(result.status);
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"target": "es2017",
|
|
5
|
+
"allowJs": true,
|
|
6
|
+
"moduleResolution": "node",
|
|
7
|
+
"allowSyntheticDefaultImports": true,
|
|
8
|
+
"alwaysStrict": true,
|
|
9
|
+
"noImplicitUseStrict": false,
|
|
10
|
+
"strictNullChecks": true,
|
|
11
|
+
"strictPropertyInitialization": true,
|
|
12
|
+
"noEmitOnError": false,
|
|
13
|
+
"noEmit": true,
|
|
14
|
+
"baseUrl": ".",
|
|
15
|
+
"module": "esnext",
|
|
16
|
+
"experimentalDecorators": true,
|
|
17
|
+
"paths": {
|
|
18
|
+
"dummy/tests/*": ["tests/*"],
|
|
19
|
+
"dummy/*": ["tests/dummy/app/*", "app/*"],
|
|
20
|
+
"@sentry/ember": ["addon"],
|
|
21
|
+
"@sentry/ember/*": ["addon/*"],
|
|
22
|
+
"@sentry/ember/test-support": ["addon-test-support"],
|
|
23
|
+
"@sentry/ember/test-support/*": ["addon-test-support/*"],
|
|
24
|
+
"*": ["types/*"]
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"include": ["app/**/*", "addon/**/*", "types/**/*", "addon-test-support/**/*"]
|
|
28
|
+
}
|
package/types.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { BrowserOptions } from '@sentry/browser';
|
|
2
|
+
export declare type EmberSentryConfig = {
|
|
3
|
+
sentry: BrowserOptions & {
|
|
4
|
+
browserTracingOptions: Object;
|
|
5
|
+
};
|
|
6
|
+
transitionTimeout: number;
|
|
7
|
+
ignoreEmberOnErrorWarning: boolean;
|
|
8
|
+
disableInstrumentComponents: boolean;
|
|
9
|
+
disablePerformance: boolean;
|
|
10
|
+
disablePostTransitionRender: boolean;
|
|
11
|
+
disableRunloopPerformance: boolean;
|
|
12
|
+
disableInitialLoadInstrumentation: boolean;
|
|
13
|
+
enableComponentDefinitions: boolean;
|
|
14
|
+
minimumRunloopQueueDuration: number;
|
|
15
|
+
minimumComponentRenderDuration: number;
|
|
16
|
+
browserTracingOptions: Object;
|
|
17
|
+
};
|
|
18
|
+
export declare type OwnConfig = {
|
|
19
|
+
sentryConfig: EmberSentryConfig;
|
|
20
|
+
};
|
|
21
|
+
export declare type GlobalConfig = {
|
|
22
|
+
__sentryEmberConfig: EmberSentryConfig['sentry'];
|
|
23
|
+
};
|