@newrelic/browser-agent 1.277.0 → 1.278.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 +7 -0
- package/dist/cjs/common/aggregate/event-aggregator.js +1 -1
- package/dist/cjs/common/config/init.js +1 -10
- package/dist/cjs/common/config/runtime.js +2 -1
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/harvest/harvester.js +255 -0
- package/dist/cjs/common/harvest/types.js +5 -21
- package/dist/cjs/features/ajax/aggregate/index.js +2 -11
- package/dist/cjs/features/generic_events/aggregate/index.js +3 -10
- package/dist/cjs/features/jserrors/aggregate/index.js +3 -14
- package/dist/cjs/features/logging/aggregate/index.js +4 -12
- package/dist/cjs/features/metrics/aggregate/index.js +7 -15
- package/dist/cjs/features/page_view_event/aggregate/index.js +46 -48
- package/dist/cjs/features/page_view_timing/aggregate/index.js +0 -9
- package/dist/cjs/features/session_replay/aggregate/index.js +21 -43
- package/dist/cjs/features/session_replay/instrument/index.js +2 -1
- package/dist/cjs/features/session_replay/shared/recorder.js +6 -6
- package/dist/cjs/features/session_trace/aggregate/index.js +9 -24
- package/dist/cjs/features/session_trace/aggregate/trace/storage.js +8 -2
- package/dist/cjs/features/soft_navigations/aggregate/index.js +4 -11
- package/dist/cjs/features/spa/aggregate/index.js +7 -10
- package/dist/cjs/features/utils/aggregate-base.js +66 -27
- package/dist/cjs/features/utils/event-buffer.js +0 -1
- package/dist/cjs/features/utils/event-store-manager.js +109 -0
- package/dist/cjs/features/utils/instrument-base.js +1 -10
- package/dist/cjs/loaders/features/features.js +16 -10
- package/dist/cjs/loaders/micro-agent.js +1 -0
- package/dist/esm/common/aggregate/event-aggregator.js +1 -1
- package/dist/esm/common/config/init.js +1 -10
- package/dist/esm/common/config/runtime.js +2 -1
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/harvest/harvester.js +249 -0
- package/dist/esm/common/harvest/types.js +5 -21
- package/dist/esm/features/ajax/aggregate/index.js +3 -12
- package/dist/esm/features/generic_events/aggregate/index.js +3 -10
- package/dist/esm/features/jserrors/aggregate/index.js +4 -15
- package/dist/esm/features/logging/aggregate/index.js +4 -12
- package/dist/esm/features/metrics/aggregate/index.js +7 -15
- package/dist/esm/features/page_view_event/aggregate/index.js +46 -48
- package/dist/esm/features/page_view_timing/aggregate/index.js +1 -10
- package/dist/esm/features/session_replay/aggregate/index.js +22 -44
- package/dist/esm/features/session_replay/instrument/index.js +2 -1
- package/dist/esm/features/session_replay/shared/recorder.js +6 -6
- package/dist/esm/features/session_trace/aggregate/index.js +9 -24
- package/dist/esm/features/session_trace/aggregate/trace/storage.js +8 -2
- package/dist/esm/features/soft_navigations/aggregate/index.js +5 -12
- package/dist/esm/features/spa/aggregate/index.js +8 -11
- package/dist/esm/features/utils/aggregate-base.js +66 -27
- package/dist/esm/features/utils/event-buffer.js +0 -1
- package/dist/esm/features/utils/event-store-manager.js +103 -0
- package/dist/esm/features/utils/instrument-base.js +1 -10
- package/dist/esm/loaders/features/features.js +15 -9
- package/dist/esm/loaders/micro-agent.js +1 -0
- package/dist/types/common/aggregate/event-aggregator.d.ts +1 -1
- package/dist/types/common/aggregate/event-aggregator.d.ts.map +1 -1
- package/dist/types/common/config/init.d.ts.map +1 -1
- package/dist/types/common/config/runtime.d.ts.map +1 -1
- package/dist/types/common/harvest/harvester.d.ts +16 -0
- package/dist/types/common/harvest/harvester.d.ts.map +1 -0
- package/dist/types/common/harvest/types.d.ts +8 -45
- package/dist/types/common/harvest/types.d.ts.map +1 -1
- package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/generic_events/aggregate/index.d.ts +0 -3
- package/dist/types/features/generic_events/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/logging/aggregate/index.d.ts +0 -3
- package/dist/types/features/logging/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/metrics/aggregate/index.d.ts +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 +6 -2
- package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts +12 -15
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
- package/dist/types/features/session_trace/aggregate/index.d.ts +0 -5
- package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_trace/aggregate/trace/storage.d.ts +8 -5
- package/dist/types/features/session_trace/aggregate/trace/storage.d.ts.map +1 -1
- package/dist/types/features/soft_navigations/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/spa/aggregate/index.d.ts +0 -1
- package/dist/types/features/spa/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/utils/aggregate-base.d.ts +12 -7
- package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
- package/dist/types/features/utils/event-buffer.d.ts +1 -2
- package/dist/types/features/utils/event-buffer.d.ts.map +1 -1
- package/dist/types/features/utils/event-store-manager.d.ts +43 -0
- package/dist/types/features/utils/event-store-manager.d.ts.map +1 -0
- package/dist/types/features/utils/instrument-base.d.ts +0 -1
- package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
- package/dist/types/loaders/features/features.d.ts +15 -12
- package/dist/types/loaders/features/features.d.ts.map +1 -1
- package/dist/types/loaders/micro-agent.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/common/aggregate/event-aggregator.js +1 -1
- package/src/common/config/init.js +9 -10
- package/src/common/config/runtime.js +2 -1
- package/src/common/harvest/__mocks__/harvester.js +6 -0
- package/src/common/harvest/harvester.js +230 -0
- package/src/common/harvest/types.js +5 -21
- package/src/features/ajax/aggregate/index.js +3 -14
- package/src/features/generic_events/aggregate/index.js +3 -13
- package/src/features/jserrors/aggregate/index.js +4 -11
- package/src/features/logging/aggregate/index.js +4 -12
- package/src/features/metrics/aggregate/index.js +5 -12
- package/src/features/page_view_event/aggregate/index.js +38 -38
- package/src/features/page_view_timing/aggregate/index.js +1 -12
- package/src/features/session_replay/aggregate/index.js +19 -42
- package/src/features/session_replay/instrument/index.js +1 -1
- package/src/features/session_replay/shared/recorder.js +6 -6
- package/src/features/session_trace/aggregate/index.js +8 -25
- package/src/features/session_trace/aggregate/trace/storage.js +5 -2
- package/src/features/soft_navigations/aggregate/index.js +4 -12
- package/src/features/spa/aggregate/index.js +8 -11
- package/src/features/utils/aggregate-base.js +59 -27
- package/src/features/utils/event-buffer.js +0 -1
- package/src/features/utils/event-store-manager.js +101 -0
- package/src/features/utils/instrument-base.js +2 -8
- package/src/loaders/features/features.js +16 -9
- package/src/loaders/micro-agent.js +1 -0
- package/dist/cjs/common/harvest/harvest-scheduler.js +0 -168
- package/dist/cjs/common/harvest/harvest.js +0 -295
- package/dist/esm/common/harvest/harvest-scheduler.js +0 -160
- package/dist/esm/common/harvest/harvest.js +0 -286
- package/dist/types/common/harvest/harvest-scheduler.d.ts +0 -50
- package/dist/types/common/harvest/harvest-scheduler.d.ts.map +0 -1
- package/dist/types/common/harvest/harvest.d.ts +0 -65
- package/dist/types/common/harvest/harvest.d.ts.map +0 -1
- package/src/common/harvest/__mocks__/harvest.js +0 -13
- package/src/common/harvest/harvest-scheduler.js +0 -166
- package/src/common/harvest/harvest.js +0 -282
|
@@ -14,32 +14,16 @@
|
|
|
14
14
|
* @property {object} body Map of values that should be sent as the body of the request.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
/**
|
|
18
|
-
* @typedef {object} FeatureHarvestCallbackOptions Options for aggregating data for harvesting.
|
|
19
|
-
* @property {boolean} options.retry Indicates if the feature should store the aggregated
|
|
20
|
-
* data in anticipation of a possible need to retry the transmission.
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* @callback FeatureHarvestCallback
|
|
25
|
-
* @param {FeatureHarvestCallbackOptions} options Options for aggregating data for harvesting.
|
|
26
|
-
* @returns {HarvestPayload} Payload of data to transmit to bam endpoint.
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
17
|
/**
|
|
30
18
|
* @typedef {object} NetworkSendSpec
|
|
31
19
|
* @property {HarvestEndpointIdentifier} endpoint The endpoint to use (jserrors, events, resources etc.)
|
|
32
20
|
* @property {HarvestPayload} payload Object representing payload.
|
|
33
|
-
* @property {object}
|
|
34
|
-
* @property {boolean}
|
|
35
|
-
* @property {boolean}
|
|
36
|
-
* @property {boolean}
|
|
37
|
-
* @property {boolean}
|
|
38
|
-
* retry the transmission.
|
|
21
|
+
* @property {object} localOpts Additional options for sending data
|
|
22
|
+
* @property {boolean} localOpts.needResponse Specify whether the caller expects a response data.
|
|
23
|
+
* @property {boolean} localOpts.isFinalHarvest Specify whether the call is a final harvest during page unload.
|
|
24
|
+
* @property {boolean} localOpts.sendEmptyBody Specify whether the call should be made even if the body is empty. Useful for rum calls.
|
|
25
|
+
* @property {boolean} localOpts.forceNoRetry Don't save the buffered data in the case of a need to retry the transmission.
|
|
39
26
|
* @property {import('../util/submit-data.js').NetworkMethods} submitMethod The network method to use {@link ../util/submit-data.js}
|
|
40
|
-
* @property {string} customUrl Override the beacon url the data is sent to; must include protocol if defined
|
|
41
|
-
* @property {boolean} raw If true, disables adding the license key to the url
|
|
42
|
-
* @property {boolean} includeBaseParams Enables the use of base query parameters in the beacon url
|
|
43
27
|
*/
|
|
44
28
|
|
|
45
29
|
/* istanbul ignore next */
|
|
@@ -5,10 +5,9 @@
|
|
|
5
5
|
import { registerHandler } from '../../../common/event-emitter/register-handler'
|
|
6
6
|
import { stringify } from '../../../common/util/stringify'
|
|
7
7
|
import { handle } from '../../../common/event-emitter/handle'
|
|
8
|
-
import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler'
|
|
9
8
|
import { setDenyList, shouldCollectEvent } from '../../../common/deny-list/deny-list'
|
|
10
9
|
import { FEATURE_NAME } from '../constants'
|
|
11
|
-
import { FEATURE_NAMES
|
|
10
|
+
import { FEATURE_NAMES } from '../../../loaders/features/features'
|
|
12
11
|
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants'
|
|
13
12
|
import { AggregateBase } from '../../utils/aggregate-base'
|
|
14
13
|
import { parseGQL } from './gql'
|
|
@@ -19,10 +18,7 @@ export class Aggregate extends AggregateBase {
|
|
|
19
18
|
|
|
20
19
|
constructor (agentRef) {
|
|
21
20
|
super(agentRef, FEATURE_NAME)
|
|
22
|
-
|
|
23
|
-
const harvestTimeSeconds = agentRef.init.ajax.harvestTimeSeconds || 10
|
|
24
21
|
setDenyList(agentRef.runtime.denyList)
|
|
25
|
-
|
|
26
22
|
this.underSpaEvents = {}
|
|
27
23
|
const classThis = this
|
|
28
24
|
|
|
@@ -43,14 +39,7 @@ export class Aggregate extends AggregateBase {
|
|
|
43
39
|
classThis.storeXhr(...arguments, this) // this switches the context back to the class instance while passing the NR context as an argument -- see "ctx" in storeXhr
|
|
44
40
|
}, this.featureName, this.ee)
|
|
45
41
|
|
|
46
|
-
this.waitForFlags(([])).then(() =>
|
|
47
|
-
const scheduler = new HarvestScheduler(FEATURE_TO_ENDPOINT[this.featureName], {
|
|
48
|
-
onFinished: (result) => this.postHarvestCleanup(result.sent && result.retry),
|
|
49
|
-
getPayload: (options) => this.makeHarvestPayload(options.retry)
|
|
50
|
-
}, this)
|
|
51
|
-
scheduler.startTimer(harvestTimeSeconds)
|
|
52
|
-
this.drain()
|
|
53
|
-
})
|
|
42
|
+
this.waitForFlags(([])).then(() => this.drain())
|
|
54
43
|
}
|
|
55
44
|
|
|
56
45
|
storeXhr (params, metrics, startTime, endTime, type, ctx) {
|
|
@@ -70,7 +59,7 @@ export class Aggregate extends AggregateBase {
|
|
|
70
59
|
|
|
71
60
|
// Report ajax timeslice metric (to be harvested by jserrors feature, but only if it's running).
|
|
72
61
|
if (jserrorsInUse && (shouldCollect || !shouldOmitAjaxMetrics)) {
|
|
73
|
-
this.agentRef.sharedAggregator.add('xhr', hash, params, metrics)
|
|
62
|
+
this.agentRef.sharedAggregator.add(['xhr', hash, params, metrics])
|
|
74
63
|
}
|
|
75
64
|
|
|
76
65
|
if (!shouldCollect) {
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { stringify } from '../../../common/util/stringify'
|
|
6
|
-
import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler'
|
|
7
6
|
import { cleanURL } from '../../../common/url/clean-url'
|
|
8
7
|
import { FEATURE_NAME, RESERVED_EVENT_TYPES } from '../constants'
|
|
9
8
|
import { globalScope, initialLocation, isBrowserScope } from '../../../common/constants/runtime'
|
|
@@ -13,7 +12,6 @@ import { now } from '../../../common/timing/now'
|
|
|
13
12
|
import { registerHandler } from '../../../common/event-emitter/register-handler'
|
|
14
13
|
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants'
|
|
15
14
|
import { applyFnToProps } from '../../../common/util/traverse'
|
|
16
|
-
import { FEATURE_TO_ENDPOINT } from '../../../loaders/features/features'
|
|
17
15
|
import { UserActionsAggregator } from './user-actions/user-actions-aggregator'
|
|
18
16
|
import { isIFrameWindow } from '../../../common/dom/iframe'
|
|
19
17
|
import { handle } from '../../../common/event-emitter/handle'
|
|
@@ -22,10 +20,7 @@ export class Aggregate extends AggregateBase {
|
|
|
22
20
|
static featureName = FEATURE_NAME
|
|
23
21
|
constructor (agentRef) {
|
|
24
22
|
super(agentRef, FEATURE_NAME)
|
|
25
|
-
|
|
26
23
|
this.eventsPerHarvest = 1000
|
|
27
|
-
this.harvestTimeSeconds = agentRef.init.generic_events.harvestTimeSeconds
|
|
28
|
-
|
|
29
24
|
this.referrerUrl = (isBrowserScope && document.referrer) ? cleanURL(document.referrer) : undefined
|
|
30
25
|
|
|
31
26
|
this.waitForFlags(['ins']).then(([ins]) => {
|
|
@@ -66,6 +61,7 @@ export class Aggregate extends AggregateBase {
|
|
|
66
61
|
let addUserAction
|
|
67
62
|
if (isBrowserScope && agentRef.init.user_actions.enabled) {
|
|
68
63
|
this.userActionAggregator = new UserActionsAggregator()
|
|
64
|
+
this.harvestOpts.beforeUnload = () => addUserAction?.(this.userActionAggregator.aggregationEvent)
|
|
69
65
|
|
|
70
66
|
addUserAction = (aggregatedUserAction) => {
|
|
71
67
|
try {
|
|
@@ -186,13 +182,7 @@ export class Aggregate extends AggregateBase {
|
|
|
186
182
|
}, this.featureName, this.ee)
|
|
187
183
|
}
|
|
188
184
|
|
|
189
|
-
|
|
190
|
-
onFinished: (result) => this.postHarvestCleanup(result.sent && result.retry),
|
|
191
|
-
onUnload: () => addUserAction?.(this.userActionAggregator.aggregationEvent)
|
|
192
|
-
}, this)
|
|
193
|
-
this.harvestScheduler.harvest.on(FEATURE_TO_ENDPOINT[this.featureName], (options) => this.makeHarvestPayload(options.retry))
|
|
194
|
-
this.harvestScheduler.startTimer(this.harvestTimeSeconds, 0)
|
|
195
|
-
|
|
185
|
+
agentRef.runtime.harvester.triggerHarvestFor(this)
|
|
196
186
|
this.drain()
|
|
197
187
|
})
|
|
198
188
|
}
|
|
@@ -246,7 +236,7 @@ export class Aggregate extends AggregateBase {
|
|
|
246
236
|
* if it fails again, we do nothing
|
|
247
237
|
*/
|
|
248
238
|
this.ee.emit(SUPPORTABILITY_METRIC_CHANNEL, ['GenericEvents/Harvest/Max/Seen'])
|
|
249
|
-
this.
|
|
239
|
+
this.agentRef.runtime.harvester.triggerHarvestFor(this)
|
|
250
240
|
this.events.add(eventAttributes)
|
|
251
241
|
}
|
|
252
242
|
}
|
|
@@ -9,13 +9,12 @@ import { stringHashCode } from './string-hash-code'
|
|
|
9
9
|
import { truncateSize } from './format-stack-trace'
|
|
10
10
|
|
|
11
11
|
import { registerHandler as register } from '../../../common/event-emitter/register-handler'
|
|
12
|
-
import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler'
|
|
13
12
|
import { stringify } from '../../../common/util/stringify'
|
|
14
13
|
import { handle } from '../../../common/event-emitter/handle'
|
|
15
14
|
import { globalScope } from '../../../common/constants/runtime'
|
|
16
15
|
|
|
17
16
|
import { FEATURE_NAME } from '../constants'
|
|
18
|
-
import { FEATURE_NAMES
|
|
17
|
+
import { FEATURE_NAMES } from '../../../loaders/features/features'
|
|
19
18
|
import { AggregateBase } from '../../utils/aggregate-base'
|
|
20
19
|
import { now } from '../../../common/timing/now'
|
|
21
20
|
import { applyFnToProps } from '../../../common/util/traverse'
|
|
@@ -45,17 +44,11 @@ export class Aggregate extends AggregateBase {
|
|
|
45
44
|
register('softNavFlush', (interactionId, wasFinished, softNavAttrs) =>
|
|
46
45
|
this.onSoftNavNotification(interactionId, wasFinished, softNavAttrs), this.featureName, this.ee) // when an ixn is done or cancelled
|
|
47
46
|
|
|
48
|
-
|
|
49
|
-
const aggregatorTypes = ['err', 'ierr', 'xhr'] // the types in EventAggregator this feature cares about
|
|
47
|
+
this.harvestOpts.aggregatorTypes = ['err', 'ierr', 'xhr'] // the types in EventAggregator this feature cares about
|
|
50
48
|
|
|
51
49
|
// 0 == off, 1 == on
|
|
52
50
|
this.waitForFlags(['err']).then(([errFlag]) => {
|
|
53
51
|
if (errFlag) {
|
|
54
|
-
const scheduler = new HarvestScheduler(FEATURE_TO_ENDPOINT[this.featureName], {
|
|
55
|
-
onFinished: (result) => this.postHarvestCleanup(result.sent && result.retry, { aggregatorTypes })
|
|
56
|
-
}, this)
|
|
57
|
-
scheduler.harvest.on(FEATURE_TO_ENDPOINT[this.featureName], (options) => this.makeHarvestPayload(options.retry, { aggregatorTypes }))
|
|
58
|
-
scheduler.startTimer(harvestTimeSeconds)
|
|
59
52
|
this.drain()
|
|
60
53
|
} else {
|
|
61
54
|
this.blocked = true // if rum response determines that customer lacks entitlements for spa endpoint, this feature shouldn't harvest
|
|
@@ -235,7 +228,7 @@ export class Aggregate extends AggregateBase {
|
|
|
235
228
|
|
|
236
229
|
const jsAttributesHash = stringHashCode(stringify(allCustomAttrs))
|
|
237
230
|
const aggregateHash = bucketHash + ':' + jsAttributesHash
|
|
238
|
-
this.events.add(type, aggregateHash, params, newMetrics, allCustomAttrs)
|
|
231
|
+
this.events.add([type, aggregateHash, params, newMetrics, allCustomAttrs])
|
|
239
232
|
|
|
240
233
|
function setCustom (key, val) {
|
|
241
234
|
allCustomAttrs[key] = (val && typeof val === 'object' ? stringify(val) : val)
|
|
@@ -265,7 +258,7 @@ export class Aggregate extends AggregateBase {
|
|
|
265
258
|
var jsAttributesHash = stringHashCode(stringify(allCustomAttrs))
|
|
266
259
|
var aggregateHash = hash + ':' + jsAttributesHash
|
|
267
260
|
|
|
268
|
-
this.events.add(item[0], aggregateHash, params, item[3], allCustomAttrs)
|
|
261
|
+
this.events.add([item[0], aggregateHash, params, item[3], allCustomAttrs])
|
|
269
262
|
|
|
270
263
|
function setCustom ([key, val]) {
|
|
271
264
|
allCustomAttrs[key] = (val && typeof val === 'object' ? stringify(val) : val)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { handle } from '../../../common/event-emitter/handle'
|
|
2
2
|
import { registerHandler } from '../../../common/event-emitter/register-handler'
|
|
3
|
-
import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler'
|
|
4
3
|
import { warn } from '../../../common/util/console'
|
|
5
4
|
import { stringify } from '../../../common/util/stringify'
|
|
6
5
|
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants'
|
|
@@ -10,26 +9,19 @@ import { Log } from '../shared/log'
|
|
|
10
9
|
import { isValidLogLevel } from '../shared/utils'
|
|
11
10
|
import { applyFnToProps } from '../../../common/util/traverse'
|
|
12
11
|
import { MAX_PAYLOAD_SIZE } from '../../../common/constants/agent-constants'
|
|
13
|
-
import { FEATURE_TO_ENDPOINT } from '../../../loaders/features/features'
|
|
14
12
|
|
|
15
13
|
export class Aggregate extends AggregateBase {
|
|
16
14
|
static featureName = FEATURE_NAME
|
|
17
15
|
constructor (agentRef) {
|
|
18
16
|
super(agentRef, FEATURE_NAME)
|
|
19
|
-
this.
|
|
17
|
+
this.harvestOpts.raw = true
|
|
20
18
|
|
|
21
19
|
this.waitForFlags([]).then(() => {
|
|
22
|
-
this.scheduler = new HarvestScheduler(FEATURE_TO_ENDPOINT[this.featureName], {
|
|
23
|
-
onFinished: (result) => this.postHarvestCleanup(result.sent && result.retry),
|
|
24
|
-
retryDelay: this.harvestTimeSeconds,
|
|
25
|
-
getPayload: (options) => this.makeHarvestPayload(options.retry),
|
|
26
|
-
raw: true
|
|
27
|
-
}, this)
|
|
28
20
|
/** emitted by instrument class (wrapped loggers) or the api methods directly */
|
|
29
21
|
registerHandler(LOGGING_EVENT_EMITTER_CHANNEL, this.handleLog.bind(this), this.featureName, this.ee)
|
|
30
22
|
this.drain()
|
|
31
23
|
/** harvest immediately once started to purge pre-load logs collected */
|
|
32
|
-
|
|
24
|
+
agentRef.runtime.harvester.triggerHarvestFor(this)
|
|
33
25
|
})
|
|
34
26
|
}
|
|
35
27
|
|
|
@@ -73,8 +65,8 @@ export class Aggregate extends AggregateBase {
|
|
|
73
65
|
}
|
|
74
66
|
|
|
75
67
|
if (this.events.wouldExceedMaxSize(logBytes)) {
|
|
76
|
-
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Logging/Harvest/Early/Seen', this.events.
|
|
77
|
-
this.
|
|
68
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Logging/Harvest/Early/Seen', this.events.byteSize() + logBytes])
|
|
69
|
+
this.agentRef.runtime.harvester.triggerHarvestFor(this) // force a harvest synchronously to try adding again
|
|
78
70
|
}
|
|
79
71
|
|
|
80
72
|
if (!this.events.add(log)) { // still failed after a harvest attempt despite not being too large would mean harvest failed with options.retry
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { registerHandler } from '../../../common/event-emitter/register-handler'
|
|
2
|
-
import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler'
|
|
3
2
|
import { FEATURE_NAME, SUPPORTABILITY_METRIC, CUSTOM_METRIC, SUPPORTABILITY_METRIC_CHANNEL, CUSTOM_METRIC_CHANNEL/*, WATCHABLE_WEB_SOCKET_EVENTS */ } from '../constants'
|
|
4
3
|
import { getFrameworks } from './framework-detection'
|
|
5
4
|
import { isFileProtocol } from '../../../common/url/protocol'
|
|
@@ -7,7 +6,6 @@ import { onDOMContentLoaded } from '../../../common/window/load'
|
|
|
7
6
|
import { windowAddEventListener } from '../../../common/event-listener/event-listener-opts'
|
|
8
7
|
import { isBrowserScope, isWorkerScope } from '../../../common/constants/runtime'
|
|
9
8
|
import { AggregateBase } from '../../utils/aggregate-base'
|
|
10
|
-
import { FEATURE_TO_ENDPOINT } from '../../../loaders/features/features'
|
|
11
9
|
import { isIFrameWindow } from '../../../common/dom/iframe'
|
|
12
10
|
// import { WEBSOCKET_TAG } from '../../../common/wrap/wrap-websocket'
|
|
13
11
|
// import { handleWebsocketEvents } from './websocket-detection'
|
|
@@ -16,14 +14,11 @@ export class Aggregate extends AggregateBase {
|
|
|
16
14
|
static featureName = FEATURE_NAME
|
|
17
15
|
constructor (agentRef) {
|
|
18
16
|
super(agentRef, FEATURE_NAME)
|
|
19
|
-
|
|
17
|
+
this.harvestOpts.aggregatorTypes = ['cm', 'sm'] // the types in EventAggregator this feature cares about
|
|
18
|
+
// This feature only harvests once per potential EoL of the page, which is handled by the central harvester.
|
|
20
19
|
|
|
21
20
|
this.waitForFlags(['err']).then(([errFlag]) => {
|
|
22
21
|
if (errFlag) {
|
|
23
|
-
// *cli, Mar 23 - Per NR-94597, this feature should only harvest ONCE at the (potential) EoL time of the page.
|
|
24
|
-
const scheduler = new HarvestScheduler(FEATURE_TO_ENDPOINT[this.featureName], { onUnload: () => this.unload() }, this)
|
|
25
|
-
// this is needed to ensure EoL is "on" and sent
|
|
26
|
-
scheduler.harvest.on(FEATURE_TO_ENDPOINT[this.featureName], () => this.makeHarvestPayload(undefined, { aggregatorTypes }))
|
|
27
22
|
this.drain()
|
|
28
23
|
} else {
|
|
29
24
|
this.blocked = true // if rum response determines that customer lacks entitlements for spa endpoint, this feature shouldn't harvest
|
|
@@ -39,6 +34,8 @@ export class Aggregate extends AggregateBase {
|
|
|
39
34
|
this.eachSessionChecks() // the start of every time user engages with page
|
|
40
35
|
}
|
|
41
36
|
|
|
37
|
+
preHarvestChecks () { return this.drained } // only allow any metrics to be sent if we know for sure it has gotten the go-ahead RUM flag
|
|
38
|
+
|
|
42
39
|
storeSupportabilityMetrics (name, value) {
|
|
43
40
|
if (this.blocked) return
|
|
44
41
|
const type = SUPPORTABILITY_METRIC
|
|
@@ -50,7 +47,7 @@ export class Aggregate extends AggregateBase {
|
|
|
50
47
|
if (this.blocked) return
|
|
51
48
|
const type = CUSTOM_METRIC
|
|
52
49
|
const params = { name }
|
|
53
|
-
this.events.add(type, name, params, metrics)
|
|
50
|
+
this.events.add([type, name, params, metrics])
|
|
54
51
|
}
|
|
55
52
|
|
|
56
53
|
singleChecks () {
|
|
@@ -132,8 +129,4 @@ export class Aggregate extends AggregateBase {
|
|
|
132
129
|
if (evt?.persisted) { this.storeSupportabilityMetrics('Generic/BFCache/PageRestored') }
|
|
133
130
|
})
|
|
134
131
|
}
|
|
135
|
-
|
|
136
|
-
unload () {
|
|
137
|
-
// do nothing for now, marks and measures and resources stats are now being captured by the ge feature
|
|
138
|
-
}
|
|
139
132
|
}
|
|
@@ -2,7 +2,6 @@ import { globalScope, isBrowserScope, originTime } from '../../../common/constan
|
|
|
2
2
|
import { addPT, addPN } from '../../../common/timing/nav-timing'
|
|
3
3
|
import { stringify } from '../../../common/util/stringify'
|
|
4
4
|
import { isValid } from '../../../common/config/info'
|
|
5
|
-
import { Harvest } from '../../../common/harvest/harvest'
|
|
6
5
|
import * as CONSTANTS from '../constants'
|
|
7
6
|
import { getActivatedFeaturesFlags } from './initialized-features'
|
|
8
7
|
import { activateFeatures } from '../../../common/util/feature-flags'
|
|
@@ -23,12 +22,12 @@ export class Aggregate extends AggregateBase {
|
|
|
23
22
|
this.timeToFirstByte = 0
|
|
24
23
|
this.firstByteToWindowLoad = 0 // our "frontend" duration
|
|
25
24
|
this.firstByteToDomContent = 0 // our "dom processing" duration
|
|
26
|
-
this.timeKeeper = new TimeKeeper(agentRef.agentIdentifier)
|
|
27
25
|
|
|
28
26
|
if (!isValid(agentRef.agentIdentifier)) {
|
|
29
27
|
this.ee.abort()
|
|
30
28
|
return warn(43)
|
|
31
29
|
}
|
|
30
|
+
agentRef.runtime.timeKeeper = new TimeKeeper(agentRef.agentIdentifier)
|
|
32
31
|
|
|
33
32
|
if (isBrowserScope) {
|
|
34
33
|
timeToFirstByte.subscribe(({ value, attrs }) => {
|
|
@@ -47,7 +46,6 @@ export class Aggregate extends AggregateBase {
|
|
|
47
46
|
|
|
48
47
|
sendRum () {
|
|
49
48
|
const info = this.agentRef.info
|
|
50
|
-
const harvester = new Harvest(this)
|
|
51
49
|
const measures = {}
|
|
52
50
|
|
|
53
51
|
if (info.queueTime) measures.qt = info.queueTime
|
|
@@ -99,43 +97,45 @@ export class Aggregate extends AggregateBase {
|
|
|
99
97
|
queryParameters.fp = firstPaint.current.value
|
|
100
98
|
queryParameters.fcp = firstContentfulPaint.current.value
|
|
101
99
|
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
const timeKeeper = this.agentRef.runtime.timeKeeper
|
|
101
|
+
if (timeKeeper?.ready) {
|
|
102
|
+
queryParameters.timestamp = Math.floor(timeKeeper.correctRelativeTimestamp(now()))
|
|
104
103
|
}
|
|
105
104
|
|
|
106
|
-
|
|
107
|
-
harvester.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (status >= 400 || status === 0) {
|
|
115
|
-
// Adding retry logic for the rum call will be a separate change
|
|
116
|
-
this.ee.abort()
|
|
117
|
-
return
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
try {
|
|
121
|
-
const { app, ...flags } = JSON.parse(responseText)
|
|
122
|
-
try {
|
|
123
|
-
this.timeKeeper.processRumRequest(xhr, rumStartTime, rumEndTime, app.nrServerTime)
|
|
124
|
-
if (!this.timeKeeper.ready) throw new Error('TimeKeeper not ready')
|
|
125
|
-
this.agentRef.runtime.timeKeeper = this.timeKeeper
|
|
126
|
-
} catch (error) {
|
|
127
|
-
this.ee.abort()
|
|
128
|
-
warn(17, error)
|
|
129
|
-
return
|
|
130
|
-
}
|
|
131
|
-
this.agentRef.runtime.appMetadata = app
|
|
132
|
-
activateFeatures(flags, this.agentIdentifier)
|
|
133
|
-
this.drain()
|
|
134
|
-
} catch (err) {
|
|
135
|
-
this.ee.abort()
|
|
136
|
-
warn(18, err)
|
|
137
|
-
}
|
|
138
|
-
}
|
|
105
|
+
this.rumStartTime = now()
|
|
106
|
+
this.agentRef.runtime.harvester.triggerHarvestFor(this, {
|
|
107
|
+
directSend: {
|
|
108
|
+
targetApp: this.agentRef.mainAppKey,
|
|
109
|
+
payload: { qs: queryParameters, body }
|
|
110
|
+
},
|
|
111
|
+
needResponse: true,
|
|
112
|
+
sendEmptyBody: true
|
|
139
113
|
})
|
|
140
114
|
}
|
|
115
|
+
|
|
116
|
+
postHarvestCleanup ({ status, responseText, xhr }) {
|
|
117
|
+
const rumEndTime = now()
|
|
118
|
+
this.blocked = true // this prevents harvester from polling this feature's event buffer (DNE) on interval; in other words, harvests will skip PVE
|
|
119
|
+
|
|
120
|
+
if (status >= 400 || status === 0) {
|
|
121
|
+
warn(18, status)
|
|
122
|
+
// Adding retry logic for the rum call will be a separate change; this.blocked will need to be changed since that prevents another triggerHarvestFor()
|
|
123
|
+
this.ee.abort()
|
|
124
|
+
return
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const { app, ...flags } = JSON.parse(responseText)
|
|
128
|
+
try {
|
|
129
|
+
this.agentRef.runtime.timeKeeper.processRumRequest(xhr, this.rumStartTime, rumEndTime, app.nrServerTime)
|
|
130
|
+
if (!this.agentRef.runtime.timeKeeper.ready) throw new Error('TimeKeeper not ready')
|
|
131
|
+
} catch (error) {
|
|
132
|
+
this.ee.abort()
|
|
133
|
+
warn(17, error)
|
|
134
|
+
return
|
|
135
|
+
}
|
|
136
|
+
this.agentRef.runtime.appMetadata = app
|
|
137
|
+
activateFeatures(flags, this.agentIdentifier)
|
|
138
|
+
this.drain()
|
|
139
|
+
this.agentRef.runtime.harvester.startTimer()
|
|
140
|
+
}
|
|
141
141
|
}
|
|
@@ -4,11 +4,10 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { nullable, numeric, getAddStringContext, addCustomAttributes } from '../../../common/serialize/bel-serializer'
|
|
7
|
-
import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler'
|
|
8
7
|
import { registerHandler } from '../../../common/event-emitter/register-handler'
|
|
9
8
|
import { handle } from '../../../common/event-emitter/handle'
|
|
10
9
|
import { FEATURE_NAME } from '../constants'
|
|
11
|
-
import { FEATURE_NAMES
|
|
10
|
+
import { FEATURE_NAMES } from '../../../loaders/features/features'
|
|
12
11
|
import { AggregateBase } from '../../utils/aggregate-base'
|
|
13
12
|
import { cumulativeLayoutShift } from '../../../common/vitals/cumulative-layout-shift'
|
|
14
13
|
import { firstContentfulPaint } from '../../../common/vitals/first-contentful-paint'
|
|
@@ -35,11 +34,7 @@ export class Aggregate extends AggregateBase {
|
|
|
35
34
|
// Add the time of _window pagehide event_ firing to the next PVT harvest == NRDB windowUnload attr:
|
|
36
35
|
registerHandler('winPagehide', msTimestamp => this.addTiming('unload', msTimestamp, null), this.featureName, this.ee)
|
|
37
36
|
|
|
38
|
-
const harvestTimeSeconds = agentRef.init.page_view_timing.harvestTimeSeconds || 30
|
|
39
|
-
|
|
40
37
|
this.waitForFlags(([])).then(() => {
|
|
41
|
-
/* It's important that CWV api, like "onLCP", is called before the **scheduler** is initialized. The reason is because they listen to the same
|
|
42
|
-
on vis change or pagehide events, and we'd want ex. onLCP to record the timing (win the race) before we try to send "final harvest". */
|
|
43
38
|
firstPaint.subscribe(this.#handleVitalMetric)
|
|
44
39
|
firstContentfulPaint.subscribe(this.#handleVitalMetric)
|
|
45
40
|
firstInputDelay.subscribe(this.#handleVitalMetric)
|
|
@@ -57,12 +52,6 @@ export class Aggregate extends AggregateBase {
|
|
|
57
52
|
this.addTiming(name, value * 1000, attrs)
|
|
58
53
|
}, true) // CLS node should only reports on vis change rather than on every change
|
|
59
54
|
|
|
60
|
-
const scheduler = new HarvestScheduler(FEATURE_TO_ENDPOINT[this.featureName], {
|
|
61
|
-
onFinished: (result) => this.postHarvestCleanup(result.sent && result.retry),
|
|
62
|
-
getPayload: (options) => this.makeHarvestPayload(options.retry)
|
|
63
|
-
}, this)
|
|
64
|
-
scheduler.startTimer(harvestTimeSeconds)
|
|
65
|
-
|
|
66
55
|
this.drain()
|
|
67
56
|
})
|
|
68
57
|
}
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { registerHandler } from '../../../common/event-emitter/register-handler'
|
|
10
|
-
import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler'
|
|
11
10
|
import { ABORT_REASONS, FEATURE_NAME, QUERY_PARAM_PADDING, RRWEB_EVENT_TYPES, SR_EVENT_EMITTER_TYPES, TRIGGERS } from '../constants'
|
|
12
11
|
import { AggregateBase } from '../../utils/aggregate-base'
|
|
13
12
|
import { sharedChannel } from '../../../common/constants/shared-channel'
|
|
@@ -16,7 +15,7 @@ import { warn } from '../../../common/util/console'
|
|
|
16
15
|
import { globalScope } from '../../../common/constants/runtime'
|
|
17
16
|
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants'
|
|
18
17
|
import { handle } from '../../../common/event-emitter/handle'
|
|
19
|
-
import { FEATURE_NAMES
|
|
18
|
+
import { FEATURE_NAMES } from '../../../loaders/features/features'
|
|
20
19
|
import { RRWEB_VERSION } from '../../../common/constants/env'
|
|
21
20
|
import { MODE, SESSION_EVENTS, SESSION_EVENT_TYPES } from '../../../common/session/constants'
|
|
22
21
|
import { stringify } from '../../../common/util/stringify'
|
|
@@ -33,8 +32,6 @@ export class Aggregate extends AggregateBase {
|
|
|
33
32
|
// pass the recorder into the aggregator
|
|
34
33
|
constructor (agentRef, args) {
|
|
35
34
|
super(agentRef, FEATURE_NAME)
|
|
36
|
-
/** The interval to harvest at. This gets overridden if the size of the payload exceeds certain thresholds */
|
|
37
|
-
this.harvestTimeSeconds = agentRef.init.session_replay.harvestTimeSeconds || 60
|
|
38
35
|
/** Set once the recorder has fully initialized after flag checks and sampling */
|
|
39
36
|
this.initialized = false
|
|
40
37
|
/** Set once the feature has been "aborted" to prevent other side-effects from continuing */
|
|
@@ -51,6 +48,7 @@ export class Aggregate extends AggregateBase {
|
|
|
51
48
|
|
|
52
49
|
this.recorder = args?.recorder
|
|
53
50
|
this.errorNoticed = args?.errorNoticed || false
|
|
51
|
+
this.harvestOpts.raw = true
|
|
54
52
|
|
|
55
53
|
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/Enabled'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
56
54
|
|
|
@@ -76,16 +74,8 @@ export class Aggregate extends AggregateBase {
|
|
|
76
74
|
this.mode = data.sessionReplay
|
|
77
75
|
})
|
|
78
76
|
|
|
79
|
-
// Bespoke logic for blobs endpoint.
|
|
80
|
-
this.scheduler = new HarvestScheduler(FEATURE_TO_ENDPOINT[this.featureName], {
|
|
81
|
-
onFinished: (result) => this.postHarvestCleanup(result),
|
|
82
|
-
retryDelay: this.harvestTimeSeconds,
|
|
83
|
-
getPayload: ({ retry, ...opts }) => this.makeHarvestPayload(retry, opts),
|
|
84
|
-
raw: true
|
|
85
|
-
}, this)
|
|
86
|
-
|
|
87
77
|
registerHandler(SR_EVENT_EMITTER_TYPES.PAUSE, () => {
|
|
88
|
-
this.forceStop(this.mode
|
|
78
|
+
this.forceStop(this.mode === MODE.FULL)
|
|
89
79
|
}, this.featureName, this.ee)
|
|
90
80
|
|
|
91
81
|
registerHandler(SR_EVENT_EMITTER_TYPES.ERROR_DURING_REPLAY, e => {
|
|
@@ -127,7 +117,7 @@ export class Aggregate extends AggregateBase {
|
|
|
127
117
|
}
|
|
128
118
|
|
|
129
119
|
replayIsActive () {
|
|
130
|
-
return Boolean(this.
|
|
120
|
+
return Boolean(this.recorder && this.mode === MODE.FULL && !this.blocked && this.entitled)
|
|
131
121
|
}
|
|
132
122
|
|
|
133
123
|
handleError (e) {
|
|
@@ -144,18 +134,15 @@ export class Aggregate extends AggregateBase {
|
|
|
144
134
|
// if the error was noticed AFTER the recorder was already imported....
|
|
145
135
|
if (this.recorder && this.initialized) {
|
|
146
136
|
if (!this.recorder.recording) this.recorder.startRecording()
|
|
147
|
-
this.scheduler.startTimer(this.harvestTimeSeconds)
|
|
148
137
|
this.syncWithSessionManager({ sessionReplayMode: this.mode })
|
|
149
138
|
} else {
|
|
150
|
-
this.initializeRecording(
|
|
139
|
+
this.initializeRecording(MODE.FULL, true)
|
|
151
140
|
}
|
|
152
141
|
}
|
|
153
142
|
|
|
154
143
|
/**
|
|
155
144
|
* Evaluate entitlements and sampling before starting feature mechanics, importing and configuring recording library, and setting storage state
|
|
156
145
|
* @param {boolean} entitlements - the true/false state of the "sr" flag from RUM response
|
|
157
|
-
* @param {boolean} errorSample - the true/false state of the error sampling decision
|
|
158
|
-
* @param {boolean} fullSample - the true/false state of the full sampling decision
|
|
159
146
|
* @param {boolean} ignoreSession - whether to force the method to ignore the session state and use just the sample flags
|
|
160
147
|
* @returns {void}
|
|
161
148
|
*/
|
|
@@ -198,20 +185,13 @@ export class Aggregate extends AggregateBase {
|
|
|
198
185
|
// If an error was noticed before the mode could be set (like in the early lifecycle of the page), immediately set to FULL mode
|
|
199
186
|
if (this.mode === MODE.ERROR && this.errorNoticed) this.mode = MODE.FULL
|
|
200
187
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
// FULL mode records AND reports from the beginning, while ERROR mode only records (but does not report).
|
|
209
|
-
// ERROR mode will do this until an error is thrown, and then switch into FULL mode.
|
|
210
|
-
// If an error happened in ERROR mode before we've gotten to this stage, it will have already set the mode to FULL
|
|
211
|
-
if (!this.scheduler.started) {
|
|
212
|
-
// We only report (harvest) in FULL mode
|
|
213
|
-
this.scheduler.startTimer(this.harvestTimeSeconds)
|
|
214
|
-
}
|
|
188
|
+
// FULL mode records AND reports from the beginning, while ERROR mode only records (but does not report).
|
|
189
|
+
// ERROR mode will do this until an error is thrown, and then switch into FULL mode.
|
|
190
|
+
// The makeHarvestPayload should ensure that no payload is returned if we're not in FULL mode...
|
|
191
|
+
|
|
192
|
+
// If theres preloaded events and we are in full mode, just harvest immediately to clear up space and for consistency
|
|
193
|
+
if (this.mode === MODE.FULL && this.recorder?.getEvents().type === 'preloaded') {
|
|
194
|
+
this.prepUtils().then(() => this.agentRef.runtime.harvester.triggerHarvestFor(this))
|
|
215
195
|
}
|
|
216
196
|
|
|
217
197
|
await this.prepUtils()
|
|
@@ -232,11 +212,13 @@ export class Aggregate extends AggregateBase {
|
|
|
232
212
|
}
|
|
233
213
|
}
|
|
234
214
|
|
|
235
|
-
makeHarvestPayload (shouldRetryOnFail
|
|
215
|
+
makeHarvestPayload (shouldRetryOnFail) {
|
|
216
|
+
if (this.mode !== MODE.FULL || this.blocked) return
|
|
236
217
|
if (!this.recorder || !this.timeKeeper?.ready || !this.recorder.hasSeenSnapshot) return
|
|
218
|
+
|
|
237
219
|
const recorderEvents = this.recorder.getEvents()
|
|
238
220
|
// get the event type and use that to trigger another harvest if needed
|
|
239
|
-
if (!recorderEvents.events.length
|
|
221
|
+
if (!recorderEvents.events.length) return
|
|
240
222
|
|
|
241
223
|
const payload = this.getHarvestContents(recorderEvents)
|
|
242
224
|
if (!payload.body.length) {
|
|
@@ -258,7 +240,6 @@ export class Aggregate extends AggregateBase {
|
|
|
258
240
|
return stringify(output)
|
|
259
241
|
}).join(',')}]`))
|
|
260
242
|
len = payload.body.length
|
|
261
|
-
this.scheduler.opts.gzip = true
|
|
262
243
|
} else {
|
|
263
244
|
payload.body = payload.body.map(({ __serialized, ...node }) => {
|
|
264
245
|
if (node.__newrelic) return node
|
|
@@ -268,7 +249,6 @@ export class Aggregate extends AggregateBase {
|
|
|
268
249
|
return output
|
|
269
250
|
})
|
|
270
251
|
len = stringify(payload.body).length
|
|
271
|
-
this.scheduler.opts.gzip = false
|
|
272
252
|
}
|
|
273
253
|
|
|
274
254
|
if (len > MAX_PAYLOAD_SIZE) {
|
|
@@ -278,8 +258,8 @@ export class Aggregate extends AggregateBase {
|
|
|
278
258
|
// TODO -- Gracefully handle the buffer for retries.
|
|
279
259
|
if (!this.agentRef.runtime.session.state.sessionReplaySentFirstChunk) this.syncWithSessionManager({ sessionReplaySentFirstChunk: true })
|
|
280
260
|
this.recorder.clearBuffer()
|
|
281
|
-
if (recorderEvents.type === 'preloaded') this.
|
|
282
|
-
return [payload]
|
|
261
|
+
if (recorderEvents.type === 'preloaded') this.agentRef.runtime.harvester.triggerHarvestFor(this)
|
|
262
|
+
return [{ targetApp: undefined, payload }] // SR doesn't need a targetApp as it only works for the main, but format needs to make AggregateBase
|
|
283
263
|
}
|
|
284
264
|
|
|
285
265
|
getCorrectedTimestamp (node) {
|
|
@@ -366,8 +346,6 @@ export class Aggregate extends AggregateBase {
|
|
|
366
346
|
if (result.status === 429) {
|
|
367
347
|
this.abort(ABORT_REASONS.TOO_MANY)
|
|
368
348
|
}
|
|
369
|
-
|
|
370
|
-
if (this.blocked) this.scheduler.stopTimer(true)
|
|
371
349
|
}
|
|
372
350
|
|
|
373
351
|
/**
|
|
@@ -376,7 +354,7 @@ export class Aggregate extends AggregateBase {
|
|
|
376
354
|
* the stopRecording API.
|
|
377
355
|
*/
|
|
378
356
|
forceStop (forceHarvest) {
|
|
379
|
-
if (forceHarvest) this.
|
|
357
|
+
if (forceHarvest) this.agentRef.runtime.harvester.triggerHarvestFor(this)
|
|
380
358
|
this.mode = MODE.OFF
|
|
381
359
|
this.recorder?.stopRecording?.()
|
|
382
360
|
this.syncWithSessionManager({ sessionReplayMode: this.mode })
|
|
@@ -391,7 +369,6 @@ export class Aggregate extends AggregateBase {
|
|
|
391
369
|
this.recorder?.stopRecording?.()
|
|
392
370
|
this.syncWithSessionManager({ sessionReplayMode: this.mode })
|
|
393
371
|
this.recorder?.clearTimestamps?.()
|
|
394
|
-
this.ee.emit('REPLAY_ABORTED')
|
|
395
372
|
while (this.recorder?.getEvents().events.length) this.recorder?.clearBuffer?.()
|
|
396
373
|
}
|
|
397
374
|
|
|
@@ -77,7 +77,7 @@ export class Instrument extends InstrumentBase {
|
|
|
77
77
|
|
|
78
78
|
// If startReplay() has been used by this point, we must record in full mode regardless of session preload:
|
|
79
79
|
// Note: recorder starts here with w/e the mode is at this time, but this may be changed later (see #apiStartOrRestartReplay else-case)
|
|
80
|
-
this.recorder ??= new Recorder({ mode: this.#mode, agentIdentifier: this.agentIdentifier, trigger, ee: this.ee })
|
|
80
|
+
this.recorder ??= new Recorder({ mode: this.#mode, agentIdentifier: this.agentIdentifier, trigger, ee: this.ee, agentRef: this.#agentRef })
|
|
81
81
|
this.recorder.startRecording()
|
|
82
82
|
this.abortHandler = this.recorder.stopRecording
|
|
83
83
|
} catch (e) {}
|