@newrelic/browser-agent 1.302.0-rc.5 → 1.302.0-rc.7
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/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 +12 -9
- package/dist/cjs/common/harvest/types.js +0 -1
- package/dist/cjs/features/logging/aggregate/index.js +1 -2
- package/dist/cjs/features/page_view_event/aggregate/index.js +32 -20
- 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 +12 -9
- package/dist/esm/common/harvest/types.js +0 -1
- package/dist/esm/features/logging/aggregate/index.js +1 -2
- package/dist/esm/features/page_view_event/aggregate/index.js +32 -20
- package/dist/types/common/harvest/harvester.d.ts.map +1 -1
- package/dist/types/common/harvest/types.d.ts +0 -2
- package/dist/types/common/harvest/types.d.ts.map +1 -1
- package/dist/types/features/page_view_event/aggregate/index.d.ts +21 -3
- package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/common/harvest/harvester.js +10 -8
- package/src/common/harvest/types.js +0 -1
- package/src/features/logging/aggregate/index.js +1 -1
- package/src/features/page_view_event/aggregate/index.js +24 -13
|
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.RRWEB_PACKAGE_NAME = exports.D
|
|
|
17
17
|
/**
|
|
18
18
|
* Exposes the version of the agent
|
|
19
19
|
*/
|
|
20
|
-
const VERSION = exports.VERSION = "1.302.0-rc.
|
|
20
|
+
const VERSION = exports.VERSION = "1.302.0-rc.7";
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Exposes the build type of the agent
|
|
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.RRWEB_PACKAGE_NAME = exports.D
|
|
|
17
17
|
/**
|
|
18
18
|
* Exposes the version of the agent
|
|
19
19
|
*/
|
|
20
|
-
const VERSION = exports.VERSION = "1.302.0-rc.
|
|
20
|
+
const VERSION = exports.VERSION = "1.302.0-rc.7";
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Exposes the build type of the agent
|
|
@@ -25,8 +25,10 @@ var _globalEvent = require("../dispatch/global-event");
|
|
|
25
25
|
* SPDX-License-Identifier: Apache-2.0
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
|
-
const
|
|
29
|
-
const
|
|
28
|
+
const RETRY = 'Harvester/Retry/';
|
|
29
|
+
const RETRY_ATTEMPTED = RETRY + 'Attempted/';
|
|
30
|
+
const RETRY_FAILED = RETRY + 'Failed/';
|
|
31
|
+
const RETRY_SUCCEEDED = RETRY + 'Succeeded/';
|
|
30
32
|
class Harvester {
|
|
31
33
|
#started = false;
|
|
32
34
|
initializedAggregates = [];
|
|
@@ -70,8 +72,7 @@ class Harvester {
|
|
|
70
72
|
const submitMethod = (0, _submitData.getSubmitMethod)(localOpts);
|
|
71
73
|
if (!submitMethod) return output;
|
|
72
74
|
const shouldRetryOnFail = !localOpts.isFinalHarvest && submitMethod === _submitData.xhr; // always retry all features harvests except for final
|
|
73
|
-
output.payload =
|
|
74
|
-
|
|
75
|
+
output.payload = aggregateInst.makeHarvestPayload(shouldRetryOnFail, localOpts);
|
|
75
76
|
if (!output.payload) return output;
|
|
76
77
|
send(this.agentRef, {
|
|
77
78
|
endpoint: _features.FEATURE_TO_ENDPOINT[aggregateInst.featureName],
|
|
@@ -93,7 +94,9 @@ class Harvester {
|
|
|
93
94
|
function cbFinished(result) {
|
|
94
95
|
if (aggregateInst.harvestOpts.prevAttemptCode) {
|
|
95
96
|
// this means we just retried a harvest that last failed
|
|
96
|
-
(0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, [
|
|
97
|
+
const reportSM = message => (0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, [message], undefined, _features.FEATURE_NAMES.metrics, aggregateInst.ee);
|
|
98
|
+
reportSM(RETRY_ATTEMPTED + aggregateInst.featureName);
|
|
99
|
+
reportSM((result.retry ? RETRY_FAILED : RETRY_SUCCEEDED) + aggregateInst.harvestOpts.prevAttemptCode);
|
|
97
100
|
delete aggregateInst.harvestOpts.prevAttemptCode; // always reset last observation so we don't falsely report again next harvest
|
|
98
101
|
// In case this re-attempt failed again, that'll be handled (re-marked again) next.
|
|
99
102
|
}
|
|
@@ -183,9 +186,9 @@ function send(agentRef, {
|
|
|
183
186
|
status: this.status,
|
|
184
187
|
retry: shouldRetry(this.status),
|
|
185
188
|
fullUrl,
|
|
186
|
-
xhr: this
|
|
189
|
+
xhr: this,
|
|
190
|
+
responseText: this.responseText
|
|
187
191
|
};
|
|
188
|
-
if (localOpts.needResponse) cbResult.responseText = this.responseText;
|
|
189
192
|
cbFinished(cbResult);
|
|
190
193
|
|
|
191
194
|
/** temporary audit of consistency of harvest metadata flags */
|
|
@@ -199,9 +202,9 @@ function send(agentRef, {
|
|
|
199
202
|
status,
|
|
200
203
|
retry: shouldRetry(status),
|
|
201
204
|
fullUrl,
|
|
202
|
-
fetchResponse: response
|
|
205
|
+
fetchResponse: response,
|
|
206
|
+
responseText: await response.text()
|
|
203
207
|
};
|
|
204
|
-
if (localOpts.needResponse) cbResult.responseText = await response.text();
|
|
205
208
|
cbFinished(cbResult);
|
|
206
209
|
/** temporary audit of consistency of harvest metadata flags */
|
|
207
210
|
if (!shouldRetry(status)) trackHarvestMetadata();
|
|
@@ -30,7 +30,6 @@ exports.unused = void 0;
|
|
|
30
30
|
* @property {HarvestEndpointIdentifier} endpoint The endpoint to use (jserrors, events, resources etc.)
|
|
31
31
|
* @property {HarvestPayload} payload Object representing payload.
|
|
32
32
|
* @property {object} localOpts Additional options for sending data
|
|
33
|
-
* @property {boolean} localOpts.needResponse Specify whether the caller expects a response data.
|
|
34
33
|
* @property {boolean} localOpts.isFinalHarvest Specify whether the call is a final harvest during page unload.
|
|
35
34
|
* @property {boolean} localOpts.sendEmptyBody Specify whether the call should be made even if the body is empty. Useful for rum calls.
|
|
36
35
|
* @property {boolean} localOpts.forceNoRetry Don't save the buffered data in the case of a need to retry the transmission.
|
|
@@ -104,8 +104,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
104
104
|
common: {
|
|
105
105
|
/** Attributes in the `common` section are added to `all` logs generated in the payload */
|
|
106
106
|
attributes: {
|
|
107
|
-
...this.agentRef.info.jsAttributes,
|
|
108
|
-
// user-provided custom attributes
|
|
107
|
+
...(0, _traverse.applyFnToProps)(this.agentRef.info.jsAttributes, this.obfuscator.obfuscateString.bind(this.obfuscator), 'string'),
|
|
109
108
|
...(this.harvestEndpointVersion === 1 && {
|
|
110
109
|
'entity.guid': this.agentRef.runtime.appMetadata.agents[0].entityGuid,
|
|
111
110
|
appId: this.agentRef.info.applicationID
|
|
@@ -35,7 +35,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
35
35
|
this.timeToFirstByte = 0;
|
|
36
36
|
this.firstByteToWindowLoad = 0; // our "frontend" duration
|
|
37
37
|
this.firstByteToDomContent = 0; // our "dom processing" duration
|
|
38
|
-
|
|
38
|
+
this.retries = 0;
|
|
39
39
|
if (!(0, _info.isValid)(agentRef.info)) {
|
|
40
40
|
this.ee.abort();
|
|
41
41
|
return (0, _console.warn)(43);
|
|
@@ -63,12 +63,8 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
63
63
|
*
|
|
64
64
|
* @param {Function} cb A function to run once the RUM call has finished - Defaults to activateFeatures
|
|
65
65
|
* @param {*} customAttributes custom attributes to attach to the RUM call - Defaults to info.js
|
|
66
|
-
* @param {*} target The target to harvest to
|
|
67
66
|
*/
|
|
68
|
-
sendRum(customAttributes = this.agentRef.info.jsAttributes
|
|
69
|
-
licenseKey: this.agentRef.info.licenseKey,
|
|
70
|
-
applicationID: this.agentRef.info.applicationID
|
|
71
|
-
}) {
|
|
67
|
+
sendRum(customAttributes = this.agentRef.info.jsAttributes) {
|
|
72
68
|
const info = this.agentRef.info;
|
|
73
69
|
const measures = {};
|
|
74
70
|
if (info.queueTime) measures.qt = info.queueTime;
|
|
@@ -119,27 +115,30 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
119
115
|
}
|
|
120
116
|
queryParameters.fp = _firstPaint.firstPaint.current.value;
|
|
121
117
|
queryParameters.fcp = _firstContentfulPaint.firstContentfulPaint.current.value;
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
118
|
+
this.queryStringsBuilder = () => {
|
|
119
|
+
// this will be called by AggregateBase.makeHarvestPayload every time harvest is triggered to be qs
|
|
120
|
+
this.rumStartTime = (0, _now.now)(); // this should be reset at the beginning of each RUM call for proper timeKeeper calculation in coordination with postHarvestCleanup
|
|
121
|
+
const timeKeeper = this.agentRef.runtime.timeKeeper;
|
|
122
|
+
if (timeKeeper?.ready) {
|
|
123
|
+
queryParameters.timestamp = Math.floor(timeKeeper.correctRelativeTimestamp(this.rumStartTime));
|
|
124
|
+
}
|
|
125
|
+
return queryParameters;
|
|
126
|
+
};
|
|
127
|
+
this.events.add(body);
|
|
127
128
|
this.agentRef.runtime.harvester.triggerHarvestFor(this, {
|
|
128
|
-
directSend: {
|
|
129
|
-
target,
|
|
130
|
-
payload: {
|
|
131
|
-
qs: queryParameters,
|
|
132
|
-
body
|
|
133
|
-
}
|
|
134
|
-
},
|
|
135
|
-
needResponse: true,
|
|
136
129
|
sendEmptyBody: true
|
|
137
130
|
});
|
|
138
131
|
}
|
|
132
|
+
serializer(eventBuffer) {
|
|
133
|
+
// this is necessary because PVE sends a single item rather than an array; in the case of undefined, this prevents sending [null] as body
|
|
134
|
+
return eventBuffer[0];
|
|
135
|
+
}
|
|
139
136
|
postHarvestCleanup({
|
|
137
|
+
sent,
|
|
140
138
|
status,
|
|
141
139
|
responseText,
|
|
142
|
-
xhr
|
|
140
|
+
xhr,
|
|
141
|
+
retry
|
|
143
142
|
}) {
|
|
144
143
|
const rumEndTime = (0, _now.now)();
|
|
145
144
|
let app, flags;
|
|
@@ -152,8 +151,20 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
152
151
|
// wont set entity stuff here, if main agent will later abort, if registered agent, nothing will happen
|
|
153
152
|
(0, _console.warn)(53, error);
|
|
154
153
|
}
|
|
154
|
+
super.postHarvestCleanup({
|
|
155
|
+
sent,
|
|
156
|
+
retry
|
|
157
|
+
}); // this will set isRetrying & re-buffer the body if request is to be retried
|
|
158
|
+
if (this.isRetrying && this.retries++ < 1) {
|
|
159
|
+
// Only retry once
|
|
160
|
+
setTimeout(() => this.agentRef.runtime.harvester.triggerHarvestFor(this, {
|
|
161
|
+
sendEmptyBody: true
|
|
162
|
+
}), 5000); // Retry sending the RUM event after 5 seconds
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
155
165
|
if (status >= 400 || status === 0) {
|
|
156
166
|
(0, _console.warn)(18, status);
|
|
167
|
+
this.blocked = true;
|
|
157
168
|
|
|
158
169
|
// Get estimated payload size of our backlog
|
|
159
170
|
const textEncoder = new TextEncoder();
|
|
@@ -217,6 +228,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
217
228
|
}
|
|
218
229
|
} catch (error) {
|
|
219
230
|
this.ee.abort();
|
|
231
|
+
this.blocked = true;
|
|
220
232
|
(0, _console.warn)(17, error);
|
|
221
233
|
return;
|
|
222
234
|
}
|
|
@@ -17,8 +17,10 @@ import { stringify } from '../util/stringify';
|
|
|
17
17
|
import { getSubmitMethod, xhr as xhrMethod, xhrFetch as fetchMethod } from '../util/submit-data';
|
|
18
18
|
import { activatedFeatures } from '../util/feature-flags';
|
|
19
19
|
import { dispatchGlobalEvent } from '../dispatch/global-event';
|
|
20
|
-
const
|
|
21
|
-
const
|
|
20
|
+
const RETRY = 'Harvester/Retry/';
|
|
21
|
+
const RETRY_ATTEMPTED = RETRY + 'Attempted/';
|
|
22
|
+
const RETRY_FAILED = RETRY + 'Failed/';
|
|
23
|
+
const RETRY_SUCCEEDED = RETRY + 'Succeeded/';
|
|
22
24
|
export class Harvester {
|
|
23
25
|
#started = false;
|
|
24
26
|
initializedAggregates = [];
|
|
@@ -62,8 +64,7 @@ export class Harvester {
|
|
|
62
64
|
const submitMethod = getSubmitMethod(localOpts);
|
|
63
65
|
if (!submitMethod) return output;
|
|
64
66
|
const shouldRetryOnFail = !localOpts.isFinalHarvest && submitMethod === xhrMethod; // always retry all features harvests except for final
|
|
65
|
-
output.payload =
|
|
66
|
-
|
|
67
|
+
output.payload = aggregateInst.makeHarvestPayload(shouldRetryOnFail, localOpts);
|
|
67
68
|
if (!output.payload) return output;
|
|
68
69
|
send(this.agentRef, {
|
|
69
70
|
endpoint: FEATURE_TO_ENDPOINT[aggregateInst.featureName],
|
|
@@ -85,7 +86,9 @@ export class Harvester {
|
|
|
85
86
|
function cbFinished(result) {
|
|
86
87
|
if (aggregateInst.harvestOpts.prevAttemptCode) {
|
|
87
88
|
// this means we just retried a harvest that last failed
|
|
88
|
-
handle(SUPPORTABILITY_METRIC_CHANNEL, [
|
|
89
|
+
const reportSM = message => handle(SUPPORTABILITY_METRIC_CHANNEL, [message], undefined, FEATURE_NAMES.metrics, aggregateInst.ee);
|
|
90
|
+
reportSM(RETRY_ATTEMPTED + aggregateInst.featureName);
|
|
91
|
+
reportSM((result.retry ? RETRY_FAILED : RETRY_SUCCEEDED) + aggregateInst.harvestOpts.prevAttemptCode);
|
|
89
92
|
delete aggregateInst.harvestOpts.prevAttemptCode; // always reset last observation so we don't falsely report again next harvest
|
|
90
93
|
// In case this re-attempt failed again, that'll be handled (re-marked again) next.
|
|
91
94
|
}
|
|
@@ -175,9 +178,9 @@ export function send(agentRef, {
|
|
|
175
178
|
status: this.status,
|
|
176
179
|
retry: shouldRetry(this.status),
|
|
177
180
|
fullUrl,
|
|
178
|
-
xhr: this
|
|
181
|
+
xhr: this,
|
|
182
|
+
responseText: this.responseText
|
|
179
183
|
};
|
|
180
|
-
if (localOpts.needResponse) cbResult.responseText = this.responseText;
|
|
181
184
|
cbFinished(cbResult);
|
|
182
185
|
|
|
183
186
|
/** temporary audit of consistency of harvest metadata flags */
|
|
@@ -191,9 +194,9 @@ export function send(agentRef, {
|
|
|
191
194
|
status,
|
|
192
195
|
retry: shouldRetry(status),
|
|
193
196
|
fullUrl,
|
|
194
|
-
fetchResponse: response
|
|
197
|
+
fetchResponse: response,
|
|
198
|
+
responseText: await response.text()
|
|
195
199
|
};
|
|
196
|
-
if (localOpts.needResponse) cbResult.responseText = await response.text();
|
|
197
200
|
cbFinished(cbResult);
|
|
198
201
|
/** temporary audit of consistency of harvest metadata flags */
|
|
199
202
|
if (!shouldRetry(status)) trackHarvestMetadata();
|
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
* @property {HarvestEndpointIdentifier} endpoint The endpoint to use (jserrors, events, resources etc.)
|
|
25
25
|
* @property {HarvestPayload} payload Object representing payload.
|
|
26
26
|
* @property {object} localOpts Additional options for sending data
|
|
27
|
-
* @property {boolean} localOpts.needResponse Specify whether the caller expects a response data.
|
|
28
27
|
* @property {boolean} localOpts.isFinalHarvest Specify whether the call is a final harvest during page unload.
|
|
29
28
|
* @property {boolean} localOpts.sendEmptyBody Specify whether the call should be made even if the body is empty. Useful for rum calls.
|
|
30
29
|
* @property {boolean} localOpts.forceNoRetry Don't save the buffered data in the case of a need to retry the transmission.
|
|
@@ -97,8 +97,7 @@ export class Aggregate extends AggregateBase {
|
|
|
97
97
|
common: {
|
|
98
98
|
/** Attributes in the `common` section are added to `all` logs generated in the payload */
|
|
99
99
|
attributes: {
|
|
100
|
-
...this.agentRef.info.jsAttributes,
|
|
101
|
-
// user-provided custom attributes
|
|
100
|
+
...applyFnToProps(this.agentRef.info.jsAttributes, this.obfuscator.obfuscateString.bind(this.obfuscator), 'string'),
|
|
102
101
|
...(this.harvestEndpointVersion === 1 && {
|
|
103
102
|
'entity.guid': this.agentRef.runtime.appMetadata.agents[0].entityGuid,
|
|
104
103
|
appId: this.agentRef.info.applicationID
|
|
@@ -27,7 +27,7 @@ export class Aggregate extends AggregateBase {
|
|
|
27
27
|
this.timeToFirstByte = 0;
|
|
28
28
|
this.firstByteToWindowLoad = 0; // our "frontend" duration
|
|
29
29
|
this.firstByteToDomContent = 0; // our "dom processing" duration
|
|
30
|
-
|
|
30
|
+
this.retries = 0;
|
|
31
31
|
if (!isValid(agentRef.info)) {
|
|
32
32
|
this.ee.abort();
|
|
33
33
|
return warn(43);
|
|
@@ -55,12 +55,8 @@ export class Aggregate extends AggregateBase {
|
|
|
55
55
|
*
|
|
56
56
|
* @param {Function} cb A function to run once the RUM call has finished - Defaults to activateFeatures
|
|
57
57
|
* @param {*} customAttributes custom attributes to attach to the RUM call - Defaults to info.js
|
|
58
|
-
* @param {*} target The target to harvest to
|
|
59
58
|
*/
|
|
60
|
-
sendRum(customAttributes = this.agentRef.info.jsAttributes
|
|
61
|
-
licenseKey: this.agentRef.info.licenseKey,
|
|
62
|
-
applicationID: this.agentRef.info.applicationID
|
|
63
|
-
}) {
|
|
59
|
+
sendRum(customAttributes = this.agentRef.info.jsAttributes) {
|
|
64
60
|
const info = this.agentRef.info;
|
|
65
61
|
const measures = {};
|
|
66
62
|
if (info.queueTime) measures.qt = info.queueTime;
|
|
@@ -111,27 +107,30 @@ export class Aggregate extends AggregateBase {
|
|
|
111
107
|
}
|
|
112
108
|
queryParameters.fp = firstPaint.current.value;
|
|
113
109
|
queryParameters.fcp = firstContentfulPaint.current.value;
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
110
|
+
this.queryStringsBuilder = () => {
|
|
111
|
+
// this will be called by AggregateBase.makeHarvestPayload every time harvest is triggered to be qs
|
|
112
|
+
this.rumStartTime = now(); // this should be reset at the beginning of each RUM call for proper timeKeeper calculation in coordination with postHarvestCleanup
|
|
113
|
+
const timeKeeper = this.agentRef.runtime.timeKeeper;
|
|
114
|
+
if (timeKeeper?.ready) {
|
|
115
|
+
queryParameters.timestamp = Math.floor(timeKeeper.correctRelativeTimestamp(this.rumStartTime));
|
|
116
|
+
}
|
|
117
|
+
return queryParameters;
|
|
118
|
+
};
|
|
119
|
+
this.events.add(body);
|
|
119
120
|
this.agentRef.runtime.harvester.triggerHarvestFor(this, {
|
|
120
|
-
directSend: {
|
|
121
|
-
target,
|
|
122
|
-
payload: {
|
|
123
|
-
qs: queryParameters,
|
|
124
|
-
body
|
|
125
|
-
}
|
|
126
|
-
},
|
|
127
|
-
needResponse: true,
|
|
128
121
|
sendEmptyBody: true
|
|
129
122
|
});
|
|
130
123
|
}
|
|
124
|
+
serializer(eventBuffer) {
|
|
125
|
+
// this is necessary because PVE sends a single item rather than an array; in the case of undefined, this prevents sending [null] as body
|
|
126
|
+
return eventBuffer[0];
|
|
127
|
+
}
|
|
131
128
|
postHarvestCleanup({
|
|
129
|
+
sent,
|
|
132
130
|
status,
|
|
133
131
|
responseText,
|
|
134
|
-
xhr
|
|
132
|
+
xhr,
|
|
133
|
+
retry
|
|
135
134
|
}) {
|
|
136
135
|
const rumEndTime = now();
|
|
137
136
|
let app, flags;
|
|
@@ -144,8 +143,20 @@ export class Aggregate extends AggregateBase {
|
|
|
144
143
|
// wont set entity stuff here, if main agent will later abort, if registered agent, nothing will happen
|
|
145
144
|
warn(53, error);
|
|
146
145
|
}
|
|
146
|
+
super.postHarvestCleanup({
|
|
147
|
+
sent,
|
|
148
|
+
retry
|
|
149
|
+
}); // this will set isRetrying & re-buffer the body if request is to be retried
|
|
150
|
+
if (this.isRetrying && this.retries++ < 1) {
|
|
151
|
+
// Only retry once
|
|
152
|
+
setTimeout(() => this.agentRef.runtime.harvester.triggerHarvestFor(this, {
|
|
153
|
+
sendEmptyBody: true
|
|
154
|
+
}), 5000); // Retry sending the RUM event after 5 seconds
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
147
157
|
if (status >= 400 || status === 0) {
|
|
148
158
|
warn(18, status);
|
|
159
|
+
this.blocked = true;
|
|
149
160
|
|
|
150
161
|
// Get estimated payload size of our backlog
|
|
151
162
|
const textEncoder = new TextEncoder();
|
|
@@ -209,6 +220,7 @@ export class Aggregate extends AggregateBase {
|
|
|
209
220
|
}
|
|
210
221
|
} catch (error) {
|
|
211
222
|
this.ee.abort();
|
|
223
|
+
this.blocked = true;
|
|
212
224
|
warn(17, error);
|
|
213
225
|
return;
|
|
214
226
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"harvester.d.ts","sourceRoot":"","sources":["../../../../src/common/harvest/harvester.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"harvester.d.ts","sourceRoot":"","sources":["../../../../src/common/harvest/harvester.js"],"names":[],"mappings":"AA6GA;;;;IAII;AACJ;;;;;;;;;IAFc,OAAO,CAuHpB;AA9MD;IAIE,2BAUC;IAZD,6BAA0B;IAGxB,cAAwB;IAW1B,wCASC;IAED;;;;;OAKG;IACH,iCAJW,MAAM,cACN,MAAM,GACJ,OAAO,CA6CnB;;CACF;8BAGY,OAAO,YAAY,EAAE,eAAe"}
|
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
* @property {HarvestEndpointIdentifier} endpoint The endpoint to use (jserrors, events, resources etc.)
|
|
21
21
|
* @property {HarvestPayload} payload Object representing payload.
|
|
22
22
|
* @property {object} localOpts Additional options for sending data
|
|
23
|
-
* @property {boolean} localOpts.needResponse Specify whether the caller expects a response data.
|
|
24
23
|
* @property {boolean} localOpts.isFinalHarvest Specify whether the call is a final harvest during page unload.
|
|
25
24
|
* @property {boolean} localOpts.sendEmptyBody Specify whether the call should be made even if the body is empty. Useful for rum calls.
|
|
26
25
|
* @property {boolean} localOpts.forceNoRetry Don't save the buffered data in the case of a need to retry the transmission.
|
|
@@ -51,7 +50,6 @@ export type NetworkSendSpec = {
|
|
|
51
50
|
* Additional options for sending data
|
|
52
51
|
*/
|
|
53
52
|
localOpts: {
|
|
54
|
-
needResponse: boolean;
|
|
55
53
|
isFinalHarvest: boolean;
|
|
56
54
|
sendEmptyBody: boolean;
|
|
57
55
|
forceNoRetry: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/common/harvest/types.js"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;GAIG;AAEH;;GAEG;AAEH;;;;GAIG;AAEH
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/common/harvest/types.js"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;GAIG;AAEH;;GAEG;AAEH;;;;GAIG;AAEH;;;;;;;;;GASG;AAEH,wBAAwB;wCApBX,KAAK,GAAC,UAAU,GAAC,QAAQ,GAAC,KAAK,GAAC,WAAW,GAAC,MAAM;;;;;QAKjD,MAAM;;;;UACN,MAAM;;;;;;cAKN,yBAAyB;;;;aACzB,cAAc;;;;eAEzB;QAA8B,cAAc,EAAjC,OAAO;QACY,aAAa,EAAhC,OAAO;QACY,YAAY,EAA/B,OAAO;KAClB;;;;kBAAW,OAAO,wBAAwB,EAAE,cAAc"}
|
|
@@ -4,18 +4,36 @@ export class Aggregate extends AggregateBase {
|
|
|
4
4
|
timeToFirstByte: number;
|
|
5
5
|
firstByteToWindowLoad: number;
|
|
6
6
|
firstByteToDomContent: number;
|
|
7
|
+
retries: number;
|
|
7
8
|
/**
|
|
8
9
|
*
|
|
9
10
|
* @param {Function} cb A function to run once the RUM call has finished - Defaults to activateFeatures
|
|
10
11
|
* @param {*} customAttributes custom attributes to attach to the RUM call - Defaults to info.js
|
|
11
|
-
* @param {*} target The target to harvest to
|
|
12
12
|
*/
|
|
13
|
-
sendRum(customAttributes?: any
|
|
13
|
+
sendRum(customAttributes?: any): void;
|
|
14
|
+
queryStringsBuilder: (() => {
|
|
15
|
+
xx: any;
|
|
16
|
+
ua: any;
|
|
17
|
+
at: any;
|
|
18
|
+
qt: any;
|
|
19
|
+
ap: any;
|
|
20
|
+
be: number;
|
|
21
|
+
fe: number;
|
|
22
|
+
dc: number;
|
|
23
|
+
tt: any;
|
|
24
|
+
us: any;
|
|
25
|
+
ac: any;
|
|
26
|
+
pr: any;
|
|
27
|
+
af: string;
|
|
28
|
+
}) | undefined;
|
|
14
29
|
rumStartTime: number | undefined;
|
|
15
|
-
|
|
30
|
+
serializer(eventBuffer: any): any;
|
|
31
|
+
postHarvestCleanup({ sent, status, responseText, xhr, retry }: {
|
|
32
|
+
sent: any;
|
|
16
33
|
status: any;
|
|
17
34
|
responseText: any;
|
|
18
35
|
xhr: any;
|
|
36
|
+
retry: any;
|
|
19
37
|
}): void;
|
|
20
38
|
}
|
|
21
39
|
import { AggregateBase } from '../../utils/aggregate-base';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/page_view_event/aggregate/index.js"],"names":[],"mappings":"AAuBA;IACE,2BAA2C;IAC3C,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/page_view_event/aggregate/index.js"],"names":[],"mappings":"AAuBA;IACE,2BAA2C;IAC3C,2BA2BC;IAxBC,wBAAwB;IACxB,8BAA8B;IAC9B,8BAA8B;IAC9B,gBAAgB;IAuBlB;;;;OAIG;IACH,2BAFW,GAAC,QAoEX;IAbC;;;;;;;;;;;;;;mBAOC;IANC,iCAAyB;IAc7B,kCAEC;IAED;;;;;;aAiGC;CACF;8BAzN6B,4BAA4B"}
|
package/package.json
CHANGED
|
@@ -18,8 +18,10 @@ import { getSubmitMethod, xhr as xhrMethod, xhrFetch as fetchMethod } from '../u
|
|
|
18
18
|
import { activatedFeatures } from '../util/feature-flags'
|
|
19
19
|
import { dispatchGlobalEvent } from '../dispatch/global-event'
|
|
20
20
|
|
|
21
|
-
const
|
|
22
|
-
const
|
|
21
|
+
const RETRY = 'Harvester/Retry/'
|
|
22
|
+
const RETRY_ATTEMPTED = RETRY + 'Attempted/'
|
|
23
|
+
const RETRY_FAILED = RETRY + 'Failed/'
|
|
24
|
+
const RETRY_SUCCEEDED = RETRY + 'Succeeded/'
|
|
23
25
|
|
|
24
26
|
export class Harvester {
|
|
25
27
|
#started = false
|
|
@@ -62,7 +64,7 @@ export class Harvester {
|
|
|
62
64
|
if (!submitMethod) return output
|
|
63
65
|
|
|
64
66
|
const shouldRetryOnFail = !localOpts.isFinalHarvest && submitMethod === xhrMethod // always retry all features harvests except for final
|
|
65
|
-
output.payload =
|
|
67
|
+
output.payload = aggregateInst.makeHarvestPayload(shouldRetryOnFail, localOpts)
|
|
66
68
|
|
|
67
69
|
if (!output.payload) return output
|
|
68
70
|
|
|
@@ -86,7 +88,9 @@ export class Harvester {
|
|
|
86
88
|
*/
|
|
87
89
|
function cbFinished (result) {
|
|
88
90
|
if (aggregateInst.harvestOpts.prevAttemptCode) { // this means we just retried a harvest that last failed
|
|
89
|
-
handle(SUPPORTABILITY_METRIC_CHANNEL, [
|
|
91
|
+
const reportSM = (message) => handle(SUPPORTABILITY_METRIC_CHANNEL, [message], undefined, FEATURE_NAMES.metrics, aggregateInst.ee)
|
|
92
|
+
reportSM(RETRY_ATTEMPTED + aggregateInst.featureName)
|
|
93
|
+
reportSM((result.retry ? RETRY_FAILED : RETRY_SUCCEEDED) + aggregateInst.harvestOpts.prevAttemptCode)
|
|
90
94
|
delete aggregateInst.harvestOpts.prevAttemptCode // always reset last observation so we don't falsely report again next harvest
|
|
91
95
|
// In case this re-attempt failed again, that'll be handled (re-marked again) next.
|
|
92
96
|
}
|
|
@@ -155,8 +159,7 @@ export function send (agentRef, { endpoint, payload, localOpts = {}, submitMetho
|
|
|
155
159
|
result.addEventListener('loadend', function () {
|
|
156
160
|
// `this` here in block refers to the XHR object in this scope, do not change the anon function to an arrow function
|
|
157
161
|
// status 0 refers to a local error, such as CORS or network failure, or a blocked request by the browser (e.g. adblocker)
|
|
158
|
-
const cbResult = { sent: this.status !== 0, status: this.status, retry: shouldRetry(this.status), fullUrl, xhr: this }
|
|
159
|
-
if (localOpts.needResponse) cbResult.responseText = this.responseText
|
|
162
|
+
const cbResult = { sent: this.status !== 0, status: this.status, retry: shouldRetry(this.status), fullUrl, xhr: this, responseText: this.responseText }
|
|
160
163
|
cbFinished(cbResult)
|
|
161
164
|
|
|
162
165
|
/** temporary audit of consistency of harvest metadata flags */
|
|
@@ -165,8 +168,7 @@ export function send (agentRef, { endpoint, payload, localOpts = {}, submitMetho
|
|
|
165
168
|
} else if (submitMethod === fetchMethod) {
|
|
166
169
|
result.then(async function (response) {
|
|
167
170
|
const status = response.status
|
|
168
|
-
const cbResult = { sent: true, status, retry: shouldRetry(status), fullUrl, fetchResponse: response }
|
|
169
|
-
if (localOpts.needResponse) cbResult.responseText = await response.text()
|
|
171
|
+
const cbResult = { sent: true, status, retry: shouldRetry(status), fullUrl, fetchResponse: response, responseText: await response.text() }
|
|
170
172
|
cbFinished(cbResult)
|
|
171
173
|
/** temporary audit of consistency of harvest metadata flags */
|
|
172
174
|
if (!shouldRetry(status)) trackHarvestMetadata()
|
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
* @property {HarvestEndpointIdentifier} endpoint The endpoint to use (jserrors, events, resources etc.)
|
|
25
25
|
* @property {HarvestPayload} payload Object representing payload.
|
|
26
26
|
* @property {object} localOpts Additional options for sending data
|
|
27
|
-
* @property {boolean} localOpts.needResponse Specify whether the caller expects a response data.
|
|
28
27
|
* @property {boolean} localOpts.isFinalHarvest Specify whether the call is a final harvest during page unload.
|
|
29
28
|
* @property {boolean} localOpts.sendEmptyBody Specify whether the call should be made even if the body is empty. Useful for rum calls.
|
|
30
29
|
* @property {boolean} localOpts.forceNoRetry Don't save the buffered data in the case of a need to retry the transmission.
|
|
@@ -116,7 +116,7 @@ export class Aggregate extends AggregateBase {
|
|
|
116
116
|
common: {
|
|
117
117
|
/** Attributes in the `common` section are added to `all` logs generated in the payload */
|
|
118
118
|
attributes: {
|
|
119
|
-
...this.agentRef.info.jsAttributes,
|
|
119
|
+
...(applyFnToProps(this.agentRef.info.jsAttributes, this.obfuscator.obfuscateString.bind(this.obfuscator), 'string')),
|
|
120
120
|
...(this.harvestEndpointVersion === 1 && {
|
|
121
121
|
'entity.guid': this.agentRef.runtime.appMetadata.agents[0].entityGuid,
|
|
122
122
|
appId: this.agentRef.info.applicationID
|
|
@@ -29,6 +29,7 @@ export class Aggregate extends AggregateBase {
|
|
|
29
29
|
this.timeToFirstByte = 0
|
|
30
30
|
this.firstByteToWindowLoad = 0 // our "frontend" duration
|
|
31
31
|
this.firstByteToDomContent = 0 // our "dom processing" duration
|
|
32
|
+
this.retries = 0
|
|
32
33
|
|
|
33
34
|
if (!isValid(agentRef.info)) {
|
|
34
35
|
this.ee.abort()
|
|
@@ -55,9 +56,8 @@ export class Aggregate extends AggregateBase {
|
|
|
55
56
|
*
|
|
56
57
|
* @param {Function} cb A function to run once the RUM call has finished - Defaults to activateFeatures
|
|
57
58
|
* @param {*} customAttributes custom attributes to attach to the RUM call - Defaults to info.js
|
|
58
|
-
* @param {*} target The target to harvest to
|
|
59
59
|
*/
|
|
60
|
-
sendRum (customAttributes = this.agentRef.info.jsAttributes
|
|
60
|
+
sendRum (customAttributes = this.agentRef.info.jsAttributes) {
|
|
61
61
|
const info = this.agentRef.info
|
|
62
62
|
const measures = {}
|
|
63
63
|
|
|
@@ -110,24 +110,26 @@ export class Aggregate extends AggregateBase {
|
|
|
110
110
|
queryParameters.fp = firstPaint.current.value
|
|
111
111
|
queryParameters.fcp = firstContentfulPaint.current.value
|
|
112
112
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
113
|
+
this.queryStringsBuilder = () => { // this will be called by AggregateBase.makeHarvestPayload every time harvest is triggered to be qs
|
|
114
|
+
this.rumStartTime = now() // this should be reset at the beginning of each RUM call for proper timeKeeper calculation in coordination with postHarvestCleanup
|
|
115
|
+
const timeKeeper = this.agentRef.runtime.timeKeeper
|
|
116
|
+
if (timeKeeper?.ready) {
|
|
117
|
+
queryParameters.timestamp = Math.floor(timeKeeper.correctRelativeTimestamp(this.rumStartTime))
|
|
118
|
+
}
|
|
119
|
+
return queryParameters
|
|
116
120
|
}
|
|
117
|
-
|
|
118
|
-
this.rumStartTime = now()
|
|
121
|
+
this.events.add(body)
|
|
119
122
|
|
|
120
123
|
this.agentRef.runtime.harvester.triggerHarvestFor(this, {
|
|
121
|
-
directSend: {
|
|
122
|
-
target,
|
|
123
|
-
payload: { qs: queryParameters, body }
|
|
124
|
-
},
|
|
125
|
-
needResponse: true,
|
|
126
124
|
sendEmptyBody: true
|
|
127
125
|
})
|
|
128
126
|
}
|
|
129
127
|
|
|
130
|
-
|
|
128
|
+
serializer (eventBuffer) { // this is necessary because PVE sends a single item rather than an array; in the case of undefined, this prevents sending [null] as body
|
|
129
|
+
return eventBuffer[0]
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
postHarvestCleanup ({ sent, status, responseText, xhr, retry }) {
|
|
131
133
|
const rumEndTime = now()
|
|
132
134
|
let app, flags
|
|
133
135
|
try {
|
|
@@ -137,8 +139,16 @@ export class Aggregate extends AggregateBase {
|
|
|
137
139
|
warn(53, error)
|
|
138
140
|
}
|
|
139
141
|
|
|
142
|
+
super.postHarvestCleanup({ sent, retry }) // this will set isRetrying & re-buffer the body if request is to be retried
|
|
143
|
+
if (this.isRetrying && this.retries++ < 1) { // Only retry once
|
|
144
|
+
setTimeout(() => this.agentRef.runtime.harvester.triggerHarvestFor(this, {
|
|
145
|
+
sendEmptyBody: true
|
|
146
|
+
}), 5000) // Retry sending the RUM event after 5 seconds
|
|
147
|
+
return
|
|
148
|
+
}
|
|
140
149
|
if (status >= 400 || status === 0) {
|
|
141
150
|
warn(18, status)
|
|
151
|
+
this.blocked = true
|
|
142
152
|
|
|
143
153
|
// Get estimated payload size of our backlog
|
|
144
154
|
const textEncoder = new TextEncoder()
|
|
@@ -205,6 +215,7 @@ export class Aggregate extends AggregateBase {
|
|
|
205
215
|
}
|
|
206
216
|
} catch (error) {
|
|
207
217
|
this.ee.abort()
|
|
218
|
+
this.blocked = true
|
|
208
219
|
warn(17, error)
|
|
209
220
|
return
|
|
210
221
|
}
|