@@ -20,13 +20,13 @@ import {
2020 SpanKind ,
2121 RootSpan ,
2222} from '@opencensus/web-core' ;
23- import { AsyncTask } from './zone-types' ;
23+ import { AsyncTask , InteractionName } from './zone-types' ;
2424import {
2525 OnPageInteractionStopwatch ,
2626 startOnPageInteraction ,
2727} from './on-page-interaction-stop-watch' ;
2828
29- import { isTrackedTask } from './util' ;
29+ import { isTrackedTask , getTraceId , resolveInteractionName } from './util' ;
3030import { interceptXhrTask } from './xhr-interceptor' ;
3131
3232// Allows us to monkey patch Zone prototype without TS compiler errors.
@@ -59,7 +59,6 @@ export class InteractionTracker {
5959 this . patchZoneRunTask ( ) ;
6060 this . patchZoneScheduleTask ( ) ;
6161 this . patchZoneCancelTask ( ) ;
62- this . patchHistoryApi ( ) ;
6362 }
6463
6564 static startTracking ( ) : void {
@@ -147,11 +146,11 @@ export class InteractionTracker {
147146 interceptingElement : HTMLElement ,
148147 eventName : string ,
149148 taskZone : Zone ,
150- interactionName : string
149+ interactionName : InteractionName
151150 ) {
152151 const traceId = randomTraceId ( ) ;
153152 const spanOptions = {
154- name : interactionName ,
153+ name : interactionName . name ,
155154 spanContext : {
156155 traceId,
157156 // This becomes the parentSpanId field of the root span, and the actual
@@ -168,6 +167,8 @@ export class InteractionTracker {
168167 // to capture the new zone, also, start the `OnPageInteraction` to capture the
169168 // new root span.
170169 this . currentEventTracingZone = Zone . current ;
170+ this . currentEventTracingZone . get ( 'data' ) [ 'isRootSpanNameReplaceable' ] =
171+ interactionName . isReplaceable ;
171172 this . interactions [ traceId ] = startOnPageInteraction ( {
172173 startLocationHref : location . href ,
173174 startLocationPath : location . pathname ,
@@ -266,81 +267,6 @@ export class InteractionTracker {
266267 stopWatch . stopAndRecord ( ) ;
267268 delete this . interactions [ interactionId ] ;
268269 }
269-
270- // Monkey-patch `History API` to detect route transitions.
271- // This is necessary because there might be some cases when
272- // there are several interactions being tracked at the same time
273- // but if there is an user interaction that triggers a route transition
274- // while those interactions are still in tracking, only that interaction
275- // will have a `Navigation` name. Otherwise, if this is not patched, the
276- // other interactions will change the name to `Navigation` even if they
277- // did not cause the route transition.
278- private patchHistoryApi ( ) {
279- const pushState = history . pushState ;
280- history . pushState = (
281- data : unknown ,
282- title : string ,
283- url ?: string | null | undefined
284- ) => {
285- patchHistoryApiMethod ( pushState , data , title , url ) ;
286- } ;
287-
288- const replaceState = history . replaceState ;
289- history . replaceState = (
290- data : unknown ,
291- title : string ,
292- url ?: string | null | undefined
293- ) => {
294- patchHistoryApiMethod ( replaceState , data , title , url ) ;
295- } ;
296-
297- const back = history . back ;
298- history . back = ( ) => {
299- patchHistoryApiMethod ( back ) ;
300- } ;
301-
302- const forward = history . forward ;
303- history . forward = ( ) => {
304- patchHistoryApiMethod ( forward ) ;
305- } ;
306-
307- const go = history . go ;
308- history . go = ( delta ?: number ) => {
309- patchHistoryApiMethod ( go , delta ) ;
310- } ;
311-
312- const patchHistoryApiMethod = ( func : Function , ...args : unknown [ ] ) => {
313- // Store the location.pathname before it changes calling `func`.
314- const currentPathname = location . pathname ;
315- func . call ( history , ...args ) ;
316- this . maybeUpdateInteractionName ( currentPathname ) ;
317- } ;
318- }
319-
320- private maybeUpdateInteractionName ( previousLocationPathname : string ) {
321- const rootSpan = tracing . tracer . currentRootSpan ;
322- // If for this interaction, the developer did not give any
323- // explicit attibute (`data-ocweb-id`) the current interaction
324- // name will start with a '<' that stands to the tag name. If that is
325- // the case, change the name to `Navigation <pathname>` as this is a more
326- // understadable name for the interaction.
327- // Also, we check if the location pathname did change.
328- if (
329- rootSpan &&
330- rootSpan . name . startsWith ( '<' ) &&
331- previousLocationPathname !== location . pathname
332- ) {
333- rootSpan . name = 'Navigation ' + location . pathname ;
334- }
335- }
336- }
337-
338- /**
339- * Get the trace ID from the zone properties.
340- * @param zone
341- */
342- function getTraceId ( zone : Zone ) : string {
343- return zone && zone . get ( 'data' ) ? zone . get ( 'data' ) . traceId : '' ;
344270}
345271
346272function getTrackedElement ( task : AsyncTask ) : HTMLElement | null {
@@ -349,39 +275,6 @@ function getTrackedElement(task: AsyncTask): HTMLElement | null {
349275 return task . target as HTMLElement ;
350276}
351277
352- /**
353- * Look for 'data-ocweb-id' attibute in the HTMLElement in order to
354- * give a name to the user interaction and Root span. If this attibute is
355- * not present, use the element ID, tag name, event that triggered the interaction.
356- * Thus, the resulting interaction name will be: "tag_name> id:'ID' event"
357- * (e.g. "<BUTTON> id:'save_changes' click").
358- * In case the the name is not resolvable, return empty string (e.g. element is the document).
359- * @param element
360- */
361- function resolveInteractionName (
362- element : HTMLElement | null ,
363- eventName : string
364- ) : string {
365- if ( ! element ) return '' ;
366- if ( ! element . getAttribute ) return '' ;
367- if ( element . hasAttribute ( 'disabled' ) ) {
368- return '' ;
369- }
370- let interactionName = element . getAttribute ( 'data-ocweb-id' ) ;
371- if ( ! interactionName ) {
372- const elementId = element . getAttribute ( 'id' ) || '' ;
373- const tagName = element . tagName ;
374- if ( ! tagName ) return '' ;
375- interactionName =
376- '<' +
377- tagName +
378- '>' +
379- ( elementId ? " id:'" + elementId + "' " : '' ) +
380- eventName ;
381- }
382- return interactionName ;
383- }
384-
385278/**
386279 * Whether or not a task should be tracked as part of an interaction.
387280 */
@@ -394,8 +287,8 @@ function shouldCountTask(task: Task): boolean {
394287 // This case only applies for `setInterval` as we support `setTimeout`.
395288 // TODO: ideally OpenCensus Web can manage this kind of tasks, so for example
396289 // if a periodic task ends up doing some work in the future it will still
397- // be associated with that same older tracing zone. This is something we have to
398- // think of.
290+ // be associated with that same older tracing zone. This is something we have
291+ // to think of.
399292 if ( task . data . isPeriodic ) return false ;
400293
401294 // We're only interested in macroTasks and microTasks.
0 commit comments