12
12
13
13
/* eslint-env browser */
14
14
15
- /**
16
- * log RUM if part of the sample.
17
- * @param {string } checkpoint identifies the checkpoint in funnel
18
- * @param {Object } data additional data for RUM sample
19
- * @param {string } data.source DOM node that is the source of a checkpoint event,
20
- * identified by #id or .classname
21
- * @param {string } data.target subject of the checkpoint event,
22
- * for instance the href of a link, or a search term
23
- */
24
- function sampleRUM ( checkpoint , data = { } ) {
25
- sampleRUM . defer = sampleRUM . defer || [ ] ;
26
- const defer = ( fnname ) => {
27
- sampleRUM [ fnname ] = sampleRUM [ fnname ] || ( ( ...args ) => sampleRUM . defer . push ( { fnname, args } ) ) ;
28
- } ;
29
- sampleRUM . drain = sampleRUM . drain
30
- || ( ( dfnname , fn ) => {
31
- sampleRUM [ dfnname ] = fn ;
32
- sampleRUM . defer
33
- . filter ( ( { fnname } ) => dfnname === fnname )
34
- . forEach ( ( { fnname, args } ) => sampleRUM [ fnname ] ( ...args ) ) ;
35
- } ) ;
36
- sampleRUM . always = sampleRUM . always || [ ] ;
37
- sampleRUM . always . on = ( chkpnt , fn ) => {
38
- sampleRUM . always [ chkpnt ] = fn ;
39
- } ;
40
- sampleRUM . on = ( chkpnt , fn ) => {
41
- sampleRUM . cases [ chkpnt ] = fn ;
42
- } ;
43
- defer ( 'observe' ) ;
44
- defer ( 'cwv' ) ;
15
+ function sampleRUM ( checkpoint , data ) {
16
+ // eslint-disable-next-line max-len
17
+ const timeShift = ( ) => ( window . performance ? window . performance . now ( ) : Date . now ( ) - window . hlx . rum . firstReadTime ) ;
45
18
try {
46
19
window . hlx = window . hlx || { } ;
20
+ sampleRUM . enhance = ( ) => { } ;
47
21
if ( ! window . hlx . rum ) {
48
- const usp = new URLSearchParams ( window . location . search ) ;
49
- const weight = usp . get ( 'rum' ) === 'on' ? 1 : 100 ; // with parameter, weight is 1. Defaults to 100.
50
- const id = Array . from ( { length : 75 } , ( _ , i ) => String . fromCharCode ( 48 + i ) )
51
- . filter ( ( a ) => / \d | [ A - Z ] / i. test ( a ) )
52
- . filter ( ( ) => Math . random ( ) * 75 > 70 )
53
- . join ( '' ) ;
54
- const random = Math . random ( ) ;
55
- const isSelected = random * weight < 1 ;
56
- const firstReadTime = Date . now ( ) ;
57
- const urlSanitizers = {
58
- full : ( ) => window . location . href ,
59
- origin : ( ) => window . location . origin ,
60
- path : ( ) => window . location . href . replace ( / \? .* $ / , '' ) ,
61
- } ;
22
+ const param = new URLSearchParams ( window . location . search ) . get ( 'rum' ) ;
23
+ const weight = ( window . SAMPLE_PAGEVIEWS_AT_RATE === 'high' && 10 )
24
+ || ( window . SAMPLE_PAGEVIEWS_AT_RATE === 'low' && 1000 )
25
+ || ( param === 'on' && 1 )
26
+ || 100 ;
27
+ const id = Math . random ( ) . toString ( 36 ) . slice ( - 4 ) ;
28
+ const isSelected = param !== 'off' && Math . random ( ) * weight < 1 ;
62
29
// eslint-disable-next-line object-curly-newline, max-len
63
30
window . hlx . rum = {
64
31
weight,
65
32
id,
66
- random,
67
33
isSelected,
68
- firstReadTime,
34
+ firstReadTime : window . performance ? window . performance . timeOrigin : Date . now ( ) ,
69
35
sampleRUM,
70
- sanitizeURL : urlSanitizers [ window . hlx . RUM_MASK_URL || 'path' ] ,
36
+ queue : [ ] ,
37
+ collector : ( ...args ) => window . hlx . rum . queue . push ( args ) ,
71
38
} ;
72
- }
73
- const { weight, id, firstReadTime } = window . hlx . rum ;
74
- if ( window . hlx && window . hlx . rum && window . hlx . rum . isSelected ) {
75
- const knownProperties = [
76
- 'weight' ,
77
- 'id' ,
78
- 'referer' ,
79
- 'checkpoint' ,
80
- 't' ,
81
- 'source' ,
82
- 'target' ,
83
- 'cwv' ,
84
- 'CLS' ,
85
- 'FID' ,
86
- 'LCP' ,
87
- 'INP' ,
88
- ] ;
89
- const sendPing = ( pdata = data ) => {
90
- // eslint-disable-next-line object-curly-newline, max-len, no-use-before-define
91
- const body = JSON . stringify (
92
- {
39
+ if ( isSelected ) {
40
+ const dataFromErrorObj = ( error ) => {
41
+ const errData = { source : 'undefined error' } ;
42
+ try {
43
+ errData . target = error . toString ( ) ;
44
+ errData . source = error . stack
45
+ . split ( '\n' )
46
+ . filter ( ( line ) => line . match ( / h t t p s ? : \/ \/ / ) )
47
+ . shift ( )
48
+ . replace ( / a t ( [ ^ ] + ) \( ( .+ ) \) / , '$1@$2' )
49
+ . replace ( / a t / , '@' )
50
+ . trim ( ) ;
51
+ } catch ( err ) {
52
+ /* error structure was not as expected */
53
+ }
54
+ return errData ;
55
+ } ;
56
+
57
+ window . addEventListener ( 'error' , ( { error } ) => {
58
+ const errData = dataFromErrorObj ( error ) ;
59
+ sampleRUM ( 'error' , errData ) ;
60
+ } ) ;
61
+
62
+ window . addEventListener ( 'unhandledrejection' , ( { reason } ) => {
63
+ let errData = {
64
+ source : 'Unhandled Rejection' ,
65
+ target : reason || 'Unknown' ,
66
+ } ;
67
+ if ( reason instanceof Error ) {
68
+ errData = dataFromErrorObj ( reason ) ;
69
+ }
70
+ sampleRUM ( 'error' , errData ) ;
71
+ } ) ;
72
+
73
+ sampleRUM . baseURL = sampleRUM . baseURL || new URL ( window . RUM_BASE || '/' , new URL ( 'https://rum.hlx.page' ) ) ;
74
+ sampleRUM . collectBaseURL = sampleRUM . collectBaseURL || sampleRUM . baseURL ;
75
+ sampleRUM . sendPing = ( ck , time , pingData = { } ) => {
76
+ // eslint-disable-next-line max-len, object-curly-newline
77
+ const rumData = JSON . stringify ( {
93
78
weight,
94
79
id,
95
- referer : window . hlx . rum . sanitizeURL ( ) ,
96
- checkpoint,
97
- t : Date . now ( ) - firstReadTime ,
98
- ...data ,
99
- } ,
100
- knownProperties ,
101
- ) ;
102
- const url = `https://rum.hlx.page/.rum/${ weight } ` ;
103
- // eslint-disable-next-line no-unused-expressions
104
- navigator . sendBeacon ( url , body ) ;
105
- // eslint-disable-next-line no-console
106
- console . debug ( `ping:${ checkpoint } ` , pdata ) ;
107
- } ;
108
- sampleRUM . cases = sampleRUM . cases || {
109
- cwv : ( ) => sampleRUM . cwv ( data ) || true ,
110
- lazy : ( ) => {
111
- // use classic script to avoid CORS issues
80
+ referer : window . location . href ,
81
+ checkpoint : ck ,
82
+ t : time ,
83
+ ...pingData ,
84
+ } ) ;
85
+ const urlParams = window . RUM_PARAMS
86
+ ? `?${ new URLSearchParams ( window . RUM_PARAMS ) . toString ( ) } `
87
+ : '' ;
88
+ const { href : url , origin } = new URL (
89
+ `.rum/${ weight } ${ urlParams } ` ,
90
+ sampleRUM . collectBaseURL ,
91
+ ) ;
92
+ const body = origin === window . location . origin
93
+ ? new Blob ( [ rumData ] , { type : 'application/json' } )
94
+ : rumData ;
95
+ navigator . sendBeacon ( url , body ) ;
96
+ // eslint-disable-next-line no-console
97
+ console . debug ( `ping:${ ck } ` , pingData ) ;
98
+ } ;
99
+ sampleRUM . sendPing ( 'top' , timeShift ( ) ) ;
100
+
101
+ sampleRUM . enhance = ( ) => {
102
+ // only enhance once
103
+ if ( document . querySelector ( 'script[src*="rum-enhancer"]' ) ) return ;
104
+ const { enhancerVersion, enhancerHash } = sampleRUM . enhancerContext || { } ;
112
105
const script = document . createElement ( 'script' ) ;
113
- script . src = 'https://rum.hlx.page/.rum/@adobe/helix-rum-enhancer@^1/src/index.js' ;
106
+ if ( enhancerHash ) {
107
+ script . integrity = enhancerHash ;
108
+ script . setAttribute ( 'crossorigin' , 'anonymous' ) ;
109
+ }
110
+ script . src = new URL (
111
+ `.rum/@adobe/helix-rum-enhancer@${ enhancerVersion || '^2' } /src/index.js` ,
112
+ sampleRUM . baseURL ,
113
+ ) . href ;
114
114
document . head . appendChild ( script ) ;
115
- return true ;
116
- } ,
117
- } ;
118
- sendPing ( data ) ;
119
- if ( sampleRUM . cases [ checkpoint ] ) {
120
- sampleRUM . cases [ checkpoint ] ( ) ;
115
+ } ;
116
+ if ( ! window . hlx . RUM_MANUAL_ENHANCE ) {
117
+ sampleRUM . enhance ( ) ;
118
+ }
121
119
}
122
120
}
123
- if ( sampleRUM . always [ checkpoint ] ) {
124
- sampleRUM . always [ checkpoint ] ( data ) ;
121
+ if ( window . hlx . rum && window . hlx . rum . isSelected && checkpoint ) {
122
+ window . hlx . rum . collector ( checkpoint , data , timeShift ( ) ) ;
125
123
}
124
+ document . dispatchEvent ( new CustomEvent ( 'rum' , { detail : { checkpoint, data } } ) ) ;
126
125
} catch ( error ) {
127
- // something went wrong
126
+ // something went awry
128
127
}
129
128
}
130
129
@@ -134,6 +133,7 @@ function sampleRUM(checkpoint, data = {}) {
134
133
function setup ( ) {
135
134
window . hlx = window . hlx || { } ;
136
135
window . hlx . RUM_MASK_URL = 'full' ;
136
+ window . hlx . RUM_MANUAL_ENHANCE = true ;
137
137
window . hlx . codeBasePath = '' ;
138
138
window . hlx . lighthouse = new URLSearchParams ( window . location . search ) . get ( 'lighthouse' ) === 'on' ;
139
139
@@ -154,17 +154,7 @@ function setup() {
154
154
155
155
function init ( ) {
156
156
setup ( ) ;
157
- sampleRUM ( 'top' ) ;
158
-
159
- window . addEventListener ( 'load' , ( ) => sampleRUM ( 'load' ) ) ;
160
-
161
- window . addEventListener ( 'unhandledrejection' , ( event ) => {
162
- sampleRUM ( 'error' , { source : event . reason . sourceURL , target : event . reason . line } ) ;
163
- } ) ;
164
-
165
- window . addEventListener ( 'error' , ( event ) => {
166
- sampleRUM ( 'error' , { source : event . filename , target : event . lineno } ) ;
167
- } ) ;
157
+ sampleRUM ( ) ;
168
158
}
169
159
170
160
/**
0 commit comments