1
- import { Integrations as APMIntegrations , Span as SpanClass } from '@sentry/apm' ;
2
- import { EventProcessor , Hub , Integration } from '@sentry/types' ;
1
+ import { EventProcessor , Hub , Integration , IntegrationClass , Span } from '@sentry/types' ;
3
2
import { basename , getGlobalObject , logger , timestampWithMs } from '@sentry/utils' ;
4
3
4
+ /**
5
+ * Used to extract Tracing integration from the current client,
6
+ * without the need to import `Tracing` itself from the @sentry/apm package.
7
+ */
8
+ const TRACING_GETTER = {
9
+ id : 'Tracing' ,
10
+ } as IntegrationClass < Integration > ;
11
+
5
12
/** Global Vue object limited to the methods/attributes we require */
6
13
interface VueInstance {
7
14
config ?: {
@@ -46,7 +53,10 @@ interface IntegrationOptions {
46
53
*/
47
54
logErrors : boolean ;
48
55
49
- /** When set to `true`, enables tracking of components lifecycle performance. */
56
+ /**
57
+ * When set to `false`, disables tracking of components lifecycle performance.
58
+ * By default, it tracks only when `Tracing` integration is also enabled.
59
+ */
50
60
tracing : boolean ;
51
61
52
62
/** {@link TracingOptions } */
@@ -130,7 +140,7 @@ export class Vue implements Integration {
130
140
* Cache holding already processed component names
131
141
*/
132
142
private readonly _componentsCache : { [ key : string ] : string } = { } ;
133
- private _rootSpan ?: SpanClass ;
143
+ private _rootSpan ?: Span ;
134
144
private _rootSpanTimer ?: ReturnType < typeof setTimeout > ;
135
145
private _tracingActivity ?: number ;
136
146
@@ -142,7 +152,7 @@ export class Vue implements Integration {
142
152
Vue : getGlobalObject < any > ( ) . Vue , // tslint:disable-line:no-unsafe-any
143
153
attachProps : true ,
144
154
logErrors : false ,
145
- tracing : false ,
155
+ tracing : true ,
146
156
...options ,
147
157
tracingOptions : {
148
158
hooks : [ 'beforeMount' , 'mounted' , 'beforeUpdate' , 'updated' ] ,
@@ -203,7 +213,7 @@ export class Vue implements Integration {
203
213
204
214
const name = this . _getComponentName ( vm ) ;
205
215
const rootMount = name === ROOT_COMPONENT_NAME ;
206
- const spans : { [ key : string ] : SpanClass } = { } ;
216
+ const spans : { [ key : string ] : Span } = { } ;
207
217
208
218
// Render hook starts after once event is emitted,
209
219
// but it ends before the second event of the same type.
@@ -216,16 +226,22 @@ export class Vue implements Integration {
216
226
// On the first handler call (before), it'll be undefined, as `$once` will add it in the future.
217
227
// However, on the second call (after), it'll be already in place.
218
228
if ( this . _rootSpan ) {
219
- this . _finishRootSpan ( now ) ;
229
+ this . _finishRootSpan ( now , getCurrentHub ) ;
220
230
} else {
221
231
vm . $once ( `hook:${ hook } ` , ( ) => {
222
232
// Create an activity on the first event call. There'll be no second call, as rootSpan will be in place,
223
233
// thus new event handler won't be attached.
224
- this . _tracingActivity = APMIntegrations . Tracing . pushActivity ( 'Vue Application Render' ) ;
234
+
235
+ // We do this whole dance with `TRACING_GETTER` to prevent `@sentry/apm` from becoming a peerDependency.
236
+ // We also need to ask for the `.constructor`, as `pushActivity` and `popActivity` are static, not instance methods.
237
+ const tracingIntegration = getCurrentHub ( ) . getIntegration ( TRACING_GETTER ) ;
238
+ if ( tracingIntegration ) {
239
+ this . _tracingActivity = ( tracingIntegration as any ) . constructor . pushActivity ( 'Vue Application Render' ) ;
240
+ }
225
241
this . _rootSpan = getCurrentHub ( ) . startSpan ( {
226
242
description : 'Application Render' ,
227
243
op : 'Vue' ,
228
- } ) as SpanClass ;
244
+ } ) ;
229
245
} ) ;
230
246
}
231
247
} ;
@@ -248,7 +264,7 @@ export class Vue implements Integration {
248
264
// However, on the second call (after), it'll be already in place.
249
265
if ( span ) {
250
266
span . finish ( ) ;
251
- this . _finishRootSpan ( now ) ;
267
+ this . _finishRootSpan ( now , getCurrentHub ) ;
252
268
} else {
253
269
vm . $once ( `hook:${ hook } ` , ( ) => {
254
270
if ( this . _rootSpan ) {
@@ -277,17 +293,22 @@ export class Vue implements Integration {
277
293
} ;
278
294
279
295
/** Finish top-level span and activity with a debounce configured using `timeout` option */
280
- private _finishRootSpan ( timestamp : number ) : void {
296
+ private _finishRootSpan ( timestamp : number , getCurrentHub : ( ) => Hub ) : void {
281
297
if ( this . _rootSpanTimer ) {
282
298
clearTimeout ( this . _rootSpanTimer ) ;
283
299
}
284
300
285
301
this . _rootSpanTimer = setTimeout ( ( ) => {
286
302
if ( this . _rootSpan ) {
287
- this . _rootSpan . timestamp = timestamp ;
303
+ ( ( this . _rootSpan as unknown ) as { timestamp : number } ) . timestamp = timestamp ;
288
304
}
289
305
if ( this . _tracingActivity ) {
290
- APMIntegrations . Tracing . popActivity ( this . _tracingActivity ) ;
306
+ // We do this whole dance with `TRACING_GETTER` to prevent `@sentry/apm` from becoming a peerDependency.
307
+ // We also need to ask for the `.constructor`, as `pushActivity` and `popActivity` are static, not instance methods.
308
+ const tracingIntegration = getCurrentHub ( ) . getIntegration ( TRACING_GETTER ) ;
309
+ if ( tracingIntegration ) {
310
+ ( tracingIntegration as any ) . constructor . popActivity ( this . _tracingActivity ) ;
311
+ }
291
312
}
292
313
} , this . _options . tracingOptions . timeout ) ;
293
314
}
@@ -298,8 +319,7 @@ export class Vue implements Integration {
298
319
299
320
this . _options . Vue . mixin ( {
300
321
beforeCreate ( this : ViewModel ) : void {
301
- // TODO: Move this check to `setupOnce` when we rework integrations initialization in v6
302
- if ( getCurrentHub ( ) . getIntegration ( APMIntegrations . Tracing ) ) {
322
+ if ( getCurrentHub ( ) . getIntegration ( TRACING_GETTER ) ) {
303
323
// `this` points to currently rendered component
304
324
applyTracingHooks ( this , getCurrentHub ) ;
305
325
} else {
0 commit comments