1515 * @param {string } checkpoint identifies the checkpoint in funnel
1616 * @param {Object } data additional data for RUM sample
1717 */
18- export function sampleRUM ( checkpoint , data = { } ) {
19- sampleRUM . defer = sampleRUM . defer || [ ] ;
20- const defer = ( fnname ) => {
21- sampleRUM [ fnname ] = sampleRUM [ fnname ]
22- || ( ( ...args ) => sampleRUM . defer . push ( { fnname, args } ) ) ;
23- } ;
24- sampleRUM . drain = sampleRUM . drain
25- || ( ( dfnname , fn ) => {
26- sampleRUM [ dfnname ] = fn ;
27- sampleRUM . defer
28- . filter ( ( { fnname } ) => dfnname === fnname )
29- . forEach ( ( { fnname, args } ) => sampleRUM [ fnname ] ( ...args ) ) ;
30- } ) ;
31- sampleRUM . on = ( chkpnt , fn ) => { sampleRUM . cases [ chkpnt ] = fn ; } ;
32- defer ( 'observe' ) ;
33- defer ( 'cwv' ) ;
18+ export function sampleRUM ( checkpoint , data ) {
19+ // eslint-disable-next-line max-len
20+ const timeShift = ( ) => ( window . performance ? window . performance . now ( ) : Date . now ( ) - window . hlx . rum . firstReadTime ) ;
3421 try {
3522 window . hlx = window . hlx || { } ;
23+ sampleRUM . enhance = ( ) => { } ;
3624 if ( ! window . hlx . rum ) {
37- const usp = new URLSearchParams ( window . location . search ) ;
38- const weight = ( usp . get ( 'rum' ) === 'on' ) ? 1 : 100 ; // with parameter, weight is 1. Defaults to 100.
39- // eslint-disable-next-line no-bitwise
40- const hashCode = ( s ) => s . split ( '' ) . reduce ( ( a , b ) => ( ( ( a << 5 ) - a ) + b . charCodeAt ( 0 ) ) | 0 , 0 ) ;
41- const id = `${ hashCode ( window . location . href ) } -${ new Date ( ) . getTime ( ) } -${ Math . random ( ) . toString ( 16 ) . substr ( 2 , 14 ) } ` ;
42- const random = Math . random ( ) ;
43- const isSelected = ( random * weight < 1 ) ;
44- const urlSanitizers = {
45- full : ( ) => window . location . href ,
46- origin : ( ) => window . location . origin ,
47- path : ( ) => window . location . pathname ,
48- } ;
25+ const param = new URLSearchParams ( window . location . search ) . get ( 'rum' ) ;
26+ const weight = ( window . SAMPLE_PAGEVIEWS_AT_RATE === 'high' && 10 )
27+ || ( window . SAMPLE_PAGEVIEWS_AT_RATE === 'low' && 1000 )
28+ || ( param === 'on' && 1 )
29+ || 100 ;
30+ const id = Math . random ( ) . toString ( 36 ) . slice ( - 4 ) ;
31+ const isSelected = param !== 'off' && Math . random ( ) * weight < 1 ;
4932 // eslint-disable-next-line object-curly-newline, max-len
50- window . hlx . rum = { weight, id, random, isSelected, sampleRUM, sanitizeURL : urlSanitizers [ window . hlx . RUM_MASK_URL || 'path' ] } ;
51- }
52- const { weight, id } = window . hlx . rum ;
53- if ( window . hlx && window . hlx . rum && window . hlx . rum . isSelected ) {
54- const sendPing = ( pdata = data ) => {
55- // eslint-disable-next-line object-curly-newline, max-len, no-use-before-define
56- const body = JSON . stringify ( { weight, id, referer : window . hlx . rum . sanitizeURL ( ) , checkpoint, ...data } ) ;
57- const url = `https://rum.hlx.page/.rum/${ weight } ` ;
58- // eslint-disable-next-line no-unused-expressions
59- navigator . sendBeacon ( url , body ) ;
60- // eslint-disable-next-line no-console
61- console . debug ( `ping:${ checkpoint } ` , pdata ) ;
33+ window . hlx . rum = {
34+ weight,
35+ id,
36+ isSelected,
37+ firstReadTime : window . performance ? window . performance . timeOrigin : Date . now ( ) ,
38+ sampleRUM,
39+ queue : [ ] ,
40+ collector : ( ...args ) => window . hlx . rum . queue . push ( args ) ,
6241 } ;
63- sampleRUM . cases = sampleRUM . cases || {
64- cwv : ( ) => sampleRUM . cwv ( data ) || true ,
65- lazy : ( ) => {
66- // use classic script to avoid CORS issues
42+ if ( isSelected ) {
43+ const dataFromErrorObj = ( error ) => {
44+ const errData = { source : 'undefined error' } ;
45+ try {
46+ errData . target = error . toString ( ) ;
47+ errData . source = error . stack
48+ . split ( '\n' )
49+ . filter ( ( line ) => line . match ( / h t t p s ? : \/ \/ / ) )
50+ . shift ( )
51+ . replace ( / a t ( [ ^ ] + ) \( ( .+ ) \) / , '$1@$2' )
52+ . replace ( / a t / , '@' )
53+ . trim ( ) ;
54+ } catch ( err ) {
55+ /* error structure was not as expected */
56+ }
57+ return errData ;
58+ } ;
59+
60+ window . addEventListener ( 'error' , ( { error } ) => {
61+ const errData = dataFromErrorObj ( error ) ;
62+ sampleRUM ( 'error' , errData ) ;
63+ } ) ;
64+
65+ window . addEventListener ( 'unhandledrejection' , ( { reason } ) => {
66+ let errData = {
67+ source : 'Unhandled Rejection' ,
68+ target : reason || 'Unknown' ,
69+ } ;
70+ if ( reason instanceof Error ) {
71+ errData = dataFromErrorObj ( reason ) ;
72+ }
73+ sampleRUM ( 'error' , errData ) ;
74+ } ) ;
75+
76+ sampleRUM . baseURL = sampleRUM . baseURL || new URL ( window . RUM_BASE || '/' , new URL ( 'https://rum.hlx.page' ) ) ;
77+ sampleRUM . collectBaseURL = sampleRUM . collectBaseURL || sampleRUM . baseURL ;
78+ sampleRUM . sendPing = ( ck , time , pingData = { } ) => {
79+ // eslint-disable-next-line max-len, object-curly-newline
80+ const rumData = JSON . stringify ( {
81+ weight,
82+ id,
83+ referer : window . location . href ,
84+ checkpoint : ck ,
85+ t : time ,
86+ ...pingData ,
87+ } ) ;
88+ const urlParams = window . RUM_PARAMS
89+ ? `?${ new URLSearchParams ( window . RUM_PARAMS ) . toString ( ) } `
90+ : '' ;
91+ const { href : url , origin } = new URL (
92+ `.rum/${ weight } ${ urlParams } ` ,
93+ sampleRUM . collectBaseURL ,
94+ ) ;
95+ const body = origin === window . location . origin
96+ ? new Blob ( [ rumData ] , { type : 'application/json' } )
97+ : rumData ;
98+ navigator . sendBeacon ( url , body ) ;
99+ // eslint-disable-next-line no-console
100+ console . debug ( `ping:${ ck } ` , pingData ) ;
101+ } ;
102+ sampleRUM . sendPing ( 'top' , timeShift ( ) ) ;
103+
104+ sampleRUM . enhance = ( ) => {
105+ // only enhance once
106+ if ( document . querySelector ( 'script[src*="rum-enhancer"]' ) ) return ;
107+ const { enhancerVersion, enhancerHash } = sampleRUM . enhancerContext || { } ;
67108 const script = document . createElement ( 'script' ) ;
68- script . src = 'https://rum.hlx.page/.rum/@adobe/helix-rum-enhancer@^1/src/index.js' ;
109+ if ( enhancerHash ) {
110+ script . integrity = enhancerHash ;
111+ script . setAttribute ( 'crossorigin' , 'anonymous' ) ;
112+ }
113+ script . src = new URL (
114+ `.rum/@adobe/helix-rum-enhancer@${ enhancerVersion || '^2' } /src/index.js` ,
115+ sampleRUM . baseURL ,
116+ ) . href ;
69117 document . head . appendChild ( script ) ;
70- return true ;
71- } ,
72- } ;
73- sendPing ( data ) ;
74- if ( sampleRUM . cases [ checkpoint ] ) { sampleRUM . cases [ checkpoint ] ( ) ; }
118+ } ;
119+ if ( ! window . hlx . RUM_MANUAL_ENHANCE ) {
120+ sampleRUM . enhance ( ) ;
121+ }
122+ }
123+ }
124+ if ( window . hlx . rum && window . hlx . rum . isSelected && checkpoint ) {
125+ window . hlx . rum . collector ( checkpoint , data , timeShift ( ) ) ;
75126 }
127+ document . dispatchEvent ( new CustomEvent ( 'rum' , { detail : { checkpoint, data } } ) ) ;
76128 } catch ( error ) {
77- // something went wrong
129+ // something went awry
78130 }
79131}
80132
@@ -344,6 +396,9 @@ export function updateSectionsStatus(main) {
344396 } else {
345397 section . dataset . sectionStatus = 'loaded' ;
346398 section . style . display = null ;
399+ if ( i === 0 && sampleRUM . enhance ) {
400+ sampleRUM . enhance ( ) ;
401+ }
347402 }
348403 }
349404 }
@@ -606,6 +661,7 @@ export function loadFooter(footer) {
606661export function setup ( ) {
607662 window . hlx = window . hlx || { } ;
608663 window . hlx . RUM_MASK_URL = 'full' ;
664+ window . hlx . RUM_MANUAL_ENHANCE = true ;
609665 window . hlx . codeBasePath = '' ;
610666 window . hlx . lighthouse = new URLSearchParams ( window . location . search ) . get ( 'lighthouse' ) === 'on' ;
611667
@@ -626,17 +682,7 @@ export function setup() {
626682function init ( ) {
627683 document . body . style . display = 'none' ;
628684 setup ( ) ;
629- sampleRUM ( 'top' ) ;
630-
631- window . addEventListener ( 'load' , ( ) => sampleRUM ( 'load' ) ) ;
632-
633- window . addEventListener ( 'unhandledrejection' , ( event ) => {
634- sampleRUM ( 'error' , { source : event . reason . sourceURL , target : event . reason . line } ) ;
635- } ) ;
636-
637- window . addEventListener ( 'error' , ( event ) => {
638- sampleRUM ( 'error' , { source : event . filename , target : event . lineno } ) ;
639- } ) ;
685+ sampleRUM ( ) ;
640686}
641687
642688init ( ) ;
0 commit comments