@newrelic/browser-agent 1.261.2 → 1.263.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/CHANGELOG.md +27 -0
- package/dist/cjs/common/config/state/configurable.js +4 -4
- package/dist/cjs/common/config/state/init.js +5 -3
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/context/shared-context.js +2 -2
- package/dist/cjs/common/drain/drain.js +22 -16
- package/dist/cjs/common/harvest/harvest.js +1 -1
- package/dist/cjs/common/session/session-entity.js +2 -2
- package/dist/cjs/common/timing/time-keeper.js +13 -2
- package/dist/cjs/common/util/console.js +3 -4
- package/dist/cjs/common/util/obfuscate.js +3 -3
- package/dist/cjs/common/wrap/wrap-logger.js +2 -0
- package/dist/cjs/common/wrap/wrap-xhr.js +1 -1
- package/dist/cjs/features/logging/aggregate/index.js +27 -2
- package/dist/cjs/features/logging/constants.js +2 -5
- package/dist/cjs/features/logging/shared/utils.js +2 -18
- package/dist/cjs/features/metrics/aggregate/index.js +16 -0
- package/dist/cjs/features/page_view_event/aggregate/index.js +20 -4
- package/dist/cjs/features/session_replay/aggregate/index.js +1 -1
- package/dist/cjs/features/session_replay/shared/recorder.js +1 -1
- package/dist/cjs/features/session_trace/aggregate/index.js +1 -1
- package/dist/cjs/features/spa/aggregate/index.js +1 -1
- package/dist/cjs/features/utils/aggregate-base.js +4 -3
- package/dist/cjs/features/utils/instrument-base.js +2 -2
- package/dist/cjs/loaders/agent-base.js +1 -1
- package/dist/cjs/loaders/agent.js +3 -4
- package/dist/cjs/loaders/api/api.js +13 -16
- package/dist/cjs/loaders/micro-agent.js +5 -5
- package/dist/esm/common/config/state/configurable.js +4 -4
- package/dist/esm/common/config/state/init.js +5 -3
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/context/shared-context.js +2 -2
- package/dist/esm/common/drain/drain.js +22 -16
- package/dist/esm/common/harvest/harvest.js +1 -1
- package/dist/esm/common/session/session-entity.js +2 -2
- package/dist/esm/common/timing/time-keeper.js +12 -2
- package/dist/esm/common/util/console.js +3 -4
- package/dist/esm/common/util/obfuscate.js +3 -3
- package/dist/esm/common/wrap/wrap-logger.js +2 -0
- package/dist/esm/common/wrap/wrap-xhr.js +1 -1
- package/dist/esm/features/logging/aggregate/index.js +28 -3
- package/dist/esm/features/logging/constants.js +1 -4
- package/dist/esm/features/logging/shared/utils.js +2 -18
- package/dist/esm/features/metrics/aggregate/index.js +16 -0
- package/dist/esm/features/page_view_event/aggregate/index.js +21 -5
- package/dist/esm/features/session_replay/aggregate/index.js +1 -1
- package/dist/esm/features/session_replay/shared/recorder.js +1 -1
- package/dist/esm/features/session_trace/aggregate/index.js +1 -1
- package/dist/esm/features/spa/aggregate/index.js +1 -1
- package/dist/esm/features/utils/aggregate-base.js +4 -3
- package/dist/esm/features/utils/instrument-base.js +2 -2
- package/dist/esm/loaders/agent-base.js +1 -1
- package/dist/esm/loaders/agent.js +3 -4
- package/dist/esm/loaders/api/api.js +15 -18
- package/dist/esm/loaders/micro-agent.js +5 -5
- package/dist/types/common/config/state/init.d.ts.map +1 -1
- package/dist/types/common/drain/drain.d.ts.map +1 -1
- package/dist/types/common/timing/time-keeper.d.ts +2 -1
- package/dist/types/common/timing/time-keeper.d.ts.map +1 -1
- package/dist/types/common/util/console.d.ts +1 -1
- package/dist/types/common/util/console.d.ts.map +1 -1
- package/dist/types/common/wrap/wrap-logger.d.ts.map +1 -1
- package/dist/types/features/logging/aggregate/index.d.ts +1 -1
- package/dist/types/features/logging/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/logging/constants.d.ts +0 -3
- package/dist/types/features/logging/constants.d.ts.map +1 -1
- package/dist/types/features/logging/shared/utils.d.ts +1 -1
- package/dist/types/features/logging/shared/utils.d.ts.map +1 -1
- package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
- package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
- package/dist/types/loaders/agent.d.ts.map +1 -1
- package/dist/types/loaders/api/api.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/common/config/state/configurable.js +4 -4
- package/src/common/config/state/init.js +4 -3
- package/src/common/context/shared-context.js +2 -2
- package/src/common/drain/drain.js +21 -16
- package/src/common/harvest/harvest.js +1 -1
- package/src/common/session/session-entity.js +2 -2
- package/src/common/timing/time-keeper.js +14 -2
- package/src/common/util/console.js +3 -4
- package/src/common/util/obfuscate.js +3 -3
- package/src/common/wrap/wrap-logger.js +2 -0
- package/src/common/wrap/wrap-xhr.js +1 -1
- package/src/features/logging/aggregate/index.js +30 -3
- package/src/features/logging/constants.js +0 -4
- package/src/features/logging/shared/utils.js +2 -19
- package/src/features/metrics/aggregate/index.js +12 -0
- package/src/features/page_view_event/aggregate/index.js +22 -5
- package/src/features/session_replay/aggregate/index.js +1 -1
- package/src/features/session_replay/shared/recorder.js +1 -1
- package/src/features/session_trace/aggregate/index.js +1 -1
- package/src/features/spa/aggregate/index.js +1 -1
- package/src/features/utils/aggregate-base.js +4 -3
- package/src/features/utils/instrument-base.js +2 -2
- package/src/loaders/agent-base.js +1 -1
- package/src/loaders/agent.js +3 -4
- package/src/loaders/api/api.js +15 -18
- package/src/loaders/micro-agent.js +5 -5
|
@@ -182,7 +182,7 @@ export class SessionEntity {
|
|
|
182
182
|
|
|
183
183
|
return obj
|
|
184
184
|
} catch (e) {
|
|
185
|
-
warn(
|
|
185
|
+
warn(10, e)
|
|
186
186
|
// storage is inaccessible
|
|
187
187
|
return {}
|
|
188
188
|
}
|
|
@@ -208,7 +208,7 @@ export class SessionEntity {
|
|
|
208
208
|
return data
|
|
209
209
|
} catch (e) {
|
|
210
210
|
// storage is inaccessible
|
|
211
|
-
warn(
|
|
211
|
+
warn(11, e)
|
|
212
212
|
return null
|
|
213
213
|
}
|
|
214
214
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { originTime } from '../constants/runtime'
|
|
2
2
|
import { getRuntime } from '../config/config'
|
|
3
3
|
|
|
4
|
+
const rfc2616Regex = /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), ([0-3][0-9]) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ([0-9]{4}) ([01][0-9]|2[0-3])(:[0-5][0-9]){2} GMT$/
|
|
5
|
+
|
|
4
6
|
/**
|
|
5
7
|
* Class used to adjust the timestamp of harvested data to New Relic server time. This
|
|
6
8
|
* is done by tracking the performance timings of the RUM call and applying a calculation
|
|
@@ -29,7 +31,7 @@ export class TimeKeeper {
|
|
|
29
31
|
/**
|
|
30
32
|
* Represents whether the timekeeper is in a state that it can accurately convert
|
|
31
33
|
* timestamps.
|
|
32
|
-
* @type {
|
|
34
|
+
* @type {boolean}
|
|
33
35
|
*/
|
|
34
36
|
#ready = false
|
|
35
37
|
|
|
@@ -46,6 +48,10 @@ export class TimeKeeper {
|
|
|
46
48
|
return this.#correctedOriginTime
|
|
47
49
|
}
|
|
48
50
|
|
|
51
|
+
get localTimeDiff () {
|
|
52
|
+
return this.#localTimeDiff
|
|
53
|
+
}
|
|
54
|
+
|
|
49
55
|
/**
|
|
50
56
|
* Process a rum request to calculate NR server time.
|
|
51
57
|
* @param rumRequest {XMLHttpRequest} The xhr for the rum request
|
|
@@ -53,12 +59,16 @@ export class TimeKeeper {
|
|
|
53
59
|
* @param endTime {number} The end time of the RUM request
|
|
54
60
|
*/
|
|
55
61
|
processRumRequest (rumRequest, startTime, endTime) {
|
|
56
|
-
this.processStoredDiff()
|
|
62
|
+
this.processStoredDiff() // Check session entity for stored time diff
|
|
57
63
|
if (this.#ready) return // Server time calculated from session entity
|
|
64
|
+
|
|
58
65
|
const responseDateHeader = rumRequest.getResponseHeader('Date')
|
|
59
66
|
if (!responseDateHeader) {
|
|
60
67
|
throw new Error('Missing date header on rum response.')
|
|
61
68
|
}
|
|
69
|
+
if (!rfc2616Regex.test(responseDateHeader)) {
|
|
70
|
+
throw new Error('Date header invalid format.')
|
|
71
|
+
}
|
|
62
72
|
|
|
63
73
|
const medianRumOffset = (endTime - startTime) / 2
|
|
64
74
|
const serverOffset = startTime + medianRumOffset
|
|
@@ -96,6 +106,8 @@ export class TimeKeeper {
|
|
|
96
106
|
|
|
97
107
|
/** Process the session entity and use the info to set the main time calculations if present */
|
|
98
108
|
processStoredDiff () {
|
|
109
|
+
if (this.#ready) return // Time diff has already been calculated
|
|
110
|
+
|
|
99
111
|
const storedServerTimeDiff = this.#session?.read()?.serverTimeDiff
|
|
100
112
|
if (typeof storedServerTimeDiff === 'number' && !isNaN(storedServerTimeDiff)) {
|
|
101
113
|
this.#localTimeDiff = storedServerTimeDiff
|
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
* @param {*} [secondary] Secondary data to include, usually an error or object
|
|
5
5
|
* @returns
|
|
6
6
|
*/
|
|
7
|
-
export function warn (
|
|
8
|
-
if (typeof console.
|
|
9
|
-
console.
|
|
10
|
-
if (secondary) console.warn(secondary)
|
|
7
|
+
export function warn (code, secondary) {
|
|
8
|
+
if (typeof console.debug !== 'function') return
|
|
9
|
+
console.debug(`New Relic Warning: https://github.com/newrelic/newrelic-browser-agent/blob/main/docs/warning-codes.md#${code}`, secondary)
|
|
11
10
|
}
|
|
@@ -49,16 +49,16 @@ export function validateRules (rules) {
|
|
|
49
49
|
var invalidRegexDetected = false
|
|
50
50
|
for (var i = 0; i < rules.length; i++) {
|
|
51
51
|
if (!('regex' in rules[i])) {
|
|
52
|
-
warn(
|
|
52
|
+
warn(12)
|
|
53
53
|
invalidRegexDetected = true
|
|
54
54
|
} else if (typeof rules[i].regex !== 'string' && !(rules[i].regex instanceof RegExp)) {
|
|
55
|
-
warn(
|
|
55
|
+
warn(13)
|
|
56
56
|
invalidRegexDetected = true
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
var replacement = rules[i].replacement
|
|
60
60
|
if (replacement && typeof replacement !== 'string') {
|
|
61
|
-
warn(
|
|
61
|
+
warn(14)
|
|
62
62
|
invalidReplacementDetected = true
|
|
63
63
|
}
|
|
64
64
|
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import { ee as baseEE, contextId } from '../event-emitter/contextual-ee'
|
|
11
11
|
import { EventContext } from '../event-emitter/event-context'
|
|
12
|
+
import { warn } from '../util/console'
|
|
12
13
|
import { createWrapperWithEmitter as wfn } from './wrap-function'
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -20,6 +21,7 @@ import { createWrapperWithEmitter as wfn } from './wrap-function'
|
|
|
20
21
|
*/
|
|
21
22
|
// eslint-disable-next-line
|
|
22
23
|
export function wrapLogger(sharedEE, parent, loggerFn, context) {
|
|
24
|
+
if (!(typeof parent === 'object' && !!parent && typeof loggerFn === 'string' && !!loggerFn && typeof parent[loggerFn] === 'function')) return warn(29)
|
|
23
25
|
const ee = scopedEE(sharedEE)
|
|
24
26
|
const wrapFn = wfn(ee)
|
|
25
27
|
|
|
@@ -56,7 +56,7 @@ export function wrapXhr (sharedEE) {
|
|
|
56
56
|
ee.emit('new-xhr', [xhr], context)
|
|
57
57
|
xhr.addEventListener(READY_STATE_CHANGE, wrapXHR(context), eventListenerOpts(false))
|
|
58
58
|
} catch (e) {
|
|
59
|
-
warn(
|
|
59
|
+
warn(15, e)
|
|
60
60
|
try {
|
|
61
61
|
ee.emit('internal-error', [e])
|
|
62
62
|
} catch (err) {
|
|
@@ -6,8 +6,9 @@ import { warn } from '../../../common/util/console'
|
|
|
6
6
|
import { stringify } from '../../../common/util/stringify'
|
|
7
7
|
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants'
|
|
8
8
|
import { AggregateBase } from '../../utils/aggregate-base'
|
|
9
|
-
import { FEATURE_NAME, LOGGING_EVENT_EMITTER_CHANNEL,
|
|
9
|
+
import { FEATURE_NAME, LOGGING_EVENT_EMITTER_CHANNEL, LOG_LEVELS, MAX_PAYLOAD_SIZE } from '../constants'
|
|
10
10
|
import { Log } from '../shared/log'
|
|
11
|
+
import { isValidLogLevel } from '../shared/utils'
|
|
11
12
|
|
|
12
13
|
export class Aggregate extends AggregateBase {
|
|
13
14
|
static featureName = FEATURE_NAME
|
|
@@ -43,8 +44,34 @@ export class Aggregate extends AggregateBase {
|
|
|
43
44
|
})
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
handleLog (timestamp, message, attributes, level) {
|
|
47
|
+
handleLog (timestamp, message, attributes = {}, level = LOG_LEVELS.INFO) {
|
|
47
48
|
if (this.blocked) return
|
|
49
|
+
|
|
50
|
+
if (!attributes || typeof attributes !== 'object') attributes = {}
|
|
51
|
+
if (typeof level === 'string') level = level.toUpperCase()
|
|
52
|
+
if (!isValidLogLevel(level)) return warn(30, level)
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
if (typeof message !== 'string') {
|
|
56
|
+
const stringified = stringify(message)
|
|
57
|
+
/**
|
|
58
|
+
* Error instances convert to `{}` when stringified
|
|
59
|
+
* Symbol converts to '' when stringified
|
|
60
|
+
* other cases tbd
|
|
61
|
+
* */
|
|
62
|
+
if (!!stringified && stringified !== '{}') message = stringified
|
|
63
|
+
else message = String(message)
|
|
64
|
+
}
|
|
65
|
+
} catch (err) {
|
|
66
|
+
warn(16, message)
|
|
67
|
+
return
|
|
68
|
+
}
|
|
69
|
+
if (typeof message !== 'string' || !message) return warn(32)
|
|
70
|
+
if (message.length > MAX_PAYLOAD_SIZE) {
|
|
71
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Logging/Harvest/Failed/Seen', message.length])
|
|
72
|
+
return warn(31, message.slice(0, 25) + '...')
|
|
73
|
+
}
|
|
74
|
+
|
|
48
75
|
const log = new Log(
|
|
49
76
|
this.#agentRuntime.timeKeeper.convertRelativeTimestamp(timestamp),
|
|
50
77
|
message,
|
|
@@ -54,7 +81,7 @@ export class Aggregate extends AggregateBase {
|
|
|
54
81
|
const logBytes = log.message.length + stringify(log.attributes).length + log.level.length + 10 // timestamp == 10 chars
|
|
55
82
|
if (logBytes > MAX_PAYLOAD_SIZE) {
|
|
56
83
|
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Logging/Harvest/Failed/Seen', logBytes])
|
|
57
|
-
return warn(
|
|
84
|
+
return warn(31, log.message.slice(0, 25) + '...')
|
|
58
85
|
}
|
|
59
86
|
|
|
60
87
|
if (this.estimatedBytes + logBytes >= MAX_PAYLOAD_SIZE) {
|
|
@@ -13,7 +13,3 @@ export const LOGGING_EVENT_EMITTER_CHANNEL = 'log'
|
|
|
13
13
|
export const FEATURE_NAME = FEATURE_NAMES.logging
|
|
14
14
|
|
|
15
15
|
export const MAX_PAYLOAD_SIZE = 1000000
|
|
16
|
-
|
|
17
|
-
export const LOGGING_FAILURE_MESSAGE = 'failed to wrap logger: '
|
|
18
|
-
export const LOGGING_LEVEL_FAILURE_MESSAGE = 'invalid log level: '
|
|
19
|
-
export const LOGGING_IGNORED = 'ignored log: '
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { handle } from '../../../common/event-emitter/handle'
|
|
2
2
|
import { now } from '../../../common/timing/now'
|
|
3
|
-
import { warn } from '../../../common/util/console'
|
|
4
|
-
import { stringify } from '../../../common/util/stringify'
|
|
5
3
|
import { FEATURE_NAMES } from '../../../loaders/features/features'
|
|
6
4
|
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants'
|
|
7
5
|
import { LOGGING_EVENT_EMITTER_CHANNEL, LOG_LEVELS } from '../constants'
|
|
@@ -13,31 +11,16 @@ import { LOGGING_EVENT_EMITTER_CHANNEL, LOG_LEVELS } from '../constants'
|
|
|
13
11
|
* @param {enum} level - the log level enum
|
|
14
12
|
*/
|
|
15
13
|
export function bufferLog (ee, message, customAttributes = {}, level = LOG_LEVELS.INFO) {
|
|
16
|
-
try {
|
|
17
|
-
if (typeof message !== 'string') {
|
|
18
|
-
const stringified = stringify(message)
|
|
19
|
-
/**
|
|
20
|
-
* Error instances convert to `{}` when stringified
|
|
21
|
-
* Symbol converts to '' when stringified
|
|
22
|
-
* other cases tbd
|
|
23
|
-
* */
|
|
24
|
-
if (!!stringified && stringified !== '{}') message = stringified
|
|
25
|
-
else message = String(message)
|
|
26
|
-
}
|
|
27
|
-
} catch (err) {
|
|
28
|
-
warn('could not cast log message to string', message)
|
|
29
|
-
return
|
|
30
|
-
}
|
|
31
14
|
handle(SUPPORTABILITY_METRIC_CHANNEL, [`API/logging/${level.toLowerCase()}/called`], undefined, FEATURE_NAMES.metrics, ee)
|
|
32
15
|
handle(LOGGING_EVENT_EMITTER_CHANNEL, [now(), message, customAttributes, level], undefined, FEATURE_NAMES.logging, ee)
|
|
33
16
|
}
|
|
34
17
|
|
|
35
18
|
/**
|
|
36
19
|
* Checks if a supplied log level is acceptable for use in generating a log event
|
|
37
|
-
* @param {string} level
|
|
20
|
+
* @param {string} level -- must be cast to uppercase before running this test
|
|
38
21
|
* @returns {boolean}
|
|
39
22
|
*/
|
|
40
23
|
export function isValidLogLevel (level) {
|
|
41
24
|
if (typeof level !== 'string') return false
|
|
42
|
-
return Object.values(LOG_LEVELS).some(logLevel => logLevel
|
|
25
|
+
return Object.values(LOG_LEVELS).some(logLevel => logLevel === level)
|
|
43
26
|
}
|
|
@@ -96,6 +96,18 @@ export class Aggregate extends AggregateBase {
|
|
|
96
96
|
// Check if proxy for either chunks or beacon is being used
|
|
97
97
|
if (proxy.assets) this.storeSupportabilityMetrics('Config/AssetsUrl/Changed')
|
|
98
98
|
if (proxy.beacon) this.storeSupportabilityMetrics('Config/BeaconUrl/Changed')
|
|
99
|
+
|
|
100
|
+
if (isBrowserScope && window.MutationObserver) {
|
|
101
|
+
this.storeSupportabilityMetrics('Generic/VideoElement/Added', window.document.querySelectorAll('video').length)
|
|
102
|
+
const mo = new MutationObserver(records => {
|
|
103
|
+
records.forEach(record => {
|
|
104
|
+
record.addedNodes.forEach(addedNode => {
|
|
105
|
+
if (addedNode instanceof HTMLVideoElement) { this.storeSupportabilityMetrics('Generic/VideoElement/Added', 1) }
|
|
106
|
+
})
|
|
107
|
+
})
|
|
108
|
+
})
|
|
109
|
+
mo.observe(window.document.body, { childList: true, subtree: true })
|
|
110
|
+
}
|
|
99
111
|
}
|
|
100
112
|
|
|
101
113
|
eachSessionChecks () {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { globalScope, isBrowserScope, originTime } from '../../../common/constants/runtime'
|
|
2
2
|
import { addPT, addPN } from '../../../common/timing/nav-timing'
|
|
3
3
|
import { stringify } from '../../../common/util/stringify'
|
|
4
|
-
import { getInfo, getRuntime } from '../../../common/config/config'
|
|
4
|
+
import { getInfo, getRuntime, isConfigured } from '../../../common/config/config'
|
|
5
5
|
import { Harvest } from '../../../common/harvest/harvest'
|
|
6
6
|
import * as CONSTANTS from '../constants'
|
|
7
7
|
import { getActivatedFeaturesFlags } from './initialized-features'
|
|
@@ -28,6 +28,11 @@ export class Aggregate extends AggregateBase {
|
|
|
28
28
|
this.firstByteToDomContent = 0 // our "dom processing" duration
|
|
29
29
|
this.timeKeeper = new TimeKeeper(this.agentIdentifier)
|
|
30
30
|
|
|
31
|
+
if (!isConfigured(agentIdentifier)) {
|
|
32
|
+
this.ee.abort()
|
|
33
|
+
return warn(43)
|
|
34
|
+
}
|
|
35
|
+
|
|
31
36
|
if (isBrowserScope) {
|
|
32
37
|
timeToFirstByte.subscribe(({ value, attrs }) => {
|
|
33
38
|
const navEntry = attrs.navigationEntry
|
|
@@ -48,7 +53,6 @@ export class Aggregate extends AggregateBase {
|
|
|
48
53
|
const agentRuntime = getRuntime(this.agentIdentifier)
|
|
49
54
|
const harvester = new Harvest(this)
|
|
50
55
|
|
|
51
|
-
if (!info.beacon) return
|
|
52
56
|
if (info.queueTime) this.aggregator.store('measures', 'qt', { value: info.queueTime })
|
|
53
57
|
if (info.applicationTime) this.aggregator.store('measures', 'ap', { value: info.applicationTime })
|
|
54
58
|
|
|
@@ -126,11 +130,24 @@ export class Aggregate extends AggregateBase {
|
|
|
126
130
|
if (!this.timeKeeper.ready) throw new Error('TimeKeeper not ready')
|
|
127
131
|
|
|
128
132
|
agentRuntime.timeKeeper = this.timeKeeper
|
|
133
|
+
|
|
134
|
+
// Check if the time diff is such that we need to capture a supportability metric
|
|
135
|
+
if (this.timeKeeper.localTimeDiff >= 12 * 60 * 60 * 1000) {
|
|
136
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['PVE/NRTime/Calculation/DiffExceed12Hrs'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
137
|
+
} else if (this.timeKeeper.localTimeDiff >= 6 * 60 * 60 * 1000) {
|
|
138
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['PVE/NRTime/Calculation/DiffExceed6Hrs'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
139
|
+
} else if (this.timeKeeper.localTimeDiff >= 60 * 60 * 1000) {
|
|
140
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['PVE/NRTime/Calculation/DiffExceed1Hrs'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
141
|
+
}
|
|
129
142
|
} catch (error) {
|
|
130
|
-
|
|
143
|
+
if (error?.message?.indexOf('invalid format') > 0) {
|
|
144
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['PVE/NRTime/Calculation/InvalidFormat'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
145
|
+
} else {
|
|
146
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['PVE/NRTime/Calculation/Failed'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
147
|
+
}
|
|
131
148
|
drain(this.agentIdentifier, FEATURE_NAMES.metrics, true)
|
|
132
149
|
this.ee.abort()
|
|
133
|
-
warn(
|
|
150
|
+
warn(17, error)
|
|
134
151
|
return
|
|
135
152
|
}
|
|
136
153
|
|
|
@@ -141,7 +158,7 @@ export class Aggregate extends AggregateBase {
|
|
|
141
158
|
this.drain()
|
|
142
159
|
} catch (err) {
|
|
143
160
|
this.ee.abort()
|
|
144
|
-
warn(
|
|
161
|
+
warn(18, err)
|
|
145
162
|
}
|
|
146
163
|
}
|
|
147
164
|
})
|
|
@@ -394,7 +394,7 @@ export class Aggregate extends AggregateBase {
|
|
|
394
394
|
|
|
395
395
|
/** Abort the feature, once aborted it will not resume */
|
|
396
396
|
abort (reason = {}, data) {
|
|
397
|
-
warn(
|
|
397
|
+
warn(33, reason.message)
|
|
398
398
|
handle(SUPPORTABILITY_METRIC_CHANNEL, [`SessionReplay/Abort/${reason.sm}`, data], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
399
399
|
this.blocked = true
|
|
400
400
|
this.mode = MODE.OFF
|
|
@@ -35,7 +35,7 @@ export class Recorder {
|
|
|
35
35
|
/** Config to inform to inline stylesheet contents (true default) */
|
|
36
36
|
this.shouldInlineStylesheets = getConfigurationValue(this.parent.agentIdentifier, 'session_replay.inline_stylesheet')
|
|
37
37
|
/** A flag that can be set to false by failing conversions to stop the fetching process */
|
|
38
|
-
this.shouldFix = this.shouldInlineStylesheets
|
|
38
|
+
this.shouldFix = this.shouldInlineStylesheets && getConfigurationValue(this.parent.agentIdentifier, 'session_replay.fix_stylesheets')
|
|
39
39
|
/** The method to stop recording. This defaults to a noop, but is overwritten once the recording library is imported and initialized */
|
|
40
40
|
this.stopRecording = () => { /* no-op until set by rrweb initializer */ }
|
|
41
41
|
}
|
|
@@ -757,7 +757,7 @@ export class Aggregate extends AggregateBase {
|
|
|
757
757
|
handle(SUPPORTABILITY_METRIC_CHANNEL, [`Spa/Interaction/${smCategory}/Duration/Ms`, Math.max((interaction.root?.end || 0) - (interaction.root?.start || 0), 0)], undefined, FEATURE_NAMES.metrics, baseEE)
|
|
758
758
|
|
|
759
759
|
scheduler?.scheduleHarvest(0)
|
|
760
|
-
if (!scheduler) warn(
|
|
760
|
+
if (!scheduler) warn(19)
|
|
761
761
|
}
|
|
762
762
|
|
|
763
763
|
function isEnabled () {
|
|
@@ -49,7 +49,8 @@ export class AggregateBase extends FeatureBase {
|
|
|
49
49
|
checkConfiguration () {
|
|
50
50
|
// NOTE: This check has to happen at aggregator load time
|
|
51
51
|
if (!isConfigured(this.agentIdentifier)) {
|
|
52
|
-
|
|
52
|
+
const cdn = gosCDN()
|
|
53
|
+
let jsAttributes = { ...cdn.info?.jsAttributes }
|
|
53
54
|
try {
|
|
54
55
|
jsAttributes = {
|
|
55
56
|
...jsAttributes,
|
|
@@ -59,9 +60,9 @@ export class AggregateBase extends FeatureBase {
|
|
|
59
60
|
// do nothing
|
|
60
61
|
}
|
|
61
62
|
configure({ agentIdentifier: this.agentIdentifier }, {
|
|
62
|
-
...
|
|
63
|
+
...cdn,
|
|
63
64
|
info: {
|
|
64
|
-
...
|
|
65
|
+
...cdn.info,
|
|
65
66
|
jsAttributes
|
|
66
67
|
},
|
|
67
68
|
runtime: getRuntime(this.agentIdentifier)
|
|
@@ -85,7 +85,7 @@ export class InstrumentBase extends FeatureBase {
|
|
|
85
85
|
session = setupAgentSession(this.agentIdentifier)
|
|
86
86
|
}
|
|
87
87
|
} catch (e) {
|
|
88
|
-
warn(
|
|
88
|
+
warn(20, e)
|
|
89
89
|
this.ee.emit('internal-error', [e])
|
|
90
90
|
if (this.featureName === FEATURE_NAMES.sessionReplay) this.abortHandler?.() // SR should stop recording if session DNE
|
|
91
91
|
}
|
|
@@ -105,7 +105,7 @@ export class InstrumentBase extends FeatureBase {
|
|
|
105
105
|
this.featAggregate = new Aggregate(this.agentIdentifier, this.aggregator, argsObjFromInstrument)
|
|
106
106
|
loadedSuccessfully(true)
|
|
107
107
|
} catch (e) {
|
|
108
|
-
warn(
|
|
108
|
+
warn(34, e)
|
|
109
109
|
this.abortHandler?.() // undo any important alterations made to the page
|
|
110
110
|
// not supported yet but nice to do: "abort" this agent's EE for this feature specifically
|
|
111
111
|
drain(this.agentIdentifier, this.featureName, true)
|
|
@@ -25,7 +25,7 @@ export class AgentBase {
|
|
|
25
25
|
* @param {...any} args
|
|
26
26
|
*/
|
|
27
27
|
#callMethod (methodName, ...args) {
|
|
28
|
-
if (typeof this.api?.[methodName] !== 'function') warn(
|
|
28
|
+
if (typeof this.api?.[methodName] !== 'function') warn(35, methodName)
|
|
29
29
|
else return this.api[methodName](...args)
|
|
30
30
|
}
|
|
31
31
|
|
package/src/loaders/agent.js
CHANGED
|
@@ -13,7 +13,6 @@ import { Instrument as PageViewEvent } from '../features/page_view_event/instrum
|
|
|
13
13
|
import { Aggregator } from '../common/aggregate/aggregator'
|
|
14
14
|
import { gosNREUM, setNREUMInitializedAgent } from '../common/window/nreum'
|
|
15
15
|
import { warn } from '../common/util/console'
|
|
16
|
-
import { stringify } from '../common/util/stringify'
|
|
17
16
|
import { globalScope } from '../common/constants/runtime'
|
|
18
17
|
|
|
19
18
|
/**
|
|
@@ -31,7 +30,7 @@ export class Agent extends AgentBase {
|
|
|
31
30
|
if (!globalScope) {
|
|
32
31
|
// We could not determine the runtime environment. Short-circuite the agent here
|
|
33
32
|
// to avoid possible exceptions later that may cause issues with customer's application.
|
|
34
|
-
warn(
|
|
33
|
+
warn(21)
|
|
35
34
|
return
|
|
36
35
|
}
|
|
37
36
|
|
|
@@ -74,12 +73,12 @@ export class Agent extends AgentBase {
|
|
|
74
73
|
|
|
75
74
|
const dependencies = getFeatureDependencyNames(InstrumentCtor.featureName)
|
|
76
75
|
const hasAllDeps = dependencies.every(featName => featName in this.features) // any other feature(s) this depends on should've been initialized on prior iterations by priority order
|
|
77
|
-
if (!hasAllDeps) warn(
|
|
76
|
+
if (!hasAllDeps) warn(36, InstrumentCtor.featureName)
|
|
78
77
|
|
|
79
78
|
this.features[InstrumentCtor.featureName] = new InstrumentCtor(this.agentIdentifier, this.sharedAggregator)
|
|
80
79
|
})
|
|
81
80
|
} catch (err) {
|
|
82
|
-
warn(
|
|
81
|
+
warn(22, err)
|
|
83
82
|
for (const featName in this.features) { // this.features hold only features that have been instantiated
|
|
84
83
|
this.features[featName].abortHandler?.()
|
|
85
84
|
}
|
package/src/loaders/api/api.js
CHANGED
|
@@ -16,8 +16,8 @@ import { apiMethods, asyncApiMethods } from './api-methods'
|
|
|
16
16
|
import { SR_EVENT_EMITTER_TYPES } from '../../features/session_replay/constants'
|
|
17
17
|
import { now } from '../../common/timing/now'
|
|
18
18
|
import { MODE } from '../../common/session/constants'
|
|
19
|
-
import {
|
|
20
|
-
import { bufferLog
|
|
19
|
+
import { LOG_LEVELS } from '../../features/logging/constants'
|
|
20
|
+
import { bufferLog } from '../../features/logging/shared/utils'
|
|
21
21
|
import { wrapLogger } from '../../common/wrap/wrap-logger'
|
|
22
22
|
|
|
23
23
|
export function setTopLevelCallers () {
|
|
@@ -29,7 +29,9 @@ export function setTopLevelCallers () {
|
|
|
29
29
|
function caller (fnName, ...args) {
|
|
30
30
|
let returnVals = []
|
|
31
31
|
Object.values(nr.initializedAgents).forEach(val => {
|
|
32
|
-
if (val
|
|
32
|
+
if (!val || !val.api) {
|
|
33
|
+
warn(38, fnName)
|
|
34
|
+
} else if (val.exposed && val.api[fnName]) {
|
|
33
35
|
returnVals.push(val.api[fnName](...args))
|
|
34
36
|
}
|
|
35
37
|
})
|
|
@@ -55,18 +57,13 @@ export function setAPI (agentIdentifier, forceDrain, runSoftNavOverSpa = false)
|
|
|
55
57
|
var spaPrefix = prefix + 'ixn-'
|
|
56
58
|
|
|
57
59
|
apiInterface.log = function (message, { customAttributes = {}, level = LOG_LEVELS.INFO } = {}) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (!isValidLogLevel(level)) return warn(LOGGING_LEVEL_FAILURE_MESSAGE + level, LOG_LEVELS)
|
|
61
|
-
if (message.length > MAX_PAYLOAD_SIZE) return warn(LOGGING_IGNORED + '> ' + MAX_PAYLOAD_SIZE + ' bytes: ', message.slice(0, 25) + '...')
|
|
62
|
-
bufferLog(instanceEE, message, customAttributes, level.toUpperCase())
|
|
60
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['API/log/called'], undefined, FEATURE_NAMES.metrics, instanceEE)
|
|
61
|
+
bufferLog(instanceEE, message, customAttributes, level)
|
|
63
62
|
}
|
|
64
63
|
|
|
65
64
|
apiInterface.wrapLogger = (parent, functionName, { customAttributes = {}, level = LOG_LEVELS.INFO } = {}) => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (!isValidLogLevel(level)) return warn(LOGGING_FAILURE_MESSAGE + LOGGING_LEVEL_FAILURE_MESSAGE + level, LOG_LEVELS)
|
|
69
|
-
wrapLogger(instanceEE, parent, functionName, { customAttributes, level: level.toUpperCase() })
|
|
65
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['API/wrapLogger/called'], undefined, FEATURE_NAMES.metrics, instanceEE)
|
|
66
|
+
wrapLogger(instanceEE, parent, functionName, { customAttributes, level })
|
|
70
67
|
}
|
|
71
68
|
|
|
72
69
|
// Setup stub functions that queue calls for later processing.
|
|
@@ -100,11 +97,11 @@ export function setAPI (agentIdentifier, forceDrain, runSoftNavOverSpa = false)
|
|
|
100
97
|
}
|
|
101
98
|
apiInterface.setCustomAttribute = function (name, value, persistAttribute = false) {
|
|
102
99
|
if (typeof name !== 'string') {
|
|
103
|
-
warn(
|
|
100
|
+
warn(39, typeof name)
|
|
104
101
|
return
|
|
105
102
|
}
|
|
106
103
|
if (!(['string', 'number', 'boolean'].includes(typeof value) || value === null)) {
|
|
107
|
-
warn(
|
|
104
|
+
warn(40, typeof value)
|
|
108
105
|
return
|
|
109
106
|
}
|
|
110
107
|
return appendJsAttribute(name, value, 'setCustomAttribute', persistAttribute)
|
|
@@ -116,7 +113,7 @@ export function setAPI (agentIdentifier, forceDrain, runSoftNavOverSpa = false)
|
|
|
116
113
|
*/
|
|
117
114
|
apiInterface.setUserId = function (value) {
|
|
118
115
|
if (!(typeof value === 'string' || value === null)) {
|
|
119
|
-
warn(
|
|
116
|
+
warn(41, typeof value)
|
|
120
117
|
return
|
|
121
118
|
}
|
|
122
119
|
return appendJsAttribute('enduser.id', value, 'setUserId', true)
|
|
@@ -129,7 +126,7 @@ export function setAPI (agentIdentifier, forceDrain, runSoftNavOverSpa = false)
|
|
|
129
126
|
*/
|
|
130
127
|
apiInterface.setApplicationVersion = function (value) {
|
|
131
128
|
if (!(typeof value === 'string' || value === null)) {
|
|
132
|
-
warn(
|
|
129
|
+
warn(42, typeof value)
|
|
133
130
|
return
|
|
134
131
|
}
|
|
135
132
|
return appendJsAttribute('application.version', value, 'setApplicationVersion', false)
|
|
@@ -140,7 +137,7 @@ export function setAPI (agentIdentifier, forceDrain, runSoftNavOverSpa = false)
|
|
|
140
137
|
handle(SUPPORTABILITY_METRIC_CHANNEL, ['API/start/called'], undefined, FEATURE_NAMES.metrics, instanceEE)
|
|
141
138
|
instanceEE.emit('manual-start-all')
|
|
142
139
|
} catch (err) {
|
|
143
|
-
warn(
|
|
140
|
+
warn(23, err)
|
|
144
141
|
}
|
|
145
142
|
}
|
|
146
143
|
|
|
@@ -215,7 +212,7 @@ export function setAPI (agentIdentifier, forceDrain, runSoftNavOverSpa = false)
|
|
|
215
212
|
setAPI(agentIdentifier)
|
|
216
213
|
drain(agentIdentifier, 'api')
|
|
217
214
|
}).catch((err) => {
|
|
218
|
-
warn(
|
|
215
|
+
warn(27, err)
|
|
219
216
|
instanceEE.abort()
|
|
220
217
|
})
|
|
221
218
|
}
|
|
@@ -61,11 +61,11 @@ export class MicroAgent extends AgentBase {
|
|
|
61
61
|
if (features === undefined) features = featNames
|
|
62
62
|
else {
|
|
63
63
|
features = Array.isArray(features) && features.length ? features : [features]
|
|
64
|
-
if (features.some(f => !featNames.includes(f))) return warn(
|
|
64
|
+
if (features.some(f => !featNames.includes(f))) return warn(37, featNames)
|
|
65
65
|
if (!features.includes(FEATURE_NAMES.pageViewEvent)) features.push(FEATURE_NAMES.pageViewEvent)
|
|
66
66
|
}
|
|
67
67
|
} catch (err) {
|
|
68
|
-
warn(
|
|
68
|
+
warn(23, err)
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
try {
|
|
@@ -75,7 +75,7 @@ export class MicroAgent extends AgentBase {
|
|
|
75
75
|
// a biproduct of doing this is that the "session manager" is automatically handled through importing this feature
|
|
76
76
|
this.features.page_view_event = new PVE(this.agentIdentifier, this.sharedAggregator)
|
|
77
77
|
} catch (err) {
|
|
78
|
-
warn(
|
|
78
|
+
warn(24, err)
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
onWindowLoad(() => {
|
|
@@ -87,13 +87,13 @@ export class MicroAgent extends AgentBase {
|
|
|
87
87
|
}).then(({ Aggregate }) => {
|
|
88
88
|
this.features[f] = new Aggregate(this.agentIdentifier, this.sharedAggregator)
|
|
89
89
|
}).catch(err =>
|
|
90
|
-
warn(
|
|
90
|
+
warn(25, err))
|
|
91
91
|
}
|
|
92
92
|
})
|
|
93
93
|
})
|
|
94
94
|
return true
|
|
95
95
|
} catch (err) {
|
|
96
|
-
warn(
|
|
96
|
+
warn(26, err)
|
|
97
97
|
return false
|
|
98
98
|
}
|
|
99
99
|
}
|