@cloudcare/browser-core 2.0.3 → 2.0.5
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/addEventListener.js +57 -0
- package/cjs/browser/pageExitObservable.js +4 -2
- package/cjs/browser/runOnReadyState.js +21 -0
- package/cjs/browser/xhrObservable.js +7 -5
- package/cjs/configuration/configuration.js +5 -3
- package/cjs/console/consoleObservable.js +3 -1
- package/cjs/dataMap.js +1 -0
- package/cjs/helper/byteUtils.js +26 -0
- package/cjs/helper/contextHistory.js +4 -2
- package/cjs/helper/createEventRateLimiter.js +3 -1
- package/cjs/helper/errorTools.js +4 -2
- package/cjs/helper/instrumentMethod.js +2 -4
- package/cjs/helper/serialisation/contextManager.js +84 -0
- package/cjs/helper/serialisation/heavyCustomerDataWarning.js +34 -0
- package/cjs/helper/serialisation/jsonStringify.js +57 -0
- package/cjs/helper/serialisation/rowData.js +50 -0
- package/cjs/helper/timer.js +29 -0
- package/cjs/helper/tools.js +10 -331
- package/cjs/index.js +117 -0
- package/cjs/init.js +6 -6
- package/cjs/report/reportObservable.js +4 -2
- package/cjs/session/sessionCookieStore.js +3 -1
- package/cjs/session/sessionManagement.js +10 -5
- package/cjs/session/sessionStore.js +10 -4
- package/cjs/transport/batch.js +40 -91
- package/cjs/transport/flushController.js +121 -0
- package/cjs/transport/httpRequest.js +6 -2
- package/cjs/transport/index.js +9 -1
- package/cjs/transport/sendWithRetryStrategy.js +8 -4
- package/cjs/transport/startBatchWithReplica.js +10 -2
- package/cjs/user/index.js +18 -0
- package/cjs/user/user.js +42 -0
- package/esm/browser/addEventListener.js +46 -0
- package/esm/browser/pageExitObservable.js +2 -1
- package/esm/browser/runOnReadyState.js +12 -0
- package/esm/browser/xhrObservable.js +6 -5
- package/esm/configuration/configuration.js +2 -1
- package/esm/console/consoleObservable.js +2 -1
- package/esm/dataMap.js +1 -0
- package/esm/helper/byteUtils.js +16 -0
- package/esm/helper/contextHistory.js +1 -0
- package/esm/helper/createEventRateLimiter.js +1 -0
- package/esm/helper/errorTools.js +2 -1
- package/esm/helper/instrumentMethod.js +1 -3
- package/esm/helper/serialisation/contextManager.js +70 -0
- package/esm/helper/serialisation/heavyCustomerDataWarning.js +20 -0
- package/esm/helper/serialisation/jsonStringify.js +46 -0
- package/esm/helper/serialisation/rowData.js +33 -0
- package/esm/helper/timer.js +14 -0
- package/esm/helper/tools.js +1 -292
- package/esm/index.js +10 -1
- package/esm/init.js +6 -6
- package/esm/report/reportObservable.js +3 -2
- package/esm/session/sessionCookieStore.js +1 -0
- package/esm/session/sessionManagement.js +5 -2
- package/esm/session/sessionStore.js +7 -2
- package/esm/transport/batch.js +31 -85
- package/esm/transport/flushController.js +114 -0
- package/esm/transport/httpRequest.js +5 -2
- package/esm/transport/index.js +2 -1
- package/esm/transport/sendWithRetryStrategy.js +3 -1
- package/esm/transport/startBatchWithReplica.js +9 -2
- package/esm/user/index.js +1 -0
- package/esm/user/user.js +32 -0
- package/package.json +22 -22
- package/src/browser/addEventListener.js +50 -0
- package/src/browser/pageExitObservable.js +4 -5
- package/src/browser/runOnReadyState.js +16 -0
- package/src/browser/xhrObservable.js +57 -32
- package/src/configuration/configuration.js +1 -1
- package/src/console/consoleObservable.js +22 -12
- package/src/dataMap.js +1 -0
- package/src/helper/byteUtils.js +17 -0
- package/src/helper/contextHistory.js +1 -1
- package/src/helper/createEventRateLimiter.js +7 -9
- package/src/helper/errorTools.js +2 -1
- package/src/helper/instrumentMethod.js +1 -2
- package/src/helper/serialisation/contextManager.js +79 -0
- package/src/helper/serialisation/heavyCustomerDataWarning.js +28 -0
- package/src/helper/serialisation/jsonStringify.js +47 -0
- package/src/helper/serialisation/rowData.js +41 -0
- package/src/helper/timer.js +21 -0
- package/src/helper/tools.js +2 -301
- package/src/index.js +11 -0
- package/src/init.js +6 -6
- package/src/report/reportObservable.js +40 -25
- package/src/session/sessionCookieStore.js +24 -14
- package/src/session/sessionManagement.js +34 -17
- package/src/session/sessionStore.js +7 -2
- package/src/transport/batch.js +39 -91
- package/src/transport/flushController.js +115 -0
- package/src/transport/httpRequest.js +13 -6
- package/src/transport/index.js +1 -0
- package/src/transport/sendWithRetryStrategy.js +3 -7
- package/src/transport/startBatchWithReplica.js +11 -7
- package/src/user/index.js +1 -0
- package/src/user/user.js +31 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { addEventListener } from './addEventListener'
|
|
2
|
+
import { DOM_EVENT } from '../helper/enums'
|
|
3
|
+
export function runOnReadyState(expectedReadyState, callback) {
|
|
4
|
+
if (
|
|
5
|
+
document.readyState === expectedReadyState ||
|
|
6
|
+
document.readyState === 'complete'
|
|
7
|
+
) {
|
|
8
|
+
callback()
|
|
9
|
+
} else {
|
|
10
|
+
var eventName =
|
|
11
|
+
expectedReadyState === 'complete'
|
|
12
|
+
? DOM_EVENT.LOAD
|
|
13
|
+
: DOM_EVENT.DOM_CONTENT_LOADED
|
|
14
|
+
addEventListener(window, eventName, callback, { once: true })
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { instrumentMethodAndCallOriginal } from '../helper/instrumentMethod'
|
|
2
2
|
import { Observable } from '../helper/observable'
|
|
3
3
|
import { normalizeUrl } from '../helper/urlPolyfill'
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
shallowClone,
|
|
6
|
+
elapsed,
|
|
7
|
+
relativeNow,
|
|
8
|
+
clocksNow,
|
|
9
|
+
timeStampNow,
|
|
10
|
+
UUID
|
|
11
|
+
} from '../helper/tools'
|
|
12
|
+
import { addEventListener } from '../browser/addEventListener'
|
|
6
13
|
var xhrObservable
|
|
7
14
|
var xhrContexts = {}
|
|
8
15
|
var DATA_FLUX_REQUEST_ID_KEY = '_DATAFLUX_REQUEST_UUID'
|
|
@@ -14,22 +21,34 @@ export function initXhrObservable() {
|
|
|
14
21
|
}
|
|
15
22
|
|
|
16
23
|
function createXhrObservable() {
|
|
17
|
-
var observable = new Observable(function(){
|
|
18
|
-
var openInstrumentMethod = instrumentMethodAndCallOriginal(
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
var observable = new Observable(function () {
|
|
25
|
+
var openInstrumentMethod = instrumentMethodAndCallOriginal(
|
|
26
|
+
XMLHttpRequest.prototype,
|
|
27
|
+
'open',
|
|
28
|
+
{
|
|
29
|
+
before: openXhr
|
|
30
|
+
}
|
|
31
|
+
)
|
|
21
32
|
|
|
22
|
-
var sendInstrumentMethod = instrumentMethodAndCallOriginal(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
33
|
+
var sendInstrumentMethod = instrumentMethodAndCallOriginal(
|
|
34
|
+
XMLHttpRequest.prototype,
|
|
35
|
+
'send',
|
|
36
|
+
{
|
|
37
|
+
before: function () {
|
|
38
|
+
sendXhr.call(this, observable)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
)
|
|
27
42
|
|
|
28
|
-
var abortInstrumentMethod = instrumentMethodAndCallOriginal(
|
|
29
|
-
|
|
30
|
-
|
|
43
|
+
var abortInstrumentMethod = instrumentMethodAndCallOriginal(
|
|
44
|
+
XMLHttpRequest.prototype,
|
|
45
|
+
'abort',
|
|
46
|
+
{
|
|
47
|
+
before: abortXhr
|
|
48
|
+
}
|
|
49
|
+
)
|
|
31
50
|
|
|
32
|
-
return function() {
|
|
51
|
+
return function () {
|
|
33
52
|
openInstrumentMethod.stop()
|
|
34
53
|
sendInstrumentMethod.stop()
|
|
35
54
|
abortInstrumentMethod.stop()
|
|
@@ -44,7 +63,7 @@ function openXhr(method, url) {
|
|
|
44
63
|
xhrContexts[requestUUID] = {
|
|
45
64
|
state: 'open',
|
|
46
65
|
method: method,
|
|
47
|
-
url: normalizeUrl(String(url))
|
|
66
|
+
url: normalizeUrl(String(url))
|
|
48
67
|
}
|
|
49
68
|
}
|
|
50
69
|
|
|
@@ -60,34 +79,40 @@ function sendXhr(observable) {
|
|
|
60
79
|
startContext.isAborted = false
|
|
61
80
|
startContext.xhr = this
|
|
62
81
|
var hasBeenReported = false
|
|
63
|
-
var
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
82
|
+
var stopInstrumentingOnReadyStateChange = instrumentMethodAndCallOriginal(
|
|
83
|
+
this,
|
|
84
|
+
'onreadystatechange',
|
|
85
|
+
{
|
|
86
|
+
before: function () {
|
|
87
|
+
if (this.readyState === XMLHttpRequest.DONE) {
|
|
88
|
+
// Try to report the XHR as soon as possible, because the XHR may be mutated by the
|
|
89
|
+
// application during a future event. For example, Angular is calling .abort() on
|
|
90
|
+
// completed requests during a onreadystatechange event, so the status becomes '0'
|
|
91
|
+
// before the request is collected.
|
|
92
|
+
onEnd.call(this)
|
|
93
|
+
}
|
|
72
94
|
}
|
|
73
|
-
}
|
|
74
|
-
|
|
95
|
+
}
|
|
96
|
+
).stop
|
|
75
97
|
|
|
76
|
-
var onEnd = function() {
|
|
77
|
-
|
|
78
|
-
|
|
98
|
+
var onEnd = function () {
|
|
99
|
+
unsubscribeLoadEndListener()
|
|
100
|
+
stopInstrumentingOnReadyStateChange()
|
|
79
101
|
if (hasBeenReported) {
|
|
80
102
|
return
|
|
81
103
|
}
|
|
82
104
|
hasBeenReported = true
|
|
83
105
|
var completeContext = context
|
|
84
106
|
completeContext.state = 'complete'
|
|
85
|
-
completeContext.duration = elapsed(
|
|
107
|
+
completeContext.duration = elapsed(
|
|
108
|
+
startContext.startClocks.timeStamp,
|
|
109
|
+
timeStampNow()
|
|
110
|
+
)
|
|
86
111
|
completeContext.status = this.status
|
|
87
112
|
observable.notify(shallowClone(completeContext))
|
|
88
113
|
clearRequestId.call(this)
|
|
89
114
|
}
|
|
90
|
-
|
|
115
|
+
var unsubscribeLoadEndListener = addEventListener(this, 'loadend', onEnd).stop
|
|
91
116
|
observable.notify(startContext)
|
|
92
117
|
}
|
|
93
118
|
function clearRequestId() {
|
|
@@ -4,10 +4,10 @@ import { display } from '../helper/display'
|
|
|
4
4
|
import {
|
|
5
5
|
assign,
|
|
6
6
|
isPercentage,
|
|
7
|
-
ONE_KIBI_BYTE,
|
|
8
7
|
ONE_SECOND,
|
|
9
8
|
isNullUndefinedDefaultValue
|
|
10
9
|
} from '../helper/tools'
|
|
10
|
+
import { ONE_KIBI_BYTE } from '../helper/byteUtils'
|
|
11
11
|
import { computeTransportConfiguration } from './transportConfiguration'
|
|
12
12
|
|
|
13
13
|
export var DefaultPrivacyLevel = {
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { computeStackTrace } from '../tracekit'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
createHandlingStack,
|
|
4
|
+
formatErrorMessage,
|
|
5
|
+
toStackTraceString
|
|
6
|
+
} from '../helper/errorTools'
|
|
3
7
|
import { mergeObservables, Observable } from '../helper/observable'
|
|
4
|
-
import { find,
|
|
8
|
+
import { find, map } from '../helper/tools'
|
|
9
|
+
import { jsonStringify } from '../helper/serialisation/jsonStringify'
|
|
5
10
|
import { ConsoleApiName } from '../helper/display'
|
|
6
11
|
|
|
7
|
-
|
|
8
12
|
var consoleObservablesByApi = {}
|
|
9
13
|
|
|
10
14
|
export function initConsoleObservable(apis) {
|
|
11
|
-
var consoleObservables = map(apis, function(api) {
|
|
15
|
+
var consoleObservables = map(apis, function (api) {
|
|
12
16
|
if (!consoleObservablesByApi[api]) {
|
|
13
17
|
consoleObservablesByApi[api] = createConsoleObservable(api)
|
|
14
18
|
}
|
|
@@ -20,15 +24,15 @@ export function initConsoleObservable(apis) {
|
|
|
20
24
|
|
|
21
25
|
/* eslint-disable no-console */
|
|
22
26
|
function createConsoleObservable(api) {
|
|
23
|
-
var observable = new Observable(function(){
|
|
27
|
+
var observable = new Observable(function () {
|
|
24
28
|
var originalConsoleApi = console[api]
|
|
25
|
-
console[api] = function() {
|
|
29
|
+
console[api] = function () {
|
|
26
30
|
var params = [].slice.call(arguments)
|
|
27
31
|
originalConsoleApi.apply(console, arguments)
|
|
28
32
|
var handlingStack = createHandlingStack()
|
|
29
33
|
observable.notify(buildConsoleLog(params, api, handlingStack))
|
|
30
34
|
}
|
|
31
|
-
return function() {
|
|
35
|
+
return function () {
|
|
32
36
|
console[api] = originalConsoleApi
|
|
33
37
|
}
|
|
34
38
|
})
|
|
@@ -37,20 +41,26 @@ function createConsoleObservable(api) {
|
|
|
37
41
|
|
|
38
42
|
function buildConsoleLog(params, api, handlingStack) {
|
|
39
43
|
// Todo: remove console error prefix in the next major version
|
|
40
|
-
var message = map(params, function(param) {
|
|
44
|
+
var message = map(params, function (param) {
|
|
45
|
+
return formatConsoleParameters(param)
|
|
46
|
+
}).join(' ')
|
|
41
47
|
var stack
|
|
42
48
|
|
|
43
49
|
if (api === ConsoleApiName.error) {
|
|
44
|
-
var firstErrorParam = find(params, function(param) {
|
|
45
|
-
|
|
46
|
-
|
|
50
|
+
var firstErrorParam = find(params, function (param) {
|
|
51
|
+
return param instanceof Error
|
|
52
|
+
})
|
|
53
|
+
stack = firstErrorParam
|
|
54
|
+
? toStackTraceString(computeStackTrace(firstErrorParam))
|
|
55
|
+
: undefined
|
|
56
|
+
message = 'console error: ' + message
|
|
47
57
|
}
|
|
48
58
|
|
|
49
59
|
return {
|
|
50
60
|
api: api,
|
|
51
61
|
message: message,
|
|
52
62
|
stack: stack,
|
|
53
|
-
handlingStack: handlingStack
|
|
63
|
+
handlingStack: handlingStack
|
|
54
64
|
}
|
|
55
65
|
}
|
|
56
66
|
|
package/src/dataMap.js
CHANGED
|
@@ -47,6 +47,7 @@ export var dataMap = {
|
|
|
47
47
|
},
|
|
48
48
|
fields: {
|
|
49
49
|
session_replay_stats: '_dd.replay_stats',
|
|
50
|
+
session_is_active: 'session.is_active',
|
|
50
51
|
view_error_count: 'view.error.count',
|
|
51
52
|
view_resource_count: 'view.resource.count',
|
|
52
53
|
view_long_task_count: 'view.long_task.count',
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export var ONE_KIBI_BYTE = 1024
|
|
2
|
+
export var ONE_MEBI_BYTE = 1024 * ONE_KIBI_BYTE
|
|
3
|
+
// eslint-disable-next-line no-control-regex
|
|
4
|
+
var HAS_MULTI_BYTES_CHARACTERS = /[^\u0000-\u007F]/
|
|
5
|
+
|
|
6
|
+
export function computeBytesCount(candidate) {
|
|
7
|
+
// Accurate bytes count computations can degrade performances when there is a lot of events to process
|
|
8
|
+
if (!HAS_MULTI_BYTES_CHARACTERS.test(candidate)) {
|
|
9
|
+
return candidate.length
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (window.TextEncoder !== undefined) {
|
|
13
|
+
return new TextEncoder().encode(candidate).length
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return new Blob([candidate]).size
|
|
17
|
+
}
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import { ErrorSource } from './errorTools'
|
|
2
2
|
import { clocksNow, ONE_MINUTE } from './tools'
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
limit,
|
|
6
|
-
onLimitReached
|
|
7
|
-
) {
|
|
3
|
+
import { setTimeout } from './timer'
|
|
4
|
+
export function createEventRateLimiter(eventType, limit, onLimitReached) {
|
|
8
5
|
var eventCount = 0
|
|
9
6
|
var allowNextEvent = false
|
|
10
7
|
return {
|
|
11
|
-
isLimitReached: function() {
|
|
8
|
+
isLimitReached: function () {
|
|
12
9
|
if (eventCount === 0) {
|
|
13
|
-
setTimeout(function(){
|
|
10
|
+
setTimeout(function () {
|
|
14
11
|
eventCount = 0
|
|
15
12
|
}, ONE_MINUTE)
|
|
16
13
|
}
|
|
@@ -23,9 +20,10 @@ export function createEventRateLimiter(
|
|
|
23
20
|
allowNextEvent = true
|
|
24
21
|
try {
|
|
25
22
|
onLimitReached({
|
|
26
|
-
message:
|
|
23
|
+
message:
|
|
24
|
+
'Reached max number of ' + eventType + 's by minute: ' + limit,
|
|
27
25
|
source: ErrorSource.AGENT,
|
|
28
|
-
startClocks: clocksNow()
|
|
26
|
+
startClocks: clocksNow()
|
|
29
27
|
})
|
|
30
28
|
} finally {
|
|
31
29
|
allowNextEvent = false
|
package/src/helper/errorTools.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { noop } from './tools'
|
|
2
|
-
import {
|
|
2
|
+
import { setTimeout } from './timer'
|
|
3
3
|
export function instrumentMethod(object, method, instrumentationFactory) {
|
|
4
4
|
var original = object[method]
|
|
5
5
|
|
|
@@ -54,7 +54,6 @@ export function instrumentSetter(object, property, after) {
|
|
|
54
54
|
}
|
|
55
55
|
// Using the patched `setTimeout` from Zone.js triggers a rendering loop in some Angular
|
|
56
56
|
// component, see issue RUMF-1443
|
|
57
|
-
var setTimeout = getZoneJsOriginalValue(window, 'setTimeout')
|
|
58
57
|
var instrumentation = function (thisObject, value) {
|
|
59
58
|
// put hooked setter into event loop to avoid of set latency
|
|
60
59
|
setTimeout(function () {
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { computeBytesCount } from '../byteUtils'
|
|
2
|
+
import { deepClone, throttle } from '../tools'
|
|
3
|
+
import { jsonStringify } from './jsonStringify'
|
|
4
|
+
import { warnIfCustomerDataLimitReached } from './heavyCustomerDataWarning'
|
|
5
|
+
|
|
6
|
+
export var BYTES_COMPUTATION_THROTTLING_DELAY = 200
|
|
7
|
+
|
|
8
|
+
export function createContextManager(customerDataType, computeBytesCountImpl) {
|
|
9
|
+
if (typeof computeBytesCountImpl === 'undefined') {
|
|
10
|
+
computeBytesCountImpl = computeBytesCount
|
|
11
|
+
}
|
|
12
|
+
var context = {}
|
|
13
|
+
var bytesCountCache
|
|
14
|
+
var alreadyWarned = false
|
|
15
|
+
|
|
16
|
+
// Throttle the bytes computation to minimize the impact on performance.
|
|
17
|
+
// Especially useful if the user call context APIs synchronously multiple times in a row
|
|
18
|
+
var computeBytesCountThrottled = throttle(function (context) {
|
|
19
|
+
bytesCountCache = computeBytesCountImpl(jsonStringify(context))
|
|
20
|
+
if (!alreadyWarned) {
|
|
21
|
+
alreadyWarned = warnIfCustomerDataLimitReached(
|
|
22
|
+
bytesCountCache,
|
|
23
|
+
customerDataType
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
}, BYTES_COMPUTATION_THROTTLING_DELAY).throttled
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
getBytesCount: function () {
|
|
30
|
+
return bytesCountCache
|
|
31
|
+
},
|
|
32
|
+
/** @deprecated use getContext instead */
|
|
33
|
+
get: function () {
|
|
34
|
+
return context
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
/** @deprecated use setContextProperty instead */
|
|
38
|
+
add: function (key, value) {
|
|
39
|
+
context[key] = value
|
|
40
|
+
computeBytesCountThrottled(context)
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
/** @deprecated renamed to removeContextProperty */
|
|
44
|
+
remove: function (key) {
|
|
45
|
+
delete context[key]
|
|
46
|
+
computeBytesCountThrottled(context)
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
/** @deprecated use setContext instead */
|
|
50
|
+
set: function (newContext) {
|
|
51
|
+
context = newContext
|
|
52
|
+
computeBytesCountThrottled(context)
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
getContext: function () {
|
|
56
|
+
return deepClone(context)
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
setContext: function (newContext) {
|
|
60
|
+
context = deepClone(newContext)
|
|
61
|
+
computeBytesCountThrottled(context)
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
setContextProperty: function (key, property) {
|
|
65
|
+
context[key] = deepClone(property)
|
|
66
|
+
computeBytesCountThrottled(context)
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
removeContextProperty: function (key) {
|
|
70
|
+
delete context[key]
|
|
71
|
+
computeBytesCountThrottled(context)
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
clearContext: function () {
|
|
75
|
+
context = {}
|
|
76
|
+
bytesCountCache = 0
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ONE_KIBI_BYTE } from '../byteUtils'
|
|
2
|
+
import { display } from '../display'
|
|
3
|
+
|
|
4
|
+
// RUM and logs batch bytes limit is 16KB
|
|
5
|
+
// ensure that we leave room for other event attributes and maintain a decent amount of event per batch
|
|
6
|
+
// (3KB (customer data) + 1KB (other attributes)) * 4 (events per batch) = 16KB
|
|
7
|
+
export var CUSTOMER_DATA_BYTES_LIMIT = 3 * ONE_KIBI_BYTE
|
|
8
|
+
|
|
9
|
+
export var CustomerDataType = {
|
|
10
|
+
FeatureFlag: 'feature flag evaluation',
|
|
11
|
+
User: 'user',
|
|
12
|
+
GlobalContext: 'global context',
|
|
13
|
+
LoggerContext: 'logger context'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function warnIfCustomerDataLimitReached(bytesCount, customerDataType) {
|
|
17
|
+
if (bytesCount > CUSTOMER_DATA_BYTES_LIMIT) {
|
|
18
|
+
display.warn(
|
|
19
|
+
'The ' +
|
|
20
|
+
customerDataType +
|
|
21
|
+
'data is over ' +
|
|
22
|
+
CUSTOMER_DATA_BYTES_LIMIT / ONE_KIBI_BYTE +
|
|
23
|
+
" KiB. On low connectivity, the SDK has the potential to exhaust the user's upload bandwidth."
|
|
24
|
+
)
|
|
25
|
+
return true
|
|
26
|
+
}
|
|
27
|
+
return false
|
|
28
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { noop } from '../tools'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Custom implementation of JSON.stringify that ignores some toJSON methods. We need to do that
|
|
5
|
+
* because some sites badly override toJSON on certain objects. Removing all toJSON methods from
|
|
6
|
+
* nested values would be too costly, so we just detach them from the root value, and native classes
|
|
7
|
+
* used to build JSON values (Array and Object).
|
|
8
|
+
*
|
|
9
|
+
* Note: this still assumes that JSON.stringify is correct.
|
|
10
|
+
*/
|
|
11
|
+
export function jsonStringify(value, replacer, space) {
|
|
12
|
+
if (typeof value !== 'object' || value === null) {
|
|
13
|
+
return JSON.stringify(value)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Note: The order matter here. We need to detach toJSON methods on parent classes before their
|
|
17
|
+
// subclasses.
|
|
18
|
+
var restoreObjectPrototypeToJson = detachToJsonMethod(Object.prototype)
|
|
19
|
+
var restoreArrayPrototypeToJson = detachToJsonMethod(Array.prototype)
|
|
20
|
+
var restoreValuePrototypeToJson = detachToJsonMethod(
|
|
21
|
+
Object.getPrototypeOf(value)
|
|
22
|
+
)
|
|
23
|
+
var restoreValueToJson = detachToJsonMethod(value)
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
return JSON.stringify(value, replacer, space)
|
|
27
|
+
} catch {
|
|
28
|
+
return '<error: unable to serialize object>'
|
|
29
|
+
} finally {
|
|
30
|
+
restoreObjectPrototypeToJson()
|
|
31
|
+
restoreArrayPrototypeToJson()
|
|
32
|
+
restoreValuePrototypeToJson()
|
|
33
|
+
restoreValueToJson()
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function detachToJsonMethod(value) {
|
|
38
|
+
const object = value
|
|
39
|
+
const objectToJson = object.toJSON
|
|
40
|
+
if (objectToJson) {
|
|
41
|
+
delete object.toJSON
|
|
42
|
+
return () => {
|
|
43
|
+
object.toJSON = objectToJson
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return noop
|
|
47
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { jsonStringify } from './jsonStringify'
|
|
2
|
+
import { isString } from '../tools'
|
|
3
|
+
export function escapeRowData(str) {
|
|
4
|
+
if (typeof str === 'object' && str) {
|
|
5
|
+
str = jsonStringify(str)
|
|
6
|
+
} else if (!isString(str)) {
|
|
7
|
+
return str
|
|
8
|
+
}
|
|
9
|
+
var reg = /[\s=,"]/g
|
|
10
|
+
return String(str).replace(reg, function (word) {
|
|
11
|
+
return '\\' + word
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function escapeJsonValue(value) {
|
|
16
|
+
if (isString(value)) {
|
|
17
|
+
return value
|
|
18
|
+
} else {
|
|
19
|
+
return jsonStringify(value)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function escapeFieldValueStr(str) {
|
|
24
|
+
return (
|
|
25
|
+
'"' +
|
|
26
|
+
str
|
|
27
|
+
.replace(/\\/g, '\\\\')
|
|
28
|
+
.replace(/[\\]*"/g, '"')
|
|
29
|
+
.replace(/"/g, '\\"') +
|
|
30
|
+
'"'
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
export function escapeRowField(value) {
|
|
34
|
+
if (typeof value === 'object' && value) {
|
|
35
|
+
return escapeFieldValueStr(jsonStringify(value))
|
|
36
|
+
} else if (isString(value)) {
|
|
37
|
+
return escapeFieldValueStr(value)
|
|
38
|
+
} else {
|
|
39
|
+
return value
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { getZoneJsOriginalValue } from './getZoneJsOriginalValue'
|
|
2
|
+
import { getGlobalObject } from '../init'
|
|
3
|
+
|
|
4
|
+
export function setTimeout(callback, delay) {
|
|
5
|
+
return getZoneJsOriginalValue(getGlobalObject(), 'setTimeout')(
|
|
6
|
+
callback,
|
|
7
|
+
delay
|
|
8
|
+
)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function clearTimeout(timeoutId) {
|
|
12
|
+
getZoneJsOriginalValue(getGlobalObject(), 'clearTimeout')(timeoutId)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function setInterval(callback, delay) {
|
|
16
|
+
return getZoneJsOriginalValue(window, 'setInterval')(callback, delay)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function clearInterval(timeoutId) {
|
|
20
|
+
getZoneJsOriginalValue(window, 'clearInterval')(timeoutId)
|
|
21
|
+
}
|