@cloudcare/browser-core 1.2.9 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/browser/fetchObservable.js +3 -4
- package/cjs/browser/htmlDomUtils.js +45 -0
- package/cjs/browser/pageExitObservable.js +72 -0
- package/cjs/configuration/configuration.js +8 -0
- package/cjs/configuration/transportConfiguration.js +7 -0
- package/cjs/dataMap.js +12 -4
- package/cjs/helper/deviceInfo.js +44 -2
- package/cjs/helper/enums.js +3 -0
- package/cjs/helper/getZoneJsOriginalValue.js +34 -0
- package/cjs/helper/instrumentMethod.js +7 -1
- package/cjs/helper/lifeCycle.js +2 -6
- package/cjs/helper/readBytesFromStream.js +74 -0
- package/cjs/helper/tools.js +124 -47
- package/cjs/index.js +52 -0
- package/cjs/session/sessionStore.js +1 -1
- package/cjs/transport/batch.js +7 -44
- package/cjs/transport/httpRequest.js +4 -2
- package/cjs/transport/sendWithRetryStrategy.js +8 -8
- package/cjs/transport/startBatchWithReplica.js +2 -2
- package/esm/browser/fetchObservable.js +3 -4
- package/esm/browser/htmlDomUtils.js +26 -0
- package/esm/browser/pageExitObservable.js +57 -0
- package/esm/configuration/configuration.js +5 -0
- package/esm/configuration/transportConfiguration.js +7 -0
- package/esm/dataMap.js +9 -2
- package/esm/helper/contextHistory.js +1 -1
- package/esm/helper/deviceInfo.js +44 -2
- package/esm/helper/enums.js +3 -0
- package/esm/helper/getZoneJsOriginalValue.js +27 -0
- package/esm/helper/instrumentMethod.js +6 -1
- package/esm/helper/lifeCycle.js +2 -6
- package/esm/helper/readBytesFromStream.js +67 -0
- package/esm/helper/tools.js +100 -45
- package/esm/index.js +4 -0
- package/esm/session/sessionStore.js +1 -1
- package/esm/transport/batch.js +8 -45
- package/esm/transport/httpRequest.js +4 -2
- package/esm/transport/sendWithRetryStrategy.js +8 -8
- package/esm/transport/startBatchWithReplica.js +2 -2
- package/package.json +2 -2
- package/src/browser/fetchObservable.js +21 -17
- package/src/browser/htmlDomUtils.js +35 -0
- package/src/browser/pageExitObservable.js +70 -0
- package/src/configuration/configuration.js +6 -0
- package/src/configuration/transportConfiguration.js +30 -6
- package/src/dataMap.js +9 -2
- package/src/helper/contextHistory.js +1 -1
- package/src/helper/deviceInfo.js +39 -3
- package/src/helper/enums.js +40 -37
- package/src/helper/getZoneJsOriginalValue.js +27 -0
- package/src/helper/instrumentMethod.js +40 -50
- package/src/helper/lifeCycle.js +2 -7
- package/src/helper/readBytesFromStream.js +69 -0
- package/src/helper/tools.js +114 -45
- package/src/index.js +4 -1
- package/src/session/sessionStore.js +27 -24
- package/src/synthetics/syntheticsWorkerValues.js +11 -7
- package/src/transport/batch.js +70 -81
- package/src/transport/httpRequest.js +25 -25
- package/src/transport/sendWithRetryStrategy.js +14 -9
- package/src/transport/startBatchWithReplica.js +11 -5
|
@@ -13,7 +13,7 @@ export function initFetchObservable() {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
function createFetchObservable() {
|
|
16
|
-
var observable = new Observable(function() {
|
|
16
|
+
var observable = new Observable(function () {
|
|
17
17
|
if (!window.fetch) {
|
|
18
18
|
return
|
|
19
19
|
}
|
|
@@ -21,19 +21,23 @@ function createFetchObservable() {
|
|
|
21
21
|
var fetchMethod = instrumentMethod(
|
|
22
22
|
window,
|
|
23
23
|
'fetch',
|
|
24
|
-
function(originalFetch) {
|
|
24
|
+
function (originalFetch) {
|
|
25
25
|
return function (input, init) {
|
|
26
26
|
var responsePromise
|
|
27
27
|
var context = beforeSend(observable, input, init)
|
|
28
28
|
if (context) {
|
|
29
|
-
responsePromise = originalFetch.call(
|
|
29
|
+
responsePromise = originalFetch.call(
|
|
30
|
+
this,
|
|
31
|
+
context.input,
|
|
32
|
+
context.init
|
|
33
|
+
)
|
|
30
34
|
afterSend(observable, responsePromise, context)
|
|
31
35
|
} else {
|
|
32
36
|
responsePromise = originalFetch.call(this, input, init)
|
|
33
37
|
}
|
|
34
38
|
return responsePromise
|
|
35
39
|
}
|
|
36
|
-
}
|
|
40
|
+
}
|
|
37
41
|
)
|
|
38
42
|
return fetchMethod.stop
|
|
39
43
|
})
|
|
@@ -42,7 +46,10 @@ function createFetchObservable() {
|
|
|
42
46
|
}
|
|
43
47
|
|
|
44
48
|
function beforeSend(observable, input, init) {
|
|
45
|
-
var method =
|
|
49
|
+
var method =
|
|
50
|
+
(init && init.method) ||
|
|
51
|
+
(typeof input === 'object' && input.method) ||
|
|
52
|
+
'GET'
|
|
46
53
|
var url = normalizeUrl((typeof input === 'object' && input.url) || input)
|
|
47
54
|
var startClocks = clocksNow()
|
|
48
55
|
|
|
@@ -52,7 +59,7 @@ function beforeSend(observable, input, init) {
|
|
|
52
59
|
input: input,
|
|
53
60
|
method: method,
|
|
54
61
|
startClocks: startClocks,
|
|
55
|
-
url: url
|
|
62
|
+
url: url
|
|
56
63
|
}
|
|
57
64
|
|
|
58
65
|
observable.notify(context)
|
|
@@ -60,27 +67,24 @@ function beforeSend(observable, input, init) {
|
|
|
60
67
|
return context
|
|
61
68
|
}
|
|
62
69
|
|
|
63
|
-
function afterSend(
|
|
64
|
-
|
|
65
|
-
responsePromise,
|
|
66
|
-
startContext
|
|
67
|
-
) {
|
|
68
|
-
var reportFetch = function(response) {
|
|
70
|
+
function afterSend(observable, responsePromise, startContext) {
|
|
71
|
+
var reportFetch = function (response) {
|
|
69
72
|
var context = startContext
|
|
70
|
-
context.state = '
|
|
71
|
-
context.duration = elapsed(context.startClocks.timeStamp, timeStampNow())
|
|
73
|
+
context.state = 'resolve'
|
|
74
|
+
// context.duration = elapsed(context.startClocks.timeStamp, timeStampNow())
|
|
72
75
|
if ('stack' in response || response instanceof Error) {
|
|
73
76
|
context.status = 0
|
|
74
|
-
context.isAborted =
|
|
77
|
+
context.isAborted =
|
|
78
|
+
response instanceof DOMException &&
|
|
79
|
+
response.code === DOMException.ABORT_ERR
|
|
75
80
|
context.error = response
|
|
76
|
-
observable.notify(context)
|
|
77
81
|
} else if ('status' in response) {
|
|
78
82
|
context.response = response
|
|
79
83
|
context.responseType = response.type
|
|
80
84
|
context.status = response.status
|
|
81
85
|
context.isAborted = false
|
|
82
|
-
observable.notify(context)
|
|
83
86
|
}
|
|
87
|
+
observable.notify(context)
|
|
84
88
|
}
|
|
85
89
|
responsePromise.then(reportFetch, reportFetch)
|
|
86
90
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export function isTextNode(node) {
|
|
2
|
+
return node.nodeType === Node.TEXT_NODE
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function isCommentNode(node) {
|
|
6
|
+
return node.nodeType === Node.COMMENT_NODE
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function isElementNode(node) {
|
|
10
|
+
return node.nodeType === Node.ELEMENT_NODE
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function isNodeShadowHost(node) {
|
|
14
|
+
return isElementNode(node) && Boolean(node.shadowRoot)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function isNodeShadowRoot(node) {
|
|
18
|
+
var shadowRoot = node
|
|
19
|
+
return (
|
|
20
|
+
!!shadowRoot.host &&
|
|
21
|
+
shadowRoot.nodeType === Node.DOCUMENT_FRAGMENT_NODE &&
|
|
22
|
+
isElementNode(shadowRoot.host)
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function getChildNodes(node) {
|
|
27
|
+
return isNodeShadowHost(node) ? node.shadowRoot.childNodes : node.childNodes
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Return `host` in case if the current node is a shadow root otherwise will return the `parentNode`
|
|
32
|
+
*/
|
|
33
|
+
export function getParentNode(node) {
|
|
34
|
+
return isNodeShadowRoot(node) ? node.host : node.parentNode
|
|
35
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Observable } from '../helper/observable'
|
|
2
|
+
import {
|
|
3
|
+
addEventListener,
|
|
4
|
+
addEventListeners,
|
|
5
|
+
includes,
|
|
6
|
+
values
|
|
7
|
+
} from '../helper/tools'
|
|
8
|
+
import { DOM_EVENT } from '../helper/enums'
|
|
9
|
+
export var PageExitReason = {
|
|
10
|
+
HIDDEN: 'visibility_hidden',
|
|
11
|
+
UNLOADING: 'before_unload',
|
|
12
|
+
PAGEHIDE: 'page_hide',
|
|
13
|
+
FROZEN: 'page_frozen'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function createPageExitObservable() {
|
|
17
|
+
var observable = new Observable(function () {
|
|
18
|
+
/**
|
|
19
|
+
* Only event that guarantee to fire on mobile devices when the page transitions to background state
|
|
20
|
+
* (e.g. when user switches to a different application, goes to homescreen, etc), or is being unloaded.
|
|
21
|
+
*/
|
|
22
|
+
var visibilityChangeListener = addEventListeners(
|
|
23
|
+
document,
|
|
24
|
+
[DOM_EVENT.VISIBILITY_CHANGE, DOM_EVENT.FREEZE, DOM_EVENT.PAGE_HIDE],
|
|
25
|
+
function (event) {
|
|
26
|
+
if (
|
|
27
|
+
event.type === DOM_EVENT.VISIBILITY_CHANGE &&
|
|
28
|
+
document.visibilityState === 'hidden'
|
|
29
|
+
) {
|
|
30
|
+
/**
|
|
31
|
+
* Only event that guarantee to fire on mobile devices when the page transitions to background state
|
|
32
|
+
* (e.g. when user switches to a different application, goes to homescreen, etc), or is being unloaded.
|
|
33
|
+
*/
|
|
34
|
+
observable.notify({ reason: PageExitReason.HIDDEN })
|
|
35
|
+
} else if (event.type === DOM_EVENT.FREEZE) {
|
|
36
|
+
/**
|
|
37
|
+
* After transitioning in background a tab can be freezed to preserve resources. (cf: https://developer.chrome.com/blog/page-lifecycle-api)
|
|
38
|
+
* Allow to collect events happening between hidden and frozen state.
|
|
39
|
+
*/
|
|
40
|
+
observable.notify({ reason: PageExitReason.FROZEN })
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
{ capture: true }
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Safari does not support yet to send a request during:
|
|
48
|
+
* - a visibility change during doc unload (cf: https://bugs.webkit.org/show_bug.cgi?id=194897)
|
|
49
|
+
* - a page hide transition (cf: https://bugs.webkit.org/show_bug.cgi?id=188329)
|
|
50
|
+
*/
|
|
51
|
+
var beforeUnloadListener = addEventListener(
|
|
52
|
+
window,
|
|
53
|
+
DOM_EVENT.BEFORE_UNLOAD,
|
|
54
|
+
function () {
|
|
55
|
+
observable.notify({ reason: PageExitReason.UNLOADING })
|
|
56
|
+
}
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
return function () {
|
|
60
|
+
visibilityChangeListener.stop()
|
|
61
|
+
beforeUnloadListener.stop()
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
return observable
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function isPageExitReason(reason) {
|
|
69
|
+
return includes(values(PageExitReason), reason)
|
|
70
|
+
}
|
|
@@ -9,6 +9,12 @@ import {
|
|
|
9
9
|
isNullUndefinedDefaultValue
|
|
10
10
|
} from '../helper/tools'
|
|
11
11
|
import { computeTransportConfiguration } from './transportConfiguration'
|
|
12
|
+
|
|
13
|
+
export var DefaultPrivacyLevel = {
|
|
14
|
+
ALLOW: 'allow',
|
|
15
|
+
MASK: 'mask',
|
|
16
|
+
MASK_USER_INPUT: 'mask-user-input'
|
|
17
|
+
}
|
|
12
18
|
export function validateAndBuildConfiguration(initConfiguration) {
|
|
13
19
|
if (
|
|
14
20
|
initConfiguration.sampleRate !== undefined &&
|
|
@@ -12,13 +12,31 @@ function getLogsEndPoint(url) {
|
|
|
12
12
|
return trim(url) + 'v1/write/logging'
|
|
13
13
|
return trim(url) + '/v1/write/logging'
|
|
14
14
|
}
|
|
15
|
+
function getSessionReplayEndPoint(url) {
|
|
16
|
+
// return 'http://localhost:3002/write_data'
|
|
17
|
+
if (url.lastIndexOf('/') === url.length - 1)
|
|
18
|
+
return trim(url) + 'v1/write/rum/replay'
|
|
19
|
+
return trim(url) + '/v1/write/rum/replay'
|
|
20
|
+
}
|
|
15
21
|
export function computeTransportConfiguration(initConfiguration) {
|
|
16
|
-
var isIntakeUrl = function(url) {
|
|
17
|
-
|
|
22
|
+
var isIntakeUrl = function (url) {
|
|
23
|
+
return false
|
|
24
|
+
}
|
|
25
|
+
if (
|
|
26
|
+
'isIntakeUrl' in initConfiguration &&
|
|
27
|
+
isFunction(initConfiguration.isIntakeUrl) &&
|
|
28
|
+
isBoolean(initConfiguration.isIntakeUrl())
|
|
29
|
+
) {
|
|
18
30
|
isIntakeUrl = initConfiguration.isIntakeUrl
|
|
19
31
|
}
|
|
20
|
-
var isServerError = function(request) {
|
|
21
|
-
|
|
32
|
+
var isServerError = function (request) {
|
|
33
|
+
return false
|
|
34
|
+
}
|
|
35
|
+
if (
|
|
36
|
+
'isServerError' in initConfiguration &&
|
|
37
|
+
isFunction(initConfiguration.isServerError) &&
|
|
38
|
+
isBoolean(initConfiguration.isServerError())
|
|
39
|
+
) {
|
|
22
40
|
isServerError = initConfiguration.isServerError
|
|
23
41
|
}
|
|
24
42
|
return {
|
|
@@ -26,10 +44,12 @@ export function computeTransportConfiguration(initConfiguration) {
|
|
|
26
44
|
initConfiguration.datakitUrl || initConfiguration.datakitOrigin
|
|
27
45
|
),
|
|
28
46
|
logsEndpoint: getLogsEndPoint(initConfiguration.datakitOrigin),
|
|
47
|
+
sessionReplayEndPoint: getSessionReplayEndPoint(
|
|
48
|
+
initConfiguration.datakitOrigin
|
|
49
|
+
),
|
|
29
50
|
isIntakeUrl: isIntakeUrl,
|
|
30
51
|
isServerError: isServerError
|
|
31
52
|
}
|
|
32
|
-
|
|
33
53
|
}
|
|
34
54
|
export function isIntakeRequest(url, configuration) {
|
|
35
55
|
// return haveSameOrigin(url, configuration.datakitUrl)
|
|
@@ -38,5 +58,9 @@ export function isIntakeRequest(url, configuration) {
|
|
|
38
58
|
notTakeRequest.push(configuration.logsEndpoint)
|
|
39
59
|
}
|
|
40
60
|
// datakit 地址,log 地址,以及客户自定义过滤方法定义url
|
|
41
|
-
return
|
|
61
|
+
return (
|
|
62
|
+
some(notTakeRequest, function (takeUrl) {
|
|
63
|
+
return url.indexOf(takeUrl) === 0
|
|
64
|
+
}) || configuration.isIntakeUrl(url)
|
|
65
|
+
)
|
|
42
66
|
}
|
package/src/dataMap.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { RumEventType } from './helper/enums'
|
|
2
2
|
export var commonTags = {
|
|
3
|
-
action_id: 'action.id',
|
|
4
3
|
sdk_name: '_dd.sdk_name',
|
|
5
4
|
sdk_version: '_dd.sdk_version',
|
|
6
5
|
app_id: 'application.id',
|
|
@@ -13,6 +12,7 @@ export var commonTags = {
|
|
|
13
12
|
session_id: 'session.id',
|
|
14
13
|
session_type: 'session.type',
|
|
15
14
|
session_sampling: 'session.is_sampling',
|
|
15
|
+
session_has_replay: 'session.has_replay',
|
|
16
16
|
is_signin: 'user.is_signin',
|
|
17
17
|
os: 'device.os',
|
|
18
18
|
os_version: 'device.os_version',
|
|
@@ -32,6 +32,10 @@ export var commonTags = {
|
|
|
32
32
|
view_path_group: 'view.path_group',
|
|
33
33
|
view_url_query: 'view.url_query'
|
|
34
34
|
}
|
|
35
|
+
export var commonFields = {
|
|
36
|
+
action_id: 'action.id',
|
|
37
|
+
view_in_foreground: 'view.in_foreground'
|
|
38
|
+
}
|
|
35
39
|
// 需要用双引号将字符串类型的field value括起来, 这里有数组标示[string, path]
|
|
36
40
|
export var dataMap = {
|
|
37
41
|
view: {
|
|
@@ -42,6 +46,7 @@ export var dataMap = {
|
|
|
42
46
|
is_active: 'view.is_active'
|
|
43
47
|
},
|
|
44
48
|
fields: {
|
|
49
|
+
session_replay_stats: '_dd.replay_stats',
|
|
45
50
|
view_error_count: 'view.error.count',
|
|
46
51
|
view_resource_count: 'view.resource.count',
|
|
47
52
|
view_long_task_count: 'view.long_task.count',
|
|
@@ -62,7 +67,9 @@ export var dataMap = {
|
|
|
62
67
|
time_to_interactive: 'view.tti',
|
|
63
68
|
dom: 'view.dom',
|
|
64
69
|
dom_ready: 'view.dom_ready',
|
|
65
|
-
time_spent: 'view.time_spent'
|
|
70
|
+
time_spent: 'view.time_spent',
|
|
71
|
+
in_foreground_periods: 'view.in_foreground_periods',
|
|
72
|
+
frustration_count: 'view.frustration.count'
|
|
66
73
|
}
|
|
67
74
|
},
|
|
68
75
|
resource: {
|
package/src/helper/deviceInfo.js
CHANGED
|
@@ -247,9 +247,45 @@ var MethodLibrary = {
|
|
|
247
247
|
},
|
|
248
248
|
// 获取网络状态
|
|
249
249
|
getNetwork: function () {
|
|
250
|
-
var
|
|
251
|
-
navigator
|
|
252
|
-
|
|
250
|
+
var connection =
|
|
251
|
+
window.navigator.connection ||
|
|
252
|
+
window.navigator.mozConnection ||
|
|
253
|
+
window.navigator.webkitConnection
|
|
254
|
+
var result = 'unknown'
|
|
255
|
+
var type = connection ? connection.type || connection.effectiveType : null
|
|
256
|
+
if (type && typeof type === 'string') {
|
|
257
|
+
switch (type) {
|
|
258
|
+
// possible type values
|
|
259
|
+
case 'bluetooth':
|
|
260
|
+
case 'cellular':
|
|
261
|
+
result = 'cellular'
|
|
262
|
+
break
|
|
263
|
+
case 'none':
|
|
264
|
+
result = 'none'
|
|
265
|
+
break
|
|
266
|
+
case 'ethernet':
|
|
267
|
+
case 'wifi':
|
|
268
|
+
case 'wimax':
|
|
269
|
+
result = 'wifi'
|
|
270
|
+
break
|
|
271
|
+
case 'other':
|
|
272
|
+
case 'unknown':
|
|
273
|
+
result = 'unknown'
|
|
274
|
+
break
|
|
275
|
+
// possible effectiveType values
|
|
276
|
+
case 'slow-2g':
|
|
277
|
+
case '2g':
|
|
278
|
+
case '3g':
|
|
279
|
+
result = 'cellular'
|
|
280
|
+
break
|
|
281
|
+
case '4g':
|
|
282
|
+
result = 'wifi'
|
|
283
|
+
break
|
|
284
|
+
default:
|
|
285
|
+
break
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return result
|
|
253
289
|
},
|
|
254
290
|
// 获取当前语言
|
|
255
291
|
getLanguage: function () {
|
package/src/helper/enums.js
CHANGED
|
@@ -1,34 +1,37 @@
|
|
|
1
1
|
export var DOM_EVENT = {
|
|
2
2
|
BEFORE_UNLOAD: 'beforeunload',
|
|
3
|
-
CLICK
|
|
4
|
-
DBL_CLICK
|
|
5
|
-
KEY_DOWN
|
|
6
|
-
LOAD
|
|
7
|
-
POP_STATE
|
|
8
|
-
SCROLL
|
|
9
|
-
TOUCH_START
|
|
10
|
-
TOUCH_END
|
|
11
|
-
TOUCH_MOVE
|
|
12
|
-
VISIBILITY_CHANGE
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
3
|
+
CLICK: 'click',
|
|
4
|
+
DBL_CLICK: 'dblclick',
|
|
5
|
+
KEY_DOWN: 'keydown',
|
|
6
|
+
LOAD: 'load',
|
|
7
|
+
POP_STATE: 'popstate',
|
|
8
|
+
SCROLL: 'scroll',
|
|
9
|
+
TOUCH_START: 'touchstart',
|
|
10
|
+
TOUCH_END: 'touchend',
|
|
11
|
+
TOUCH_MOVE: 'touchmove',
|
|
12
|
+
VISIBILITY_CHANGE: 'visibilitychange',
|
|
13
|
+
PAGE_SHOW: 'pageshow',
|
|
14
|
+
FREEZE: 'freeze',
|
|
15
|
+
RESUME: 'resume',
|
|
16
|
+
DOM_CONTENT_LOADED: 'DOMContentLoaded',
|
|
17
|
+
POINTER_DOWN: 'pointerdown',
|
|
18
|
+
POINTER_UP: 'pointerup',
|
|
19
|
+
POINTER_CANCEL: 'pointercancel',
|
|
20
|
+
HASH_CHANGE: 'hashchange',
|
|
21
|
+
PAGE_HIDE: 'pagehide',
|
|
22
|
+
MOUSE_DOWN: 'mousedown',
|
|
23
|
+
MOUSE_UP: 'mouseup',
|
|
24
|
+
MOUSE_MOVE: 'mousemove',
|
|
25
|
+
FOCUS: 'focus',
|
|
26
|
+
BLUR: 'blur',
|
|
27
|
+
CONTEXT_MENU: 'contextmenu',
|
|
28
|
+
RESIZE: 'resize',
|
|
29
|
+
CHANGE: 'change',
|
|
30
|
+
INPUT: 'input',
|
|
31
|
+
PLAY: 'play',
|
|
32
|
+
PAUSE: 'pause',
|
|
33
|
+
SECURITY_POLICY_VIOLATION: 'securitypolicyviolation',
|
|
34
|
+
SELECTION_CHANGE: 'selectionchange'
|
|
32
35
|
}
|
|
33
36
|
export var ResourceType = {
|
|
34
37
|
DOCUMENT: 'document',
|
|
@@ -48,9 +51,9 @@ export var ActionType = {
|
|
|
48
51
|
CUSTOM: 'custom'
|
|
49
52
|
}
|
|
50
53
|
export var FrustrationType = {
|
|
51
|
-
RAGE_CLICK
|
|
52
|
-
ERROR_CLICK
|
|
53
|
-
DEAD_CLICK
|
|
54
|
+
RAGE_CLICK: 'rage_click',
|
|
55
|
+
ERROR_CLICK: 'error_click',
|
|
56
|
+
DEAD_CLICK: 'dead_click'
|
|
54
57
|
}
|
|
55
58
|
export var RumEventType = {
|
|
56
59
|
ACTION: 'action',
|
|
@@ -61,9 +64,9 @@ export var RumEventType = {
|
|
|
61
64
|
LOGGER: 'logger'
|
|
62
65
|
}
|
|
63
66
|
|
|
64
|
-
export var ViewLoadingType
|
|
67
|
+
export var ViewLoadingType = {
|
|
65
68
|
INITIAL_LOAD: 'initial_load',
|
|
66
|
-
ROUTE_CHANGE: 'route_change'
|
|
69
|
+
ROUTE_CHANGE: 'route_change'
|
|
67
70
|
}
|
|
68
71
|
export var RequestType = {
|
|
69
72
|
FETCH: ResourceType.FETCH,
|
|
@@ -76,9 +79,9 @@ export var TraceType = {
|
|
|
76
79
|
ZIPKIN_SINGLE_HEADER: 'zipkin_single_header',
|
|
77
80
|
W3C_TRACEPARENT: 'w3c_traceparent',
|
|
78
81
|
SKYWALKING_V3: 'skywalking_v3',
|
|
79
|
-
JAEGER: 'jaeger'
|
|
82
|
+
JAEGER: 'jaeger'
|
|
80
83
|
}
|
|
81
84
|
export var ErrorHandling = {
|
|
82
85
|
HANDLED: 'handled',
|
|
83
|
-
UNHANDLED: 'unhandled'
|
|
84
|
-
}
|
|
86
|
+
UNHANDLED: 'unhandled'
|
|
87
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gets the original value for a DOM API that was potentially patched by Zone.js.
|
|
3
|
+
*
|
|
4
|
+
* Zone.js[1] is a library that patches a bunch of JS and DOM APIs. It usually stores the original
|
|
5
|
+
* value of the patched functions/constructors/methods in a hidden property prefixed by
|
|
6
|
+
* __zone_symbol__.
|
|
7
|
+
*
|
|
8
|
+
* In multiple occasions, we observed that Zone.js is the culprit of important issues leading to
|
|
9
|
+
* browser resource exhaustion (memory leak, high CPU usage). This method is used as a workaround to
|
|
10
|
+
* use the original DOM API instead of the one patched by Zone.js.
|
|
11
|
+
*
|
|
12
|
+
* [1]: https://github.com/angular/angular/tree/main/packages/zone.js
|
|
13
|
+
*/
|
|
14
|
+
export function getZoneJsOriginalValue(target, name) {
|
|
15
|
+
var browserWindow = window
|
|
16
|
+
var original
|
|
17
|
+
if (
|
|
18
|
+
browserWindow.Zone &&
|
|
19
|
+
typeof browserWindow.Zone.__symbol__ === 'function'
|
|
20
|
+
) {
|
|
21
|
+
original = target[browserWindow.Zone.__symbol__(name)]
|
|
22
|
+
}
|
|
23
|
+
if (!original) {
|
|
24
|
+
original = target[name]
|
|
25
|
+
}
|
|
26
|
+
return original
|
|
27
|
+
}
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { noop } from './tools'
|
|
2
|
-
|
|
3
|
-
export function instrumentMethod(
|
|
4
|
-
object,
|
|
5
|
-
method,
|
|
6
|
-
instrumentationFactory
|
|
7
|
-
) {
|
|
2
|
+
import { getZoneJsOriginalValue } from './getZoneJsOriginalValue'
|
|
3
|
+
export function instrumentMethod(object, method, instrumentationFactory) {
|
|
8
4
|
var original = object[method]
|
|
9
5
|
|
|
10
6
|
var instrumentation = instrumentationFactory(original)
|
|
@@ -18,62 +14,52 @@ export function instrumentMethod(
|
|
|
18
14
|
}
|
|
19
15
|
object[method] = instrumentationWrapper
|
|
20
16
|
return {
|
|
21
|
-
stop: function() {
|
|
17
|
+
stop: function () {
|
|
22
18
|
if (object[method] === instrumentationWrapper) {
|
|
23
19
|
object[method] = original
|
|
24
20
|
} else {
|
|
25
21
|
instrumentation = original
|
|
26
22
|
}
|
|
27
|
-
}
|
|
23
|
+
}
|
|
28
24
|
}
|
|
29
25
|
}
|
|
30
26
|
|
|
31
|
-
export function instrumentMethodAndCallOriginal(
|
|
32
|
-
object,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
if (typeof original === 'function') {
|
|
46
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
47
|
-
result = original.apply(this, arguments)
|
|
48
|
-
}
|
|
49
|
-
if (aliasOption && aliasOption.after) {
|
|
50
|
-
aliasOption.after.apply(this, arguments)
|
|
51
|
-
}
|
|
52
|
-
return result
|
|
27
|
+
export function instrumentMethodAndCallOriginal(object, method, aliasOption) {
|
|
28
|
+
return instrumentMethod(object, method, function (original) {
|
|
29
|
+
return function () {
|
|
30
|
+
var result
|
|
31
|
+
if (aliasOption && aliasOption.before) {
|
|
32
|
+
aliasOption.before.apply(this, arguments)
|
|
33
|
+
}
|
|
34
|
+
if (typeof original === 'function') {
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
36
|
+
result = original.apply(this, arguments)
|
|
37
|
+
}
|
|
38
|
+
if (aliasOption && aliasOption.after) {
|
|
39
|
+
aliasOption.after.apply(this, arguments)
|
|
53
40
|
}
|
|
41
|
+
return result
|
|
54
42
|
}
|
|
55
|
-
|
|
56
|
-
)
|
|
43
|
+
})
|
|
57
44
|
}
|
|
58
45
|
|
|
59
|
-
export function instrumentSetter(
|
|
60
|
-
object,
|
|
61
|
-
property,
|
|
62
|
-
after
|
|
63
|
-
) {
|
|
46
|
+
export function instrumentSetter(object, property, after) {
|
|
64
47
|
var originalDescriptor = Object.getOwnPropertyDescriptor(object, property)
|
|
65
|
-
if (
|
|
48
|
+
if (
|
|
49
|
+
!originalDescriptor ||
|
|
50
|
+
!originalDescriptor.set ||
|
|
51
|
+
!originalDescriptor.configurable
|
|
52
|
+
) {
|
|
66
53
|
return { stop: noop }
|
|
67
54
|
}
|
|
68
|
-
|
|
69
|
-
|
|
55
|
+
// Using the patched `setTimeout` from Zone.js triggers a rendering loop in some Angular
|
|
56
|
+
// component, see issue RUMF-1443
|
|
57
|
+
var setTimeout = getZoneJsOriginalValue(window, 'setTimeout')
|
|
58
|
+
var instrumentation = function (thisObject, value) {
|
|
70
59
|
// put hooked setter into event loop to avoid of set latency
|
|
71
|
-
setTimeout(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
},
|
|
75
|
-
0
|
|
76
|
-
)
|
|
60
|
+
setTimeout(function () {
|
|
61
|
+
after(thisObject, value)
|
|
62
|
+
}, 0)
|
|
77
63
|
}
|
|
78
64
|
|
|
79
65
|
var instrumentationWrapper = function (value) {
|
|
@@ -82,16 +68,20 @@ export function instrumentSetter(
|
|
|
82
68
|
}
|
|
83
69
|
|
|
84
70
|
Object.defineProperty(object, property, {
|
|
85
|
-
set: instrumentationWrapper
|
|
71
|
+
set: instrumentationWrapper
|
|
86
72
|
})
|
|
87
73
|
|
|
88
74
|
return {
|
|
89
|
-
stop: function() {
|
|
90
|
-
if (
|
|
75
|
+
stop: function () {
|
|
76
|
+
if (
|
|
77
|
+
Object.getOwnPropertyDescriptor(object, property) &&
|
|
78
|
+
Object.getOwnPropertyDescriptor(object, property).set ===
|
|
79
|
+
instrumentationWrapper
|
|
80
|
+
) {
|
|
91
81
|
Object.defineProperty(object, property, originalDescriptor)
|
|
92
82
|
} else {
|
|
93
83
|
instrumentation = noop
|
|
94
84
|
}
|
|
95
|
-
}
|
|
85
|
+
}
|
|
96
86
|
}
|
|
97
87
|
}
|
package/src/helper/lifeCycle.js
CHANGED
|
@@ -1,28 +1,23 @@
|
|
|
1
1
|
import { each, filter } from './tools'
|
|
2
2
|
export var LifeCycleEventType = {
|
|
3
3
|
PERFORMANCE_ENTRIES_COLLECTED: 'PERFORMANCE_ENTRIES_COLLECTED',
|
|
4
|
-
AUTO_ACTION_CREATED: 'AUTO_ACTION_CREATED',
|
|
5
4
|
AUTO_ACTION_COMPLETED: 'AUTO_ACTION_COMPLETED',
|
|
6
5
|
VIEW_CREATED: 'VIEW_CREATED',
|
|
7
6
|
VIEW_UPDATED: 'VIEW_UPDATED',
|
|
8
7
|
VIEW_ENDED: 'VIEW_ENDED',
|
|
9
8
|
SESSION_RENEWED: 'SESSION_RENEWED',
|
|
10
9
|
SESSION_EXPIRED: 'SESSION_EXPIRED',
|
|
11
|
-
|
|
12
|
-
BEFORE_UNLOAD: 'BEFORE_UNLOAD',
|
|
10
|
+
PAGE_EXITED: 'PAGE_EXITED',
|
|
13
11
|
REQUEST_STARTED: 'REQUEST_STARTED',
|
|
14
12
|
REQUEST_COMPLETED: 'REQUEST_COMPLETED',
|
|
15
13
|
RAW_RUM_EVENT_COLLECTED: 'RAW_RUM_EVENT_COLLECTED',
|
|
16
14
|
RUM_EVENT_COLLECTED: 'RUM_EVENT_COLLECTED',
|
|
17
15
|
RAW_ERROR_COLLECTED: 'RAW_ERROR_COLLECTED',
|
|
18
|
-
RECORD_STARTED: 'RECORD_STARTED',
|
|
19
|
-
RECORD_STOPPED: 'RECORD_STOPPED',
|
|
20
16
|
RAW_LOG_COLLECTED: 'RAW_LOG_COLLECTED',
|
|
21
17
|
LOG_COLLECTED: 'LOG_COLLECTED'
|
|
22
18
|
}
|
|
23
|
-
|
|
24
19
|
export function LifeCycle() {
|
|
25
|
-
this.callbacks =
|
|
20
|
+
this.callbacks = {}
|
|
26
21
|
}
|
|
27
22
|
LifeCycle.prototype = {
|
|
28
23
|
notify: function (eventType, data) {
|