@cloudcare/browser-core 1.1.2 → 1.2.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/{cookie.js → browser/cookie.js} +6 -37
- package/cjs/browser/fetchObservable.js +91 -0
- package/cjs/browser/xhrObservable.js +118 -0
- package/cjs/configuration/configuration.js +70 -0
- package/cjs/configuration/transportConfiguration.js +64 -0
- package/cjs/console/consoleObservable.js +84 -0
- package/cjs/dataMap.js +26 -21
- package/cjs/error/trackRuntimeError.js +27 -0
- package/cjs/helper/catchUserErrors.js +20 -0
- package/cjs/helper/contextHistory.js +134 -0
- package/cjs/helper/createEventRateLimiter.js +47 -0
- package/cjs/helper/deviceInfo.js +8 -25
- package/cjs/helper/display.js +31 -0
- package/cjs/helper/enums.js +28 -2
- package/cjs/helper/errorTools.js +63 -2
- package/cjs/helper/instrumentMethod.js +93 -0
- package/cjs/helper/lifeCycle.js +5 -3
- package/cjs/helper/observable.js +40 -2
- package/cjs/helper/tools.js +217 -11
- package/cjs/index.js +153 -23
- package/cjs/init.js +17 -27
- package/cjs/report/reportObservable.js +112 -0
- package/cjs/session/sessionConstants.js +13 -0
- package/cjs/session/sessionCookieStore.js +188 -0
- package/cjs/session/sessionManagement.js +96 -0
- package/cjs/session/sessionStore.js +150 -0
- package/cjs/synthetics/syntheticsWorkerValues.js +32 -0
- package/cjs/synthetics/usr.js +32 -0
- package/cjs/tracekit/computeStackTrace.js +73 -563
- package/cjs/tracekit/index.js +3 -15
- package/cjs/tracekit/tracekit.js +113 -0
- package/cjs/transport/batch.js +332 -0
- package/cjs/transport/httpRequest.js +112 -0
- package/cjs/transport/index.js +29 -0
- package/cjs/transport/sendWithRetryStrategy.js +177 -0
- package/cjs/transport/startBatchWithReplica.js +24 -0
- package/esm/{cookie.js → browser/cookie.js} +4 -35
- package/esm/browser/fetchObservable.js +77 -0
- package/esm/browser/xhrObservable.js +106 -0
- package/esm/configuration/configuration.js +55 -0
- package/esm/configuration/transportConfiguration.js +54 -0
- package/esm/console/consoleObservable.js +70 -0
- package/esm/dataMap.js +26 -21
- package/esm/error/trackRuntimeError.js +16 -0
- package/esm/helper/catchUserErrors.js +12 -0
- package/esm/helper/contextHistory.js +106 -0
- package/esm/helper/createEventRateLimiter.js +38 -0
- package/esm/helper/deviceInfo.js +6 -25
- package/esm/helper/display.js +21 -0
- package/esm/helper/enums.js +25 -1
- package/esm/helper/errorTools.js +58 -3
- package/esm/helper/instrumentMethod.js +81 -0
- package/esm/helper/lifeCycle.js +5 -3
- package/esm/helper/observable.js +39 -3
- package/esm/helper/tools.js +173 -3
- package/esm/index.js +17 -7
- package/esm/init.js +17 -22
- package/esm/report/reportObservable.js +98 -0
- package/esm/session/sessionConstants.js +3 -0
- package/esm/session/sessionCookieStore.js +168 -0
- package/esm/session/sessionManagement.js +78 -0
- package/esm/session/sessionStore.js +139 -0
- package/esm/synthetics/syntheticsWorkerValues.js +15 -0
- package/esm/synthetics/usr.js +18 -0
- package/esm/tracekit/computeStackTrace.js +73 -557
- package/esm/tracekit/index.js +1 -1
- package/esm/tracekit/tracekit.js +103 -0
- package/esm/transport/batch.js +316 -0
- package/esm/transport/httpRequest.js +104 -0
- package/esm/transport/index.js +3 -0
- package/esm/transport/sendWithRetryStrategy.js +165 -0
- package/esm/transport/startBatchWithReplica.js +15 -0
- package/package.json +2 -2
- package/src/.DS_Store +0 -0
- package/src/{cookie.js → browser/cookie.js} +6 -34
- package/src/browser/fetchObservable.js +86 -0
- package/src/browser/xhrObservable.js +102 -0
- package/src/configuration/configuration.js +61 -0
- package/src/configuration/transportConfiguration.js +42 -0
- package/src/console/consoleObservable.js +65 -0
- package/src/dataMap.js +26 -21
- package/src/error/trackRuntimeError.js +19 -0
- package/src/helper/catchUserErrors.js +12 -0
- package/src/helper/contextHistory.js +85 -0
- package/src/helper/createEventRateLimiter.js +37 -0
- package/src/helper/deviceInfo.js +5 -51
- package/src/helper/display.js +21 -0
- package/src/helper/enums.js +38 -14
- package/src/helper/errorTools.js +76 -12
- package/src/helper/instrumentMethod.js +97 -0
- package/src/helper/lifeCycle.js +5 -3
- package/src/helper/observable.js +33 -2
- package/src/helper/tools.js +159 -5
- package/src/index.js +18 -7
- package/src/init.js +17 -18
- package/src/report/reportObservable.js +113 -0
- package/src/session/sessionConstants.js +3 -0
- package/src/session/sessionCookieStore.js +159 -0
- package/src/session/sessionManagement.js +89 -0
- package/src/session/sessionStore.js +139 -0
- package/src/synthetics/syntheticsWorkerValues.js +22 -0
- package/src/synthetics/usr.js +18 -0
- package/src/tracekit/computeStackTrace.js +75 -551
- package/src/tracekit/index.js +1 -1
- package/src/tracekit/tracekit.js +100 -0
- package/src/transport/batch.js +289 -0
- package/src/transport/httpRequest.js +109 -0
- package/src/transport/index.js +3 -0
- package/src/transport/sendWithRetryStrategy.js +186 -0
- package/src/transport/startBatchWithReplica.js +26 -0
- package/cjs/configuration.js +0 -184
- package/cjs/errorCollection.js +0 -167
- package/cjs/fetchProxy.js +0 -162
- package/cjs/helper/errorFilter.js +0 -47
- package/cjs/sessionManagement.js +0 -221
- package/cjs/tracekit/report.js +0 -289
- package/cjs/transport.js +0 -373
- package/cjs/xhrProxy.js +0 -122
- package/esm/configuration.js +0 -167
- package/esm/errorCollection.js +0 -141
- package/esm/fetchProxy.js +0 -116
- package/esm/helper/errorFilter.js +0 -38
- package/esm/sessionManagement.js +0 -195
- package/esm/tracekit/report.js +0 -273
- package/esm/transport.js +0 -357
- package/esm/xhrProxy.js +0 -110
- package/src/configuration.js +0 -156
- package/src/errorCollection.js +0 -170
- package/src/fetchProxy.js +0 -109
- package/src/helper/errorFilter.js +0 -38
- package/src/sessionManagement.js +0 -224
- package/src/tracekit/report.js +0 -284
- package/src/transport.js +0 -380
- package/src/xhrProxy.js +0 -106
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudcare/browser-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"main": "cjs/index.js",
|
|
5
5
|
"module": "esm/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -20,5 +20,5 @@
|
|
|
20
20
|
"author": "dataflux",
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"description": "DataFlux RUM Web 端数据指标监控",
|
|
23
|
-
"gitHead": "
|
|
23
|
+
"gitHead": "12b759bde16de07678f898b82c1bcf11c403eabe"
|
|
24
24
|
}
|
package/src/.DS_Store
CHANGED
|
Binary file
|
|
@@ -1,38 +1,5 @@
|
|
|
1
|
-
import { findCommaSeparatedValue, UUID, ONE_SECOND } from '
|
|
1
|
+
import { findCommaSeparatedValue, UUID, ONE_SECOND } from '../helper/tools'
|
|
2
2
|
export var COOKIE_ACCESS_DELAY = ONE_SECOND
|
|
3
|
-
export function cacheCookieAccess(name, options) {
|
|
4
|
-
var timeout
|
|
5
|
-
var cache
|
|
6
|
-
var hasCache = false
|
|
7
|
-
|
|
8
|
-
var cacheAccess = function () {
|
|
9
|
-
hasCache = true
|
|
10
|
-
window.clearTimeout(timeout)
|
|
11
|
-
timeout = window.setTimeout(function () {
|
|
12
|
-
hasCache = false
|
|
13
|
-
}, COOKIE_ACCESS_DELAY)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
return {
|
|
17
|
-
get: function () {
|
|
18
|
-
if (hasCache) {
|
|
19
|
-
return cache
|
|
20
|
-
}
|
|
21
|
-
cache = getCookie(name)
|
|
22
|
-
cacheAccess()
|
|
23
|
-
return cache
|
|
24
|
-
},
|
|
25
|
-
set: function (value, expireDelay) {
|
|
26
|
-
setCookie(name, value, expireDelay, options)
|
|
27
|
-
cache = value
|
|
28
|
-
cacheAccess()
|
|
29
|
-
},
|
|
30
|
-
clearCache: function() {
|
|
31
|
-
window.clearTimeout(timeout)
|
|
32
|
-
hasCache = false
|
|
33
|
-
},
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
3
|
|
|
37
4
|
export function setCookie(name, value, expireDelay, options) {
|
|
38
5
|
var date = new Date()
|
|
@@ -57,6 +24,11 @@ export function getCookie(name) {
|
|
|
57
24
|
return findCommaSeparatedValue(document.cookie, name)
|
|
58
25
|
}
|
|
59
26
|
|
|
27
|
+
export function deleteCookie(name, options) {
|
|
28
|
+
setCookie(name, '', 0, options)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
60
32
|
export function areCookiesAuthorized(options) {
|
|
61
33
|
if (document.cookie === undefined || document.cookie === null) {
|
|
62
34
|
return false
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { instrumentMethod } from '../helper/instrumentMethod'
|
|
2
|
+
import { Observable } from '../helper/observable'
|
|
3
|
+
import { elapsed, clocksNow, timeStampNow } from '../helper/tools'
|
|
4
|
+
import { normalizeUrl } from '../helper/urlPolyfill'
|
|
5
|
+
|
|
6
|
+
var fetchObservable
|
|
7
|
+
|
|
8
|
+
export function initFetchObservable() {
|
|
9
|
+
if (!fetchObservable) {
|
|
10
|
+
fetchObservable = createFetchObservable()
|
|
11
|
+
}
|
|
12
|
+
return fetchObservable
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function createFetchObservable() {
|
|
16
|
+
var observable = new Observable(function() {
|
|
17
|
+
if (!window.fetch) {
|
|
18
|
+
return
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
var fetchMethod = instrumentMethod(
|
|
22
|
+
window,
|
|
23
|
+
'fetch',
|
|
24
|
+
function(originalFetch) {
|
|
25
|
+
return function (input, init) {
|
|
26
|
+
var responsePromise
|
|
27
|
+
var context = beforeSend(observable, input, init)
|
|
28
|
+
if (context) {
|
|
29
|
+
responsePromise = originalFetch.call(this, context.input, context.init)
|
|
30
|
+
afterSend(observable, responsePromise, context)
|
|
31
|
+
} else {
|
|
32
|
+
responsePromise = originalFetch.call(this, input, init)
|
|
33
|
+
}
|
|
34
|
+
return responsePromise
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
)
|
|
38
|
+
return fetchMethod.stop
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
return observable
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function beforeSend(observable, input, init) {
|
|
45
|
+
var method = (init && init.method) || (typeof input === 'object' && input.method) || 'GET'
|
|
46
|
+
var url = normalizeUrl((typeof input === 'object' && input.url) || input)
|
|
47
|
+
var startClocks = clocksNow()
|
|
48
|
+
|
|
49
|
+
var context = {
|
|
50
|
+
state: 'start',
|
|
51
|
+
init: init,
|
|
52
|
+
input: input,
|
|
53
|
+
method: method,
|
|
54
|
+
startClocks: startClocks,
|
|
55
|
+
url: url,
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
observable.notify(context)
|
|
59
|
+
|
|
60
|
+
return context
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function afterSend(
|
|
64
|
+
observable,
|
|
65
|
+
responsePromise,
|
|
66
|
+
startContext
|
|
67
|
+
) {
|
|
68
|
+
var reportFetch = function(response) {
|
|
69
|
+
var context = startContext
|
|
70
|
+
context.state = 'complete'
|
|
71
|
+
context.duration = elapsed(context.startClocks.timeStamp, timeStampNow())
|
|
72
|
+
if ('stack' in response || response instanceof Error) {
|
|
73
|
+
context.status = 0
|
|
74
|
+
context.isAborted = response instanceof DOMException && response.code === DOMException.ABORT_ERR
|
|
75
|
+
context.error = response
|
|
76
|
+
observable.notify(context)
|
|
77
|
+
} else if ('status' in response) {
|
|
78
|
+
context.response = response
|
|
79
|
+
context.responseType = response.type
|
|
80
|
+
context.status = response.status
|
|
81
|
+
context.isAborted = false
|
|
82
|
+
observable.notify(context)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
responsePromise.then(reportFetch, reportFetch)
|
|
86
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { instrumentMethodAndCallOriginal } from '../helper/instrumentMethod'
|
|
2
|
+
import { Observable } from '../helper/observable'
|
|
3
|
+
import { normalizeUrl } from '../helper/urlPolyfill'
|
|
4
|
+
import { shallowClone, elapsed, relativeNow, clocksNow, timeStampNow, UUID } from '../helper/tools'
|
|
5
|
+
|
|
6
|
+
var xhrObservable
|
|
7
|
+
var xhrContexts = {}
|
|
8
|
+
var DATA_FLUX_REQUEST_ID_KEY = '_DATAFLUX_REQUEST_UUID'
|
|
9
|
+
export function initXhrObservable() {
|
|
10
|
+
if (!xhrObservable) {
|
|
11
|
+
xhrObservable = createXhrObservable()
|
|
12
|
+
}
|
|
13
|
+
return xhrObservable
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function createXhrObservable() {
|
|
17
|
+
var observable = new Observable(function(){
|
|
18
|
+
var openInstrumentMethod = instrumentMethodAndCallOriginal(XMLHttpRequest.prototype, 'open', {
|
|
19
|
+
before: openXhr,
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
var sendInstrumentMethod = instrumentMethodAndCallOriginal(XMLHttpRequest.prototype, 'send', {
|
|
23
|
+
before: function() {
|
|
24
|
+
sendXhr.call(this, observable)
|
|
25
|
+
},
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
var abortInstrumentMethod = instrumentMethodAndCallOriginal(XMLHttpRequest.prototype, 'abort', {
|
|
29
|
+
before:abortXhr,
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
return function() {
|
|
33
|
+
openInstrumentMethod.stop()
|
|
34
|
+
sendInstrumentMethod.stop()
|
|
35
|
+
abortInstrumentMethod.stop()
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
return observable
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function openXhr(method, url) {
|
|
42
|
+
var requestUUID = this[DATA_FLUX_REQUEST_ID_KEY] || UUID()
|
|
43
|
+
this[DATA_FLUX_REQUEST_ID_KEY] = requestUUID
|
|
44
|
+
xhrContexts[requestUUID] = {
|
|
45
|
+
state: 'open',
|
|
46
|
+
method: method,
|
|
47
|
+
url: normalizeUrl(String(url)),
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function sendXhr(observable) {
|
|
52
|
+
var context = xhrContexts[this[DATA_FLUX_REQUEST_ID_KEY]]
|
|
53
|
+
if (!context) {
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
var startContext = context
|
|
57
|
+
startContext.state = 'start'
|
|
58
|
+
startContext.startTime = relativeNow()
|
|
59
|
+
startContext.startClocks = clocksNow()
|
|
60
|
+
startContext.isAborted = false
|
|
61
|
+
startContext.xhr = this
|
|
62
|
+
var hasBeenReported = false
|
|
63
|
+
var onreadyStateChangeInstrumentMethod = instrumentMethodAndCallOriginal(this, 'onreadystatechange', {
|
|
64
|
+
before: function() {
|
|
65
|
+
if (this.readyState === XMLHttpRequest.DONE) {
|
|
66
|
+
// Try to report the XHR as soon as possible, because the XHR may be mutated by the
|
|
67
|
+
// application during a future event. For example, Angular is calling .abort() on
|
|
68
|
+
// completed requests during a onreadystatechange event, so the status becomes '0'
|
|
69
|
+
// before the request is collected.
|
|
70
|
+
onEnd.call(this)
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
var onEnd = function() {
|
|
77
|
+
this.removeEventListener('loadend', onEnd)
|
|
78
|
+
onreadyStateChangeInstrumentMethod.stop()
|
|
79
|
+
if (hasBeenReported) {
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
hasBeenReported = true
|
|
83
|
+
var completeContext = context
|
|
84
|
+
completeContext.state = 'complete'
|
|
85
|
+
completeContext.duration = elapsed(startContext.startClocks.timeStamp, timeStampNow())
|
|
86
|
+
completeContext.status = this.status
|
|
87
|
+
observable.notify(shallowClone(completeContext))
|
|
88
|
+
clearRequestId.call(this)
|
|
89
|
+
}
|
|
90
|
+
this.addEventListener('loadend', onEnd)
|
|
91
|
+
observable.notify(startContext)
|
|
92
|
+
}
|
|
93
|
+
function clearRequestId() {
|
|
94
|
+
delete xhrContexts[this[DATA_FLUX_REQUEST_ID_KEY]]
|
|
95
|
+
delete this[DATA_FLUX_REQUEST_ID_KEY]
|
|
96
|
+
}
|
|
97
|
+
function abortXhr() {
|
|
98
|
+
var context = xhrContexts[this[DATA_FLUX_REQUEST_ID_KEY]]
|
|
99
|
+
if (context) {
|
|
100
|
+
context.isAborted = true
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { getCurrentSite } from '../browser/cookie'
|
|
2
|
+
import { catchUserErrors } from '../helper/catchUserErrors'
|
|
3
|
+
import { display } from '../helper/display'
|
|
4
|
+
import { assign, isPercentage, ONE_KIBI_BYTE, ONE_SECOND, isNullUndefinedDefaultValue } from '../helper/tools'
|
|
5
|
+
import { computeTransportConfiguration } from './transportConfiguration'
|
|
6
|
+
export function validateAndBuildConfiguration(initConfiguration){
|
|
7
|
+
if (initConfiguration.sampleRate !== undefined && !isPercentage(initConfiguration.sampleRate)) {
|
|
8
|
+
display.error('Sample Rate should be a number between 0 and 100')
|
|
9
|
+
return
|
|
10
|
+
}
|
|
11
|
+
return assign(
|
|
12
|
+
{
|
|
13
|
+
beforeSend:
|
|
14
|
+
initConfiguration.beforeSend && catchUserErrors(initConfiguration.beforeSend, 'beforeSend threw an error:'),
|
|
15
|
+
cookieOptions: buildCookieOptions(initConfiguration),
|
|
16
|
+
sampleRate: isNullUndefinedDefaultValue(initConfiguration.sampleRate, 100),
|
|
17
|
+
service: initConfiguration.service,
|
|
18
|
+
version: initConfiguration.version,
|
|
19
|
+
env: initConfiguration.env,
|
|
20
|
+
silentMultipleInit: !!initConfiguration.silentMultipleInit,
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* beacon payload max queue size implementation is 64kb
|
|
24
|
+
* ensure that we leave room for logs, rum and potential other users
|
|
25
|
+
*/
|
|
26
|
+
batchBytesLimit: 16 * ONE_KIBI_BYTE,
|
|
27
|
+
|
|
28
|
+
eventRateLimiterThreshold: 3000,
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* flush automatically, aim to be lower than ALB connection timeout
|
|
32
|
+
* to maximize connection reuse.
|
|
33
|
+
*/
|
|
34
|
+
flushTimeout: 30 * ONE_SECOND,
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Logs intake limit
|
|
38
|
+
*/
|
|
39
|
+
batchMessagesLimit: 50,
|
|
40
|
+
messageBytesLimit: 256 * ONE_KIBI_BYTE,
|
|
41
|
+
},
|
|
42
|
+
computeTransportConfiguration(initConfiguration)
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function buildCookieOptions(initConfiguration) {
|
|
47
|
+
var cookieOptions = {}
|
|
48
|
+
|
|
49
|
+
cookieOptions.secure = mustUseSecureCookie(initConfiguration)
|
|
50
|
+
cookieOptions.crossSite = !!initConfiguration.useCrossSiteSessionCookie
|
|
51
|
+
|
|
52
|
+
if (initConfiguration.trackSessionAcrossSubdomains) {
|
|
53
|
+
cookieOptions.domain = getCurrentSite()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return cookieOptions
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function mustUseSecureCookie(initConfiguration) {
|
|
60
|
+
return !!initConfiguration.useSecureSessionCookie || !!initConfiguration.useCrossSiteSessionCookie
|
|
61
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { isFunction, isBoolean, some } from '../helper/tools'
|
|
2
|
+
var TRIM_REGIX = /^\s+|\s+$/g
|
|
3
|
+
function getDatakitUrl(url) {
|
|
4
|
+
if (url.lastIndexOf('/') === url.length - 1) return trim(url) + 'v1/write/rum'
|
|
5
|
+
return trim(url) + '/v1/write/rum'
|
|
6
|
+
}
|
|
7
|
+
function trim(str) {
|
|
8
|
+
return str.replace(TRIM_REGIX, '')
|
|
9
|
+
}
|
|
10
|
+
function getLogsEndPoint(url) {
|
|
11
|
+
if (url.lastIndexOf('/') === url.length - 1)
|
|
12
|
+
return trim(url) + 'v1/write/logging'
|
|
13
|
+
return trim(url) + '/v1/write/logging'
|
|
14
|
+
}
|
|
15
|
+
export function computeTransportConfiguration(initConfiguration) {
|
|
16
|
+
var isIntakeUrl = function(url) { return false }
|
|
17
|
+
if ('isIntakeUrl' in initConfiguration && isFunction(initConfiguration.isIntakeUrl) && isBoolean(initConfiguration.isIntakeUrl())) {
|
|
18
|
+
isIntakeUrl = initConfiguration.isIntakeUrl
|
|
19
|
+
}
|
|
20
|
+
var isServerError = function(request) { return false }
|
|
21
|
+
if ('isServerError' in initConfiguration && isFunction(initConfiguration.isServerError) && isBoolean(initConfiguration.isServerError())) {
|
|
22
|
+
isServerError = initConfiguration.isServerError
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
datakitUrl: getDatakitUrl(
|
|
26
|
+
initConfiguration.datakitUrl || initConfiguration.datakitOrigin
|
|
27
|
+
),
|
|
28
|
+
logsEndpoint: getLogsEndPoint(initConfiguration.datakitOrigin),
|
|
29
|
+
isIntakeUrl: isIntakeUrl,
|
|
30
|
+
isServerError: isServerError
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
export function isIntakeRequest(url, configuration) {
|
|
35
|
+
// return haveSameOrigin(url, configuration.datakitUrl)
|
|
36
|
+
var notTakeRequest = [configuration.datakitUrl]
|
|
37
|
+
if (configuration.logsEndpoint) {
|
|
38
|
+
notTakeRequest.push(configuration.logsEndpoint)
|
|
39
|
+
}
|
|
40
|
+
// datakit 地址,log 地址,以及客户自定义过滤方法定义url
|
|
41
|
+
return some(notTakeRequest, function(takeUrl) { return url.indexOf(takeUrl) === 0 }) || configuration.isIntakeUrl(url)
|
|
42
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { computeStackTrace } from '../tracekit'
|
|
2
|
+
import { createHandlingStack, formatErrorMessage, toStackTraceString } from '../helper/errorTools'
|
|
3
|
+
import { mergeObservables, Observable } from '../helper/observable'
|
|
4
|
+
import { find, jsonStringify, map } from '../helper/tools'
|
|
5
|
+
import { ConsoleApiName } from '../helper/display'
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
var consoleObservablesByApi = {}
|
|
9
|
+
|
|
10
|
+
export function initConsoleObservable(apis) {
|
|
11
|
+
var consoleObservables = map(apis, function(api) {
|
|
12
|
+
if (!consoleObservablesByApi[api]) {
|
|
13
|
+
consoleObservablesByApi[api] = createConsoleObservable(api)
|
|
14
|
+
}
|
|
15
|
+
return consoleObservablesByApi[api]
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
return mergeObservables.apply(this, consoleObservables)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* eslint-disable no-console */
|
|
22
|
+
function createConsoleObservable(api) {
|
|
23
|
+
var observable = new Observable(function(){
|
|
24
|
+
var originalConsoleApi = console[api]
|
|
25
|
+
console[api] = function() {
|
|
26
|
+
var params = [].slice.call(arguments)
|
|
27
|
+
originalConsoleApi.apply(console, arguments)
|
|
28
|
+
var handlingStack = createHandlingStack()
|
|
29
|
+
observable.notify(buildConsoleLog(params, api, handlingStack))
|
|
30
|
+
}
|
|
31
|
+
return function() {
|
|
32
|
+
console[api] = originalConsoleApi
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
return observable
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function buildConsoleLog(params, api, handlingStack) {
|
|
39
|
+
// Todo: remove console error prefix in the next major version
|
|
40
|
+
var message = map(params, function(param) { return formatConsoleParameters(param) }).join(' ')
|
|
41
|
+
var stack
|
|
42
|
+
|
|
43
|
+
if (api === ConsoleApiName.error) {
|
|
44
|
+
var firstErrorParam = find(params, function(param) { return param instanceof Error })
|
|
45
|
+
stack = firstErrorParam ? toStackTraceString(computeStackTrace(firstErrorParam)) : undefined
|
|
46
|
+
message = 'console error: '+ message
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
api: api,
|
|
51
|
+
message: message,
|
|
52
|
+
stack: stack,
|
|
53
|
+
handlingStack: handlingStack,
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function formatConsoleParameters(param) {
|
|
58
|
+
if (typeof param === 'string') {
|
|
59
|
+
return param
|
|
60
|
+
}
|
|
61
|
+
if (param instanceof Error) {
|
|
62
|
+
return formatErrorMessage(computeStackTrace(param))
|
|
63
|
+
}
|
|
64
|
+
return jsonStringify(param, undefined, 2)
|
|
65
|
+
}
|
package/src/dataMap.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { RumEventType } from './helper/enums'
|
|
2
2
|
export var commonTags = {
|
|
3
|
+
action_id: 'action.id',
|
|
3
4
|
sdk_name: '_dd.sdk_name',
|
|
4
5
|
sdk_version: '_dd.sdk_version',
|
|
5
6
|
app_id: 'application.id',
|
|
6
|
-
env: '
|
|
7
|
-
service: '
|
|
8
|
-
version: '
|
|
7
|
+
env: 'env',
|
|
8
|
+
service: 'service',
|
|
9
|
+
version: 'version',
|
|
9
10
|
userid: 'user.id',
|
|
10
11
|
user_email: 'user.email',
|
|
11
12
|
user_name: 'user.name',
|
|
@@ -92,27 +93,31 @@ export var dataMap = {
|
|
|
92
93
|
error: {
|
|
93
94
|
type: RumEventType.ERROR,
|
|
94
95
|
tags: {
|
|
96
|
+
error_id: 'error.id',
|
|
95
97
|
trace_id: '_dd.trace_id',
|
|
96
98
|
span_id: '_dd.span_id',
|
|
97
99
|
error_source: 'error.source',
|
|
98
100
|
error_type: 'error.type',
|
|
99
|
-
error_handling: 'error.handling'
|
|
100
|
-
resource_url: 'error.resource.url',
|
|
101
|
-
resource_url_host: 'error.resource.url_host',
|
|
102
|
-
resource_url_path: 'error.resource.url_path',
|
|
103
|
-
resource_url_path_group: 'error.resource.url_path_group',
|
|
104
|
-
resource_status: 'error.resource.status',
|
|
105
|
-
resource_status_group: 'error.resource.status_group',
|
|
106
|
-
resource_method: 'error.resource.method'
|
|
101
|
+
error_handling: 'error.handling'
|
|
102
|
+
// resource_url: 'error.resource.url',
|
|
103
|
+
// resource_url_host: 'error.resource.url_host',
|
|
104
|
+
// resource_url_path: 'error.resource.url_path',
|
|
105
|
+
// resource_url_path_group: 'error.resource.url_path_group',
|
|
106
|
+
// resource_status: 'error.resource.status',
|
|
107
|
+
// resource_status_group: 'error.resource.status_group',
|
|
108
|
+
// resource_method: 'error.resource.method'
|
|
107
109
|
},
|
|
108
110
|
fields: {
|
|
109
111
|
error_message: ['string', 'error.message'],
|
|
110
|
-
error_stack: ['string', 'error.stack']
|
|
112
|
+
error_stack: ['string', 'error.stack'],
|
|
113
|
+
error_causes: ['string', 'error.causes']
|
|
111
114
|
}
|
|
112
115
|
},
|
|
113
116
|
long_task: {
|
|
114
117
|
type: RumEventType.LONG_TASK,
|
|
115
|
-
tags: {
|
|
118
|
+
tags: {
|
|
119
|
+
long_task_id: 'long_task.id'
|
|
120
|
+
},
|
|
116
121
|
fields: {
|
|
117
122
|
duration: 'long_task.duration'
|
|
118
123
|
}
|
|
@@ -120,7 +125,6 @@ export var dataMap = {
|
|
|
120
125
|
action: {
|
|
121
126
|
type: RumEventType.ACTION,
|
|
122
127
|
tags: {
|
|
123
|
-
action_id: 'action.id',
|
|
124
128
|
action_name: 'action.target.name',
|
|
125
129
|
action_type: 'action.type'
|
|
126
130
|
},
|
|
@@ -128,6 +132,7 @@ export var dataMap = {
|
|
|
128
132
|
duration: 'action.loading_time',
|
|
129
133
|
action_error_count: 'action.error.count',
|
|
130
134
|
action_resource_count: 'action.resource.count',
|
|
135
|
+
action_frustration_types: 'action.frustration.type',
|
|
131
136
|
action_long_task_count: 'action.long_task.count'
|
|
132
137
|
}
|
|
133
138
|
},
|
|
@@ -136,13 +141,13 @@ export var dataMap = {
|
|
|
136
141
|
tags: {
|
|
137
142
|
error_source: 'error.source',
|
|
138
143
|
error_type: 'error.type',
|
|
139
|
-
error_resource_url: '
|
|
140
|
-
error_resource_url_host: '
|
|
141
|
-
error_resource_url_path: '
|
|
142
|
-
error_resource_url_path_group: '
|
|
143
|
-
error_resource_status: '
|
|
144
|
-
error_resource_status_group: '
|
|
145
|
-
error_resource_method: '
|
|
144
|
+
error_resource_url: 'http.url',
|
|
145
|
+
error_resource_url_host: 'http.url_host',
|
|
146
|
+
error_resource_url_path: 'http.url_path',
|
|
147
|
+
error_resource_url_path_group: 'http.url_path_group',
|
|
148
|
+
error_resource_status: 'http.status_code',
|
|
149
|
+
error_resource_status_group: 'http.status_group',
|
|
150
|
+
error_resource_method: 'http.method',
|
|
146
151
|
action_id: 'user_action.id',
|
|
147
152
|
service: 'service',
|
|
148
153
|
status: 'status'
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ErrorSource, computeRawError } from '../helper/errorTools'
|
|
2
|
+
import { clocksNow } from '../helper/tools'
|
|
3
|
+
import { ErrorHandling } from '../helper/enums'
|
|
4
|
+
import { startUnhandledErrorCollection } from '../tracekit'
|
|
5
|
+
|
|
6
|
+
export function trackRuntimeError(errorObservable) {
|
|
7
|
+
return startUnhandledErrorCollection(function (stackTrace, originalError) {
|
|
8
|
+
errorObservable.notify(
|
|
9
|
+
computeRawError({
|
|
10
|
+
stackTrace: stackTrace,
|
|
11
|
+
originalError: originalError,
|
|
12
|
+
startClocks: clocksNow(),
|
|
13
|
+
nonErrorPrefix: 'Uncaught',
|
|
14
|
+
source: ErrorSource.SOURCE,
|
|
15
|
+
handling: ErrorHandling.UNHANDLED
|
|
16
|
+
})
|
|
17
|
+
)
|
|
18
|
+
})
|
|
19
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { relativeNow, ONE_MINUTE, filter, map} from './tools'
|
|
2
|
+
|
|
3
|
+
var END_OF_TIMES = Infinity
|
|
4
|
+
|
|
5
|
+
export var CLEAR_OLD_CONTEXTS_INTERVAL = ONE_MINUTE
|
|
6
|
+
export function ContextHistory(expireDelay) {
|
|
7
|
+
this.expireDelay = expireDelay
|
|
8
|
+
this.entries = []
|
|
9
|
+
var _this = this
|
|
10
|
+
this.clearOldContextsInterval = setInterval(function(){
|
|
11
|
+
_this.clearOldContexts()
|
|
12
|
+
}, CLEAR_OLD_CONTEXTS_INTERVAL);
|
|
13
|
+
}
|
|
14
|
+
ContextHistory.prototype.add = function(context, startTime) {
|
|
15
|
+
var _this = this
|
|
16
|
+
var entry = {
|
|
17
|
+
context: context,
|
|
18
|
+
startTime: startTime,
|
|
19
|
+
endTime: END_OF_TIMES,
|
|
20
|
+
remove: function() {
|
|
21
|
+
var index = _this.entries.indexOf(entry)
|
|
22
|
+
if (index >= 0) {
|
|
23
|
+
_this.entries.splice(index, 1)
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
close: function(endTime){
|
|
27
|
+
entry.endTime = endTime
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
this.entries.unshift(entry)
|
|
31
|
+
return entry
|
|
32
|
+
}
|
|
33
|
+
ContextHistory.prototype.find = function(startTime) {
|
|
34
|
+
if (typeof startTime === 'undefined') {
|
|
35
|
+
startTime = END_OF_TIMES
|
|
36
|
+
}
|
|
37
|
+
for (var entry of this.entries) {
|
|
38
|
+
if (entry.startTime <= startTime) {
|
|
39
|
+
if (startTime <= entry.endTime) {
|
|
40
|
+
return entry.context
|
|
41
|
+
}
|
|
42
|
+
break
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Helper function to close the currently active context, if any. This method assumes that entries
|
|
48
|
+
* are not overlapping.
|
|
49
|
+
*/
|
|
50
|
+
ContextHistory.prototype.closeActive = function(endTime) {
|
|
51
|
+
var latestEntry = this.entries[0]
|
|
52
|
+
if (latestEntry && latestEntry.endTime === END_OF_TIMES) {
|
|
53
|
+
latestEntry.close(endTime)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Return all contexts that were active during `startTime`, or all currently active contexts if no
|
|
58
|
+
* `startTime` is provided.
|
|
59
|
+
*/
|
|
60
|
+
ContextHistory.prototype.findAll = function(startTime){
|
|
61
|
+
if (typeof startTime === 'undefined') {
|
|
62
|
+
startTime = END_OF_TIMES
|
|
63
|
+
}
|
|
64
|
+
var result = filter(this.entries, function(entry) { return entry.startTime <= startTime && startTime <= entry.endTime })
|
|
65
|
+
return map(result, function(entry) { return entry.context })
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Remove all entries from this collection.
|
|
69
|
+
*/
|
|
70
|
+
ContextHistory.prototype.reset = function () {
|
|
71
|
+
this.entries = []
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Stop internal garbage collection of past entries.
|
|
75
|
+
*/
|
|
76
|
+
ContextHistory.prototype.stop = function() {
|
|
77
|
+
clearInterval(this.clearOldContextsInterval)
|
|
78
|
+
}
|
|
79
|
+
ContextHistory.prototype.clearOldContexts = function() {
|
|
80
|
+
var oldTimeThreshold = relativeNow() - this.expireDelay
|
|
81
|
+
while (this.entries.length > 0 && this.entries[this.entries.length - 1].endTime < oldTimeThreshold) {
|
|
82
|
+
this.entries.pop()
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ErrorSource } from './errorTools'
|
|
2
|
+
import { clocksNow, ONE_MINUTE } from './tools'
|
|
3
|
+
export function createEventRateLimiter(
|
|
4
|
+
eventType,
|
|
5
|
+
limit,
|
|
6
|
+
onLimitReached
|
|
7
|
+
) {
|
|
8
|
+
var eventCount = 0
|
|
9
|
+
var allowNextEvent = false
|
|
10
|
+
return {
|
|
11
|
+
isLimitReached: function() {
|
|
12
|
+
if (eventCount === 0) {
|
|
13
|
+
setTimeout(function(){
|
|
14
|
+
eventCount = 0
|
|
15
|
+
}, ONE_MINUTE)
|
|
16
|
+
}
|
|
17
|
+
eventCount += 1
|
|
18
|
+
if (eventCount <= limit || allowNextEvent) {
|
|
19
|
+
allowNextEvent = false
|
|
20
|
+
return false
|
|
21
|
+
}
|
|
22
|
+
if (eventCount === limit + 1) {
|
|
23
|
+
allowNextEvent = true
|
|
24
|
+
try {
|
|
25
|
+
onLimitReached({
|
|
26
|
+
message: 'Reached max number of ' + eventType +'s by minute: ' + limit,
|
|
27
|
+
source: ErrorSource.AGENT,
|
|
28
|
+
startClocks: clocksNow(),
|
|
29
|
+
})
|
|
30
|
+
} finally {
|
|
31
|
+
allowNextEvent = false
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return true
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|