@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
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [1.278.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.277.0...v1.278.0) (2025-01-07)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* Centralized harvesting ([#1298](https://github.com/newrelic/newrelic-browser-agent/issues/1298)) ([32c0e3f](https://github.com/newrelic/newrelic-browser-agent/commit/32c0e3f7008423a3e327d17b926d1702d08ae21f))
|
|
12
|
+
|
|
6
13
|
## [1.277.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.276.0...v1.277.0) (2024-12-18)
|
|
7
14
|
|
|
8
15
|
|
|
@@ -18,7 +18,7 @@ class EventAggregator {
|
|
|
18
18
|
if (!aggregatorTypes) return Object.keys(this.#aggregator.aggregatedData).length === 0;
|
|
19
19
|
return aggregatorTypes.every(type => !this.#aggregator.aggregatedData[type]); // no bucket exist for any of the types we're looking for
|
|
20
20
|
}
|
|
21
|
-
add(type, name, params, newMetrics, customParams) {
|
|
21
|
+
add([type, name, params, newMetrics, customParams]) {
|
|
22
22
|
// Do we need to track byte size here like EventBuffer?
|
|
23
23
|
this.#aggregator.store(type, name, params, newMetrics, customParams);
|
|
24
24
|
return true;
|
|
@@ -49,7 +49,6 @@ const model = () => {
|
|
|
49
49
|
deny_list: undefined,
|
|
50
50
|
block_internal: true,
|
|
51
51
|
enabled: true,
|
|
52
|
-
harvestTimeSeconds: 10,
|
|
53
52
|
autoStart: true
|
|
54
53
|
},
|
|
55
54
|
distributed_tracing: {
|
|
@@ -67,20 +66,17 @@ const model = () => {
|
|
|
67
66
|
},
|
|
68
67
|
generic_events: {
|
|
69
68
|
enabled: true,
|
|
70
|
-
harvestTimeSeconds: 30,
|
|
71
69
|
autoStart: true
|
|
72
70
|
},
|
|
73
71
|
harvest: {
|
|
74
|
-
|
|
72
|
+
interval: 30
|
|
75
73
|
},
|
|
76
74
|
jserrors: {
|
|
77
75
|
enabled: true,
|
|
78
|
-
harvestTimeSeconds: 10,
|
|
79
76
|
autoStart: true
|
|
80
77
|
},
|
|
81
78
|
logging: {
|
|
82
79
|
enabled: true,
|
|
83
|
-
harvestTimeSeconds: 10,
|
|
84
80
|
autoStart: true,
|
|
85
81
|
level: _constants2.LOG_LEVELS.INFO
|
|
86
82
|
},
|
|
@@ -98,7 +94,6 @@ const model = () => {
|
|
|
98
94
|
},
|
|
99
95
|
page_view_timing: {
|
|
100
96
|
enabled: true,
|
|
101
|
-
harvestTimeSeconds: 30,
|
|
102
97
|
autoStart: true
|
|
103
98
|
},
|
|
104
99
|
performance: {
|
|
@@ -146,7 +141,6 @@ const model = () => {
|
|
|
146
141
|
// feature settings
|
|
147
142
|
autoStart: true,
|
|
148
143
|
enabled: false,
|
|
149
|
-
harvestTimeSeconds: 60,
|
|
150
144
|
preload: false,
|
|
151
145
|
// if true, enables the agent to load rrweb immediately instead of waiting to do so after the window.load event
|
|
152
146
|
sampling_rate: 10,
|
|
@@ -199,17 +193,14 @@ const model = () => {
|
|
|
199
193
|
},
|
|
200
194
|
session_trace: {
|
|
201
195
|
enabled: true,
|
|
202
|
-
harvestTimeSeconds: 10,
|
|
203
196
|
autoStart: true
|
|
204
197
|
},
|
|
205
198
|
soft_navigations: {
|
|
206
199
|
enabled: true,
|
|
207
|
-
harvestTimeSeconds: 10,
|
|
208
200
|
autoStart: true
|
|
209
201
|
},
|
|
210
202
|
spa: {
|
|
211
203
|
enabled: true,
|
|
212
|
-
harvestTimeSeconds: 10,
|
|
213
204
|
autoStart: true
|
|
214
205
|
},
|
|
215
206
|
ssl: undefined,
|
|
@@ -12,7 +12,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.DIST_METHOD = exports.BUILD_EN
|
|
|
12
12
|
/**
|
|
13
13
|
* Exposes the version of the agent
|
|
14
14
|
*/
|
|
15
|
-
const VERSION = exports.VERSION = "1.
|
|
15
|
+
const VERSION = exports.VERSION = "1.278.0";
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Exposes the build type of the agent
|
|
@@ -12,7 +12,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.DIST_METHOD = exports.BUILD_EN
|
|
|
12
12
|
/**
|
|
13
13
|
* Exposes the version of the agent
|
|
14
14
|
*/
|
|
15
|
-
const VERSION = exports.VERSION = "1.
|
|
15
|
+
const VERSION = exports.VERSION = "1.278.0";
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Exposes the build type of the agent
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.Harvester = void 0;
|
|
7
|
+
var _features = require("../../loaders/features/features");
|
|
8
|
+
var _env = require("../constants/env.npm");
|
|
9
|
+
var _runtime = require("../constants/runtime");
|
|
10
|
+
var _eventListenerOpts = require("../event-listener/event-listener-opts");
|
|
11
|
+
var _constants = require("../session/constants");
|
|
12
|
+
var _now = require("../timing/now");
|
|
13
|
+
var _eol = require("../unload/eol");
|
|
14
|
+
var _cleanUrl = require("../url/clean-url");
|
|
15
|
+
var _encode = require("../url/encode");
|
|
16
|
+
var _console = require("../util/console");
|
|
17
|
+
var _stringify = require("../util/stringify");
|
|
18
|
+
var _submitData = require("../util/submit-data");
|
|
19
|
+
class Harvester {
|
|
20
|
+
#started = false;
|
|
21
|
+
initializedAggregates = [];
|
|
22
|
+
constructor(agentRef) {
|
|
23
|
+
this.agentRef = agentRef;
|
|
24
|
+
(0, _eol.subscribeToEOL)(() => {
|
|
25
|
+
// do one last harvest round or check
|
|
26
|
+
this.initializedAggregates.forEach(aggregateInst => {
|
|
27
|
+
// let all features wrap up things needed to do before ANY harvest in case there's last minute cross-feature data dependencies
|
|
28
|
+
if (typeof aggregateInst.harvestOpts.beforeUnload === 'function') aggregateInst.harvestOpts.beforeUnload();
|
|
29
|
+
});
|
|
30
|
+
this.initializedAggregates.forEach(aggregateInst => this.triggerHarvestFor(aggregateInst, {
|
|
31
|
+
isFinalHarvest: true
|
|
32
|
+
}));
|
|
33
|
+
/* This callback should run in bubble phase, so that that CWV api, like "onLCP", is called before the final harvest so that emitted timings are part of last outgoing. */
|
|
34
|
+
}, false);
|
|
35
|
+
|
|
36
|
+
/* Flush all buffered data if session resets and give up retries. This should be synchronous to ensure that the correct `session` value is sent.
|
|
37
|
+
Since session-reset generates a new session ID and the ID is grabbed at send-time, any delays or retries would cause the payload to be sent under the wrong session ID. */
|
|
38
|
+
agentRef.ee.on(_constants.SESSION_EVENTS.RESET, () => this.initializedAggregates.forEach(aggregateInst => this.triggerHarvestFor(aggregateInst, {
|
|
39
|
+
forceNoRetry: true
|
|
40
|
+
})));
|
|
41
|
+
}
|
|
42
|
+
startTimer(harvestInterval = this.agentRef.init.harvest.interval) {
|
|
43
|
+
if (this.#started) return;
|
|
44
|
+
this.#started = true;
|
|
45
|
+
const onHarvestInterval = () => {
|
|
46
|
+
this.initializedAggregates.forEach(aggregateInst => this.triggerHarvestFor(aggregateInst));
|
|
47
|
+
setTimeout(onHarvestInterval, harvestInterval * 1000); // repeat in X seconds
|
|
48
|
+
};
|
|
49
|
+
setTimeout(onHarvestInterval, harvestInterval * 1000);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Given a feature (aggregate), execute a harvest on-demand.
|
|
54
|
+
* @param {object} aggregateInst
|
|
55
|
+
* @param {object} localOpts
|
|
56
|
+
* @returns {boolean} True if 1+ network call was made. Note that this does not mean or guarantee that it was successful (or that all were in the case of more than 1).
|
|
57
|
+
*/
|
|
58
|
+
triggerHarvestFor(aggregateInst, localOpts = {}) {
|
|
59
|
+
if (aggregateInst.blocked) return false;
|
|
60
|
+
const submitMethod = (0, _submitData.getSubmitMethod)(localOpts);
|
|
61
|
+
if (!submitMethod) return false;
|
|
62
|
+
const shouldRetryOnFail = !localOpts.isFinalHarvest && submitMethod === _submitData.xhr; // always retry all features harvests except for final
|
|
63
|
+
let dataToSendArr;
|
|
64
|
+
let ranSend = false;
|
|
65
|
+
if (!localOpts.directSend) {
|
|
66
|
+
// primarily used by rum call to bypass makeHarvestPayload by providing payload directly
|
|
67
|
+
dataToSendArr = aggregateInst.makeHarvestPayload(shouldRetryOnFail); // be sure the 'this' of makeHarvestPayload is the aggregate w/ access to its harvestOpts
|
|
68
|
+
if (!dataToSendArr) return false; // can be undefined if storage is empty or preharvest checks failed
|
|
69
|
+
} else dataToSendArr = [localOpts.directSend];
|
|
70
|
+
dataToSendArr.forEach(({
|
|
71
|
+
targetApp,
|
|
72
|
+
payload
|
|
73
|
+
}) => {
|
|
74
|
+
if (!payload) return;
|
|
75
|
+
send(this.agentRef, {
|
|
76
|
+
endpoint: _features.FEATURE_TO_ENDPOINT[aggregateInst.featureName],
|
|
77
|
+
targetApp,
|
|
78
|
+
payload,
|
|
79
|
+
localOpts,
|
|
80
|
+
submitMethod,
|
|
81
|
+
cbFinished,
|
|
82
|
+
raw: aggregateInst.harvestOpts.raw
|
|
83
|
+
});
|
|
84
|
+
ranSend = true;
|
|
85
|
+
});
|
|
86
|
+
return ranSend;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* This is executed immediately after harvest sends the data via XHR, or if there's nothing to send. Note that this excludes on unloading / sendBeacon.
|
|
90
|
+
* @param {Object} result - information regarding the result of the harvest attempt
|
|
91
|
+
*/
|
|
92
|
+
function cbFinished(result) {
|
|
93
|
+
if (localOpts.forceNoRetry) result.retry = false; // discard unsent data rather than re-queuing for next harvest attempt
|
|
94
|
+
aggregateInst.postHarvestCleanup(result);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* @typedef {import('./types.js').NetworkSendSpec} NetworkSendSpec
|
|
101
|
+
*/
|
|
102
|
+
exports.Harvester = Harvester;
|
|
103
|
+
const warnings = {};
|
|
104
|
+
/**
|
|
105
|
+
* Initiate a harvest call.
|
|
106
|
+
* @param {NetworkSendSpec} param0 Specification for sending data
|
|
107
|
+
* @returns {boolean} True if a network call was made. Note that this does not mean or guarantee that it was successful.
|
|
108
|
+
*/
|
|
109
|
+
function send(agentRef, {
|
|
110
|
+
endpoint,
|
|
111
|
+
targetApp,
|
|
112
|
+
payload,
|
|
113
|
+
localOpts = {},
|
|
114
|
+
submitMethod,
|
|
115
|
+
cbFinished,
|
|
116
|
+
raw
|
|
117
|
+
}) {
|
|
118
|
+
if (!agentRef.info.errorBeacon) return false;
|
|
119
|
+
let {
|
|
120
|
+
body,
|
|
121
|
+
qs
|
|
122
|
+
} = cleanPayload(payload);
|
|
123
|
+
if (Object.keys(body).length === 0 && !localOpts.sendEmptyBody) {
|
|
124
|
+
// if there's no body to send, just run onfinish stuff and return
|
|
125
|
+
if (cbFinished) cbFinished({
|
|
126
|
+
sent: false,
|
|
127
|
+
targetApp
|
|
128
|
+
});
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
const protocol = agentRef.init.ssl === false ? 'http' : 'https';
|
|
132
|
+
const perceivedBeacon = agentRef.init.proxy.beacon || agentRef.info.errorBeacon;
|
|
133
|
+
const url = raw ? "".concat(protocol, "://").concat(perceivedBeacon, "/").concat(endpoint) : "".concat(protocol, "://").concat(perceivedBeacon).concat(endpoint !== _features.RUM ? '/' + endpoint : '', "/1/").concat(targetApp.licenseKey);
|
|
134
|
+
const baseParams = !raw ? baseQueryString(agentRef, qs, endpoint, targetApp.appId) : '';
|
|
135
|
+
let payloadParams = (0, _encode.obj)(qs, agentRef.runtime.maxBytes);
|
|
136
|
+
if (baseParams === '' && payloadParams.startsWith('&')) {
|
|
137
|
+
payloadParams = payloadParams.substring(1);
|
|
138
|
+
}
|
|
139
|
+
const fullUrl = "".concat(url, "?").concat(baseParams).concat(payloadParams);
|
|
140
|
+
const gzip = !!qs?.attributes?.includes('gzip');
|
|
141
|
+
if (!gzip) {
|
|
142
|
+
if (endpoint !== _features.EVENTS) body = (0, _stringify.stringify)(body); // all features going to 'events' endpoint should already be serialized & stringified
|
|
143
|
+
// Warn--once per endpoint--if the agent tries to send large payloads
|
|
144
|
+
if (body.length > 750000 && (warnings[endpoint] = (warnings[endpoint] || 0) + 1) === 1) (0, _console.warn)(28, endpoint);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// If body is null, undefined, or an empty object or array after stringifying, send an empty string instead.
|
|
148
|
+
if (!body || body.length === 0 || body === '{}' || body === '[]') body = '';
|
|
149
|
+
const headers = [{
|
|
150
|
+
key: 'content-type',
|
|
151
|
+
value: 'text/plain'
|
|
152
|
+
}];
|
|
153
|
+
|
|
154
|
+
/* Since workers don't support sendBeacon right now, they can only use XHR method.
|
|
155
|
+
Because they still do permit synch XHR, the idea is that at final harvest time (worker is closing),
|
|
156
|
+
we just make a BLOCKING request--trivial impact--with the remaining data as a temp fill-in for sendBeacon.
|
|
157
|
+
Following the removal of img-element method. */
|
|
158
|
+
let result = submitMethod({
|
|
159
|
+
url: fullUrl,
|
|
160
|
+
body,
|
|
161
|
+
sync: localOpts.isFinalHarvest && _runtime.isWorkerScope,
|
|
162
|
+
headers
|
|
163
|
+
});
|
|
164
|
+
if (!localOpts.isFinalHarvest && cbFinished) {
|
|
165
|
+
// final harvests don't hold onto buffer data (shouldRetryOnFail is false), so cleanup isn't needed
|
|
166
|
+
if (submitMethod === _submitData.xhr) {
|
|
167
|
+
result.addEventListener('loadend', function () {
|
|
168
|
+
// `this` here in block refers to the XHR object in this scope, do not change the anon function to an arrow function
|
|
169
|
+
// status 0 refers to a local error, such as CORS or network failure, or a blocked request by the browser (e.g. adblocker)
|
|
170
|
+
const cbResult = {
|
|
171
|
+
sent: this.status !== 0,
|
|
172
|
+
status: this.status,
|
|
173
|
+
retry: shouldRetry(this.status),
|
|
174
|
+
xhr: this,
|
|
175
|
+
fullUrl,
|
|
176
|
+
targetApp
|
|
177
|
+
};
|
|
178
|
+
if (localOpts.needResponse) cbResult.responseText = this.responseText;
|
|
179
|
+
cbFinished(cbResult);
|
|
180
|
+
}, (0, _eventListenerOpts.eventListenerOpts)(false));
|
|
181
|
+
} else if (submitMethod === _submitData.xhrFetch) {
|
|
182
|
+
result.then(async function (response) {
|
|
183
|
+
const status = response.status;
|
|
184
|
+
const cbResult = {
|
|
185
|
+
sent: true,
|
|
186
|
+
status,
|
|
187
|
+
retry: shouldRetry(status),
|
|
188
|
+
fullUrl,
|
|
189
|
+
fetchResponse: response,
|
|
190
|
+
targetApp
|
|
191
|
+
};
|
|
192
|
+
if (localOpts.needResponse) cbResult.responseText = await response.text();
|
|
193
|
+
cbFinished(cbResult);
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return true;
|
|
198
|
+
function shouldRetry(status) {
|
|
199
|
+
switch (status) {
|
|
200
|
+
case 429:
|
|
201
|
+
case 408:
|
|
202
|
+
case 500:
|
|
203
|
+
case 503:
|
|
204
|
+
return true;
|
|
205
|
+
default:
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Cleans and returns a payload object containing a body and qs
|
|
213
|
+
* object with key/value pairs. KV pairs where the value is null,
|
|
214
|
+
* undefined, or an empty string are removed to save on transmission
|
|
215
|
+
* size.
|
|
216
|
+
* @param {HarvestPayload} payload Payload to be sent to the endpoint.
|
|
217
|
+
* @returns {HarvestPayload} Cleaned payload payload to be sent to the endpoint.
|
|
218
|
+
*/
|
|
219
|
+
function cleanPayload(payload = {}) {
|
|
220
|
+
const clean = input => {
|
|
221
|
+
if (typeof Uint8Array !== 'undefined' && input instanceof Uint8Array || Array.isArray(input)) return input;
|
|
222
|
+
if (typeof input === 'string') return input.length > 0 ? input : null;
|
|
223
|
+
return Object.entries(input || {}).reduce((accumulator, [key, value]) => {
|
|
224
|
+
if (typeof value === 'number' || typeof value === 'string' && value.length > 0 || typeof value === 'object' && Object.keys(value || {}).length > 0) {
|
|
225
|
+
accumulator[key] = value;
|
|
226
|
+
}
|
|
227
|
+
return accumulator;
|
|
228
|
+
}, {});
|
|
229
|
+
};
|
|
230
|
+
return {
|
|
231
|
+
body: clean(payload.body),
|
|
232
|
+
qs: clean(payload.qs)
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// The stuff that gets sent every time.
|
|
237
|
+
function baseQueryString(agentRef, qs, endpoint, applicationID) {
|
|
238
|
+
const ref = agentRef.runtime.obfuscator.obfuscateString((0, _cleanUrl.cleanURL)('' + _runtime.globalScope.location));
|
|
239
|
+
const hr = agentRef.runtime.session?.state.sessionReplayMode === 1 && endpoint !== _features.JSERRORS;
|
|
240
|
+
const qps = ['a=' + applicationID, (0, _encode.param)('sa', agentRef.info.sa ? '' + agentRef.info.sa : ''), (0, _encode.param)('v', _env.VERSION), transactionNameParam(), (0, _encode.param)('ct', agentRef.runtime.customTransaction), '&rst=' + (0, _now.now)(), '&ck=0',
|
|
241
|
+
// ck param DEPRECATED - still expected by backend
|
|
242
|
+
'&s=' + (agentRef.runtime.session?.state.value || '0'),
|
|
243
|
+
// the 0 id encaps all untrackable and default traffic
|
|
244
|
+
(0, _encode.param)('ref', ref), (0, _encode.param)('ptid', agentRef.runtime.ptid ? '' + agentRef.runtime.ptid : '')];
|
|
245
|
+
if (hr) qps.push((0, _encode.param)('hr', '1', qs));
|
|
246
|
+
return qps.join('');
|
|
247
|
+
|
|
248
|
+
// Constructs the transaction name param for the beacon URL.
|
|
249
|
+
// Prefers the obfuscated transaction name over the plain text.
|
|
250
|
+
// Falls back to making up a name.
|
|
251
|
+
function transactionNameParam() {
|
|
252
|
+
if (agentRef.info.transactionName) return (0, _encode.param)('to', agentRef.info.transactionName);
|
|
253
|
+
return (0, _encode.param)('t', agentRef.info.tNamePlain || 'Unnamed Transaction');
|
|
254
|
+
}
|
|
255
|
+
}
|
|
@@ -20,32 +20,16 @@ exports.unused = void 0;
|
|
|
20
20
|
* @property {object} body Map of values that should be sent as the body of the request.
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
-
/**
|
|
24
|
-
* @typedef {object} FeatureHarvestCallbackOptions Options for aggregating data for harvesting.
|
|
25
|
-
* @property {boolean} options.retry Indicates if the feature should store the aggregated
|
|
26
|
-
* data in anticipation of a possible need to retry the transmission.
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* @callback FeatureHarvestCallback
|
|
31
|
-
* @param {FeatureHarvestCallbackOptions} options Options for aggregating data for harvesting.
|
|
32
|
-
* @returns {HarvestPayload} Payload of data to transmit to bam endpoint.
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
23
|
/**
|
|
36
24
|
* @typedef {object} NetworkSendSpec
|
|
37
25
|
* @property {HarvestEndpointIdentifier} endpoint The endpoint to use (jserrors, events, resources etc.)
|
|
38
26
|
* @property {HarvestPayload} payload Object representing payload.
|
|
39
|
-
* @property {object}
|
|
40
|
-
* @property {boolean}
|
|
41
|
-
* @property {boolean}
|
|
42
|
-
* @property {boolean}
|
|
43
|
-
* @property {boolean}
|
|
44
|
-
* retry the transmission.
|
|
27
|
+
* @property {object} localOpts Additional options for sending data
|
|
28
|
+
* @property {boolean} localOpts.needResponse Specify whether the caller expects a response data.
|
|
29
|
+
* @property {boolean} localOpts.isFinalHarvest Specify whether the call is a final harvest during page unload.
|
|
30
|
+
* @property {boolean} localOpts.sendEmptyBody Specify whether the call should be made even if the body is empty. Useful for rum calls.
|
|
31
|
+
* @property {boolean} localOpts.forceNoRetry Don't save the buffered data in the case of a need to retry the transmission.
|
|
45
32
|
* @property {import('../util/submit-data.js').NetworkMethods} submitMethod The network method to use {@link ../util/submit-data.js}
|
|
46
|
-
* @property {string} customUrl Override the beacon url the data is sent to; must include protocol if defined
|
|
47
|
-
* @property {boolean} raw If true, disables adding the license key to the url
|
|
48
|
-
* @property {boolean} includeBaseParams Enables the use of base query parameters in the beacon url
|
|
49
33
|
*/
|
|
50
34
|
|
|
51
35
|
/* istanbul ignore next */
|
|
@@ -7,7 +7,6 @@ exports.Aggregate = void 0;
|
|
|
7
7
|
var _registerHandler = require("../../../common/event-emitter/register-handler");
|
|
8
8
|
var _stringify = require("../../../common/util/stringify");
|
|
9
9
|
var _handle = require("../../../common/event-emitter/handle");
|
|
10
|
-
var _harvestScheduler = require("../../../common/harvest/harvest-scheduler");
|
|
11
10
|
var _denyList = require("../../../common/deny-list/deny-list");
|
|
12
11
|
var _constants = require("../constants");
|
|
13
12
|
var _features = require("../../../loaders/features/features");
|
|
@@ -24,7 +23,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
24
23
|
static featureName = _constants.FEATURE_NAME;
|
|
25
24
|
constructor(agentRef) {
|
|
26
25
|
super(agentRef, _constants.FEATURE_NAME);
|
|
27
|
-
const harvestTimeSeconds = agentRef.init.ajax.harvestTimeSeconds || 10;
|
|
28
26
|
(0, _denyList.setDenyList)(agentRef.runtime.denyList);
|
|
29
27
|
this.underSpaEvents = {};
|
|
30
28
|
const classThis = this;
|
|
@@ -46,14 +44,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
46
44
|
// the EE-drain system not only switches "this" but also passes a new EventContext with info. Should consider platform refactor to another system which passes a mutable context around separately and predictably to avoid problems like this.
|
|
47
45
|
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
|
|
48
46
|
}, this.featureName, this.ee);
|
|
49
|
-
this.waitForFlags([]).then(() =>
|
|
50
|
-
const scheduler = new _harvestScheduler.HarvestScheduler(_features.FEATURE_TO_ENDPOINT[this.featureName], {
|
|
51
|
-
onFinished: result => this.postHarvestCleanup(result.sent && result.retry),
|
|
52
|
-
getPayload: options => this.makeHarvestPayload(options.retry)
|
|
53
|
-
}, this);
|
|
54
|
-
scheduler.startTimer(harvestTimeSeconds);
|
|
55
|
-
this.drain();
|
|
56
|
-
});
|
|
47
|
+
this.waitForFlags([]).then(() => this.drain());
|
|
57
48
|
}
|
|
58
49
|
storeXhr(params, metrics, startTime, endTime, type, ctx) {
|
|
59
50
|
metrics.time = startTime;
|
|
@@ -71,7 +62,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
71
62
|
|
|
72
63
|
// Report ajax timeslice metric (to be harvested by jserrors feature, but only if it's running).
|
|
73
64
|
if (jserrorsInUse && (shouldCollect || !shouldOmitAjaxMetrics)) {
|
|
74
|
-
this.agentRef.sharedAggregator.add('xhr', hash, params, metrics);
|
|
65
|
+
this.agentRef.sharedAggregator.add(['xhr', hash, params, metrics]);
|
|
75
66
|
}
|
|
76
67
|
if (!shouldCollect) {
|
|
77
68
|
if (params.hostname === this.agentRef.info.errorBeacon || this.agentRef.init.proxy?.beacon && params.hostname === this.agentRef.init.proxy.beacon) {
|
|
@@ -5,7 +5,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.Aggregate = void 0;
|
|
7
7
|
var _stringify = require("../../../common/util/stringify");
|
|
8
|
-
var _harvestScheduler = require("../../../common/harvest/harvest-scheduler");
|
|
9
8
|
var _cleanUrl = require("../../../common/url/clean-url");
|
|
10
9
|
var _constants = require("../constants");
|
|
11
10
|
var _runtime = require("../../../common/constants/runtime");
|
|
@@ -15,7 +14,6 @@ var _now = require("../../../common/timing/now");
|
|
|
15
14
|
var _registerHandler = require("../../../common/event-emitter/register-handler");
|
|
16
15
|
var _constants2 = require("../../metrics/constants");
|
|
17
16
|
var _traverse = require("../../../common/util/traverse");
|
|
18
|
-
var _features = require("../../../loaders/features/features");
|
|
19
17
|
var _userActionsAggregator = require("./user-actions/user-actions-aggregator");
|
|
20
18
|
var _iframe = require("../../../common/dom/iframe");
|
|
21
19
|
var _handle = require("../../../common/event-emitter/handle");
|
|
@@ -29,7 +27,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
29
27
|
constructor(agentRef) {
|
|
30
28
|
super(agentRef, _constants.FEATURE_NAME);
|
|
31
29
|
this.eventsPerHarvest = 1000;
|
|
32
|
-
this.harvestTimeSeconds = agentRef.init.generic_events.harvestTimeSeconds;
|
|
33
30
|
this.referrerUrl = _runtime.isBrowserScope && document.referrer ? (0, _cleanUrl.cleanURL)(document.referrer) : undefined;
|
|
34
31
|
this.waitForFlags(['ins']).then(([ins]) => {
|
|
35
32
|
if (!ins) {
|
|
@@ -65,6 +62,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
65
62
|
let addUserAction;
|
|
66
63
|
if (_runtime.isBrowserScope && agentRef.init.user_actions.enabled) {
|
|
67
64
|
this.userActionAggregator = new _userActionsAggregator.UserActionsAggregator();
|
|
65
|
+
this.harvestOpts.beforeUnload = () => addUserAction?.(this.userActionAggregator.aggregationEvent);
|
|
68
66
|
addUserAction = aggregatedUserAction => {
|
|
69
67
|
try {
|
|
70
68
|
/** The aggregator process only returns an event when it is "done" aggregating -
|
|
@@ -200,12 +198,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
200
198
|
}
|
|
201
199
|
}, this.featureName, this.ee);
|
|
202
200
|
}
|
|
203
|
-
|
|
204
|
-
onFinished: result => this.postHarvestCleanup(result.sent && result.retry),
|
|
205
|
-
onUnload: () => addUserAction?.(this.userActionAggregator.aggregationEvent)
|
|
206
|
-
}, this);
|
|
207
|
-
this.harvestScheduler.harvest.on(_features.FEATURE_TO_ENDPOINT[this.featureName], options => this.makeHarvestPayload(options.retry));
|
|
208
|
-
this.harvestScheduler.startTimer(this.harvestTimeSeconds, 0);
|
|
201
|
+
agentRef.runtime.harvester.triggerHarvestFor(this);
|
|
209
202
|
this.drain();
|
|
210
203
|
});
|
|
211
204
|
}
|
|
@@ -255,7 +248,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
255
248
|
* if it fails again, we do nothing
|
|
256
249
|
*/
|
|
257
250
|
this.ee.emit(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ['GenericEvents/Harvest/Max/Seen']);
|
|
258
|
-
this.
|
|
251
|
+
this.agentRef.runtime.harvester.triggerHarvestFor(this);
|
|
259
252
|
this.events.add(eventAttributes);
|
|
260
253
|
}
|
|
261
254
|
}
|
|
@@ -9,7 +9,6 @@ var _computeStackTrace = require("./compute-stack-trace");
|
|
|
9
9
|
var _stringHashCode = require("./string-hash-code");
|
|
10
10
|
var _formatStackTrace = require("./format-stack-trace");
|
|
11
11
|
var _registerHandler = require("../../../common/event-emitter/register-handler");
|
|
12
|
-
var _harvestScheduler = require("../../../common/harvest/harvest-scheduler");
|
|
13
12
|
var _stringify = require("../../../common/util/stringify");
|
|
14
13
|
var _handle = require("../../../common/event-emitter/handle");
|
|
15
14
|
var _runtime = require("../../../common/constants/runtime");
|
|
@@ -45,21 +44,11 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
45
44
|
(0, _registerHandler.registerHandler)('ierr', (...args) => this.storeError(...args), this.featureName, this.ee);
|
|
46
45
|
(0, _registerHandler.registerHandler)('softNavFlush', (interactionId, wasFinished, softNavAttrs) => 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.HarvestScheduler(_features.FEATURE_TO_ENDPOINT[this.featureName], {
|
|
55
|
-
onFinished: result => this.postHarvestCleanup(result.sent && result.retry, {
|
|
56
|
-
aggregatorTypes
|
|
57
|
-
})
|
|
58
|
-
}, this);
|
|
59
|
-
scheduler.harvest.on(_features.FEATURE_TO_ENDPOINT[this.featureName], options => this.makeHarvestPayload(options.retry, {
|
|
60
|
-
aggregatorTypes
|
|
61
|
-
}));
|
|
62
|
-
scheduler.startTimer(harvestTimeSeconds);
|
|
63
52
|
this.drain();
|
|
64
53
|
} else {
|
|
65
54
|
this.blocked = true; // if rum response determines that customer lacks entitlements for spa endpoint, this feature shouldn't harvest
|
|
@@ -225,7 +214,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
225
214
|
|
|
226
215
|
const jsAttributesHash = (0, _stringHashCode.stringHashCode)((0, _stringify.stringify)(allCustomAttrs));
|
|
227
216
|
const aggregateHash = bucketHash + ':' + jsAttributesHash;
|
|
228
|
-
this.events.add(type, aggregateHash, params, newMetrics, allCustomAttrs);
|
|
217
|
+
this.events.add([type, aggregateHash, params, newMetrics, allCustomAttrs]);
|
|
229
218
|
function setCustom(key, val) {
|
|
230
219
|
allCustomAttrs[key] = val && typeof val === 'object' ? (0, _stringify.stringify)(val) : val;
|
|
231
220
|
}
|
|
@@ -249,7 +238,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
249
238
|
var hash = wasSaved ? item[1] + interaction.root.attrs.id : item[1];
|
|
250
239
|
var jsAttributesHash = (0, _stringHashCode.stringHashCode)((0, _stringify.stringify)(allCustomAttrs));
|
|
251
240
|
var aggregateHash = hash + ':' + jsAttributesHash;
|
|
252
|
-
this.events.add(item[0], aggregateHash, params, item[3], allCustomAttrs);
|
|
241
|
+
this.events.add([item[0], aggregateHash, params, item[3], allCustomAttrs]);
|
|
253
242
|
function setCustom([key, val]) {
|
|
254
243
|
allCustomAttrs[key] = val && typeof val === 'object' ? (0, _stringify.stringify)(val) : val;
|
|
255
244
|
}
|
|
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.Aggregate = void 0;
|
|
7
7
|
var _handle = require("../../../common/event-emitter/handle");
|
|
8
8
|
var _registerHandler = require("../../../common/event-emitter/register-handler");
|
|
9
|
-
var _harvestScheduler = require("../../../common/harvest/harvest-scheduler");
|
|
10
9
|
var _console = require("../../../common/util/console");
|
|
11
10
|
var _stringify = require("../../../common/util/stringify");
|
|
12
11
|
var _constants = require("../../metrics/constants");
|
|
@@ -16,24 +15,17 @@ var _log = require("../shared/log");
|
|
|
16
15
|
var _utils = require("../shared/utils");
|
|
17
16
|
var _traverse = require("../../../common/util/traverse");
|
|
18
17
|
var _agentConstants = require("../../../common/constants/agent-constants");
|
|
19
|
-
var _features = require("../../../loaders/features/features");
|
|
20
18
|
class Aggregate extends _aggregateBase.AggregateBase {
|
|
21
19
|
static featureName = _constants2.FEATURE_NAME;
|
|
22
20
|
constructor(agentRef) {
|
|
23
21
|
super(agentRef, _constants2.FEATURE_NAME);
|
|
24
|
-
this.
|
|
22
|
+
this.harvestOpts.raw = true;
|
|
25
23
|
this.waitForFlags([]).then(() => {
|
|
26
|
-
this.scheduler = new _harvestScheduler.HarvestScheduler(_features.FEATURE_TO_ENDPOINT[this.featureName], {
|
|
27
|
-
onFinished: result => this.postHarvestCleanup(result.sent && result.retry),
|
|
28
|
-
retryDelay: this.harvestTimeSeconds,
|
|
29
|
-
getPayload: options => this.makeHarvestPayload(options.retry),
|
|
30
|
-
raw: true
|
|
31
|
-
}, this);
|
|
32
24
|
/** emitted by instrument class (wrapped loggers) or the api methods directly */
|
|
33
25
|
(0, _registerHandler.registerHandler)(_constants2.LOGGING_EVENT_EMITTER_CHANNEL, this.handleLog.bind(this), this.featureName, this.ee);
|
|
34
26
|
this.drain();
|
|
35
27
|
/** harvest immediately once started to purge pre-load logs collected */
|
|
36
|
-
|
|
28
|
+
agentRef.runtime.harvester.triggerHarvestFor(this);
|
|
37
29
|
});
|
|
38
30
|
}
|
|
39
31
|
handleLog(timestamp, message, attributes = {}, level = _constants2.LOG_LEVELS.INFO) {
|
|
@@ -67,8 +59,8 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
67
59
|
return;
|
|
68
60
|
}
|
|
69
61
|
if (this.events.wouldExceedMaxSize(logBytes)) {
|
|
70
|
-
(0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ['Logging/Harvest/Early/Seen', this.events.
|
|
71
|
-
this.
|
|
62
|
+
(0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ['Logging/Harvest/Early/Seen', this.events.byteSize() + logBytes]);
|
|
63
|
+
this.agentRef.runtime.harvester.triggerHarvestFor(this); // force a harvest synchronously to try adding again
|
|
72
64
|
}
|
|
73
65
|
if (!this.events.add(log)) {
|
|
74
66
|
// still failed after a harvest attempt despite not being too large would mean harvest failed with options.retry
|