1
1
/* eslint-disable max-lines */
2
2
import { Hub } from '@sentry/core' ;
3
- import { EventProcessor , Integration , Transaction , TransactionContext } from '@sentry/types' ;
3
+ import { EventProcessor , Integration , Transaction , TransactionContext , TransactionSource } from '@sentry/types' ;
4
4
import { baggageHeaderToDynamicSamplingContext , getDomElement , logger } from '@sentry/utils' ;
5
5
6
6
import { startIdleTransaction } from '../hubextensions' ;
7
- import { DEFAULT_FINAL_TIMEOUT , DEFAULT_HEARTBEAT_INTERVAL , DEFAULT_IDLE_TIMEOUT } from '../idletransaction' ;
7
+ import {
8
+ DEFAULT_FINAL_TIMEOUT ,
9
+ DEFAULT_HEARTBEAT_INTERVAL ,
10
+ DEFAULT_IDLE_TIMEOUT ,
11
+ IdleTransaction ,
12
+ } from '../idletransaction' ;
8
13
import { extractTraceparentData } from '../utils' ;
9
14
import { registerBackgroundTabDetection } from './backgroundtab' ;
10
15
import { addPerformanceEntries , startTrackingLongTasks , startTrackingWebVitals } from './metrics' ;
@@ -92,7 +97,7 @@ export interface BrowserTracingOptions extends RequestInstrumentationOptions {
92
97
*
93
98
* Default: undefined
94
99
*/
95
- _experiments ?: Partial < { enableLongTask : boolean } > ;
100
+ _experiments ?: Partial < { enableLongTask : boolean ; enableInteractions : boolean } > ;
96
101
97
102
/**
98
103
* beforeNavigate is called before a pageload/navigation transaction is created and allows users to modify transaction
@@ -125,7 +130,7 @@ const DEFAULT_BROWSER_TRACING_OPTIONS: BrowserTracingOptions = {
125
130
routingInstrumentation : instrumentRoutingWithDefaults ,
126
131
startTransactionOnLocationChange : true ,
127
132
startTransactionOnPageLoad : true ,
128
- _experiments : { enableLongTask : true } ,
133
+ _experiments : { enableLongTask : true , enableInteractions : false } ,
129
134
...defaultRequestInstrumentationOptions ,
130
135
} ;
131
136
@@ -152,6 +157,9 @@ export class BrowserTracing implements Integration {
152
157
153
158
private _getCurrentHub ?: ( ) => Hub ;
154
159
160
+ private _latestRouteName ?: string ;
161
+ private _latestRouteSource ?: TransactionSource ;
162
+
155
163
public constructor ( _options ?: Partial < BrowserTracingOptions > ) {
156
164
this . options = {
157
165
...DEFAULT_BROWSER_TRACING_OPTIONS ,
@@ -189,6 +197,7 @@ export class BrowserTracing implements Integration {
189
197
traceXHR,
190
198
tracePropagationTargets,
191
199
shouldCreateSpanForRequest,
200
+ _experiments,
192
201
} = this . options ;
193
202
194
203
instrumentRouting (
@@ -201,6 +210,10 @@ export class BrowserTracing implements Integration {
201
210
registerBackgroundTabDetection ( ) ;
202
211
}
203
212
213
+ if ( _experiments ?. enableInteractions ) {
214
+ this . _registerInteractionListener ( ) ;
215
+ }
216
+
204
217
instrumentOutgoingRequests ( {
205
218
traceFetch,
206
219
traceXHR,
@@ -252,6 +265,9 @@ export class BrowserTracing implements Integration {
252
265
? { ...finalContext . metadata , source : 'custom' }
253
266
: finalContext . metadata ;
254
267
268
+ this . _latestRouteName = finalContext . name ;
269
+ this . _latestRouteSource = finalContext . metadata ?. source ;
270
+
255
271
if ( finalContext . sampled === false ) {
256
272
__DEBUG_BUILD__ &&
257
273
logger . log ( `[Tracing] Will not send ${ finalContext . op } transaction because of beforeNavigate.` ) ;
@@ -277,6 +293,57 @@ export class BrowserTracing implements Integration {
277
293
278
294
return idleTransaction as Transaction ;
279
295
}
296
+
297
+ /** Start listener for interaction transactions */
298
+ private _registerInteractionListener ( ) : void {
299
+ let inflightInteractionTransaction : IdleTransaction | undefined ;
300
+ const registerInteractionTransaction = ( ) : void => {
301
+ const { idleTimeout, finalTimeout, heartbeatInterval } = this . options ;
302
+
303
+ const op = 'ui.action.click' ;
304
+ if ( inflightInteractionTransaction ) {
305
+ inflightInteractionTransaction . finish ( ) ;
306
+ inflightInteractionTransaction = undefined ;
307
+ }
308
+
309
+ if ( ! this . _getCurrentHub ) {
310
+ __DEBUG_BUILD__ && logger . warn ( `[Tracing] Did not create ${ op } transaction because _getCurrentHub is invalid.` ) ;
311
+ return undefined ;
312
+ }
313
+
314
+ if ( ! this . _latestRouteName ) {
315
+ __DEBUG_BUILD__ &&
316
+ logger . warn ( `[Tracing] Did not create ${ op } transaction because _latestRouteName is missing.` ) ;
317
+ return undefined ;
318
+ }
319
+
320
+ const hub = this . _getCurrentHub ( ) ;
321
+ const { location } = WINDOW ;
322
+
323
+ const context : TransactionContext = {
324
+ name : this . _latestRouteName ,
325
+ op,
326
+ trimEnd : true ,
327
+ metadata : {
328
+ source : this . _latestRouteSource ?? 'url' ,
329
+ } ,
330
+ } ;
331
+
332
+ inflightInteractionTransaction = startIdleTransaction (
333
+ hub ,
334
+ context ,
335
+ idleTimeout ,
336
+ finalTimeout ,
337
+ true ,
338
+ { location } , // for use in the tracesSampler
339
+ heartbeatInterval ,
340
+ ) ;
341
+ } ;
342
+
343
+ [ 'click' ] . forEach ( type => {
344
+ addEventListener ( type , registerInteractionTransaction , { once : false , capture : true } ) ;
345
+ } ) ;
346
+ }
280
347
}
281
348
282
349
/** Returns the value of a meta tag */
0 commit comments