@newrelic/browser-agent 1.271.0 → 1.273.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 +15 -0
- package/dist/cjs/common/aggregate/aggregator.js +23 -30
- package/dist/cjs/common/aggregate/event-aggregator.js +84 -0
- package/dist/cjs/common/config/init.js +8 -4
- 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/harvest-scheduler.js +1 -1
- package/dist/cjs/common/harvest/harvest.js +1 -5
- package/dist/cjs/common/harvest/types.js +0 -1
- package/dist/cjs/features/ajax/aggregate/index.js +52 -62
- package/dist/cjs/features/generic_events/aggregate/index.js +57 -36
- package/dist/cjs/features/generic_events/instrument/index.js +1 -1
- package/dist/cjs/features/jserrors/aggregate/index.js +23 -69
- package/dist/cjs/features/logging/aggregate/index.js +52 -59
- package/dist/cjs/features/metrics/aggregate/index.js +8 -5
- package/dist/cjs/features/page_view_timing/aggregate/index.js +8 -25
- package/dist/cjs/features/session_replay/aggregate/index.js +11 -10
- package/dist/cjs/features/session_replay/shared/recorder-events.js +2 -2
- package/dist/cjs/features/session_trace/aggregate/index.js +77 -88
- package/dist/cjs/features/session_trace/aggregate/trace/storage.js +22 -13
- package/dist/cjs/features/soft_navigations/aggregate/index.js +10 -20
- package/dist/cjs/features/soft_navigations/instrument/index.js +5 -9
- package/dist/cjs/features/spa/aggregate/index.js +10 -26
- package/dist/cjs/features/utils/aggregate-base.js +37 -0
- package/dist/cjs/features/utils/event-buffer.js +36 -87
- package/dist/cjs/features/utils/instrument-base.js +3 -3
- package/dist/cjs/loaders/features/features.js +13 -1
- package/dist/esm/common/aggregate/aggregator.js +23 -30
- package/dist/esm/common/aggregate/event-aggregator.js +78 -0
- package/dist/esm/common/config/init.js +8 -4
- 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/harvest-scheduler.js +1 -1
- package/dist/esm/common/harvest/harvest.js +1 -5
- package/dist/esm/common/harvest/types.js +0 -1
- package/dist/esm/features/ajax/aggregate/index.js +53 -62
- package/dist/esm/features/generic_events/aggregate/index.js +57 -36
- package/dist/esm/features/generic_events/instrument/index.js +1 -1
- package/dist/esm/features/jserrors/aggregate/index.js +24 -70
- package/dist/esm/features/logging/aggregate/index.js +52 -59
- package/dist/esm/features/metrics/aggregate/index.js +8 -5
- package/dist/esm/features/page_view_timing/aggregate/index.js +9 -26
- package/dist/esm/features/session_replay/aggregate/index.js +12 -11
- package/dist/esm/features/session_replay/shared/recorder-events.js +2 -2
- package/dist/esm/features/session_trace/aggregate/index.js +77 -88
- package/dist/esm/features/session_trace/aggregate/trace/storage.js +22 -13
- package/dist/esm/features/soft_navigations/aggregate/index.js +11 -21
- package/dist/esm/features/soft_navigations/instrument/index.js +5 -9
- package/dist/esm/features/spa/aggregate/index.js +11 -27
- package/dist/esm/features/utils/aggregate-base.js +37 -0
- package/dist/esm/features/utils/event-buffer.js +36 -88
- package/dist/esm/features/utils/instrument-base.js +3 -3
- package/dist/esm/loaders/features/features.js +12 -0
- package/dist/types/common/aggregate/aggregator.d.ts +4 -6
- package/dist/types/common/aggregate/aggregator.d.ts.map +1 -1
- package/dist/types/common/aggregate/event-aggregator.d.ts +26 -0
- package/dist/types/common/aggregate/event-aggregator.d.ts.map +1 -0
- package/dist/types/common/config/init.d.ts.map +1 -1
- package/dist/types/common/harvest/harvest.d.ts.map +1 -1
- package/dist/types/common/harvest/types.d.ts +1 -4
- package/dist/types/common/harvest/types.d.ts.map +1 -1
- package/dist/types/features/ajax/aggregate/index.d.ts +2 -10
- package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/generic_events/aggregate/index.d.ts +5 -11
- package/dist/types/features/generic_events/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/generic_events/instrument/index.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts +4 -7
- package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/logging/aggregate/index.d.ts +10 -28
- package/dist/types/features/logging/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_timing/aggregate/index.d.ts +1 -9
- package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts +3 -4
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/recorder-events.d.ts +1 -1
- package/dist/types/features/session_replay/shared/recorder-events.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/recorder.d.ts +1 -1
- package/dist/types/features/session_trace/aggregate/index.d.ts +17 -19
- package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_trace/aggregate/trace/storage.d.ts +10 -6
- package/dist/types/features/session_trace/aggregate/trace/storage.d.ts.map +1 -1
- package/dist/types/features/soft_navigations/aggregate/index.d.ts +3 -9
- package/dist/types/features/soft_navigations/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/soft_navigations/instrument/index.d.ts.map +1 -1
- package/dist/types/features/spa/aggregate/index.d.ts +2 -3
- package/dist/types/features/spa/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/utils/aggregate-base.d.ts +14 -0
- package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
- package/dist/types/features/utils/event-buffer.d.ts +19 -56
- package/dist/types/features/utils/event-buffer.d.ts.map +1 -1
- package/dist/types/loaders/features/features.d.ts +3 -0
- package/dist/types/loaders/features/features.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/common/aggregate/aggregator.js +22 -32
- package/src/common/aggregate/event-aggregator.js +76 -0
- package/src/common/config/init.js +6 -2
- package/src/common/harvest/harvest-scheduler.js +1 -1
- package/src/common/harvest/harvest.js +1 -5
- package/src/common/harvest/types.js +0 -1
- package/src/features/ajax/aggregate/index.js +60 -67
- package/src/features/generic_events/aggregate/index.js +48 -38
- package/src/features/generic_events/instrument/index.js +2 -0
- package/src/features/jserrors/aggregate/index.js +21 -77
- package/src/features/logging/aggregate/index.js +46 -60
- package/src/features/metrics/aggregate/index.js +6 -4
- package/src/features/page_view_timing/aggregate/index.js +9 -30
- package/src/features/session_replay/aggregate/index.js +10 -14
- package/src/features/session_replay/shared/recorder-events.js +2 -2
- package/src/features/session_trace/aggregate/index.js +64 -73
- package/src/features/session_trace/aggregate/trace/storage.js +25 -14
- package/src/features/soft_navigations/aggregate/index.js +11 -22
- package/src/features/soft_navigations/instrument/index.js +6 -9
- package/src/features/spa/aggregate/index.js +12 -27
- package/src/features/utils/aggregate-base.js +39 -0
- package/src/features/utils/event-buffer.js +36 -83
- package/src/features/utils/instrument-base.js +3 -3
- package/src/loaders/features/features.js +13 -0
- package/dist/cjs/features/ajax/aggregate/chunk.js +0 -51
- package/dist/esm/features/ajax/aggregate/chunk.js +0 -44
- package/dist/types/features/ajax/aggregate/chunk.d.ts +0 -8
- package/dist/types/features/ajax/aggregate/chunk.d.ts.map +0 -1
- package/src/features/ajax/aggregate/chunk.js +0 -52
|
@@ -12,9 +12,9 @@ import { warn } from '../../../common/util/console';
|
|
|
12
12
|
import { now } from '../../../common/timing/now';
|
|
13
13
|
import { registerHandler } from '../../../common/event-emitter/register-handler';
|
|
14
14
|
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants';
|
|
15
|
-
import { EventBuffer } from '../../utils/event-buffer';
|
|
16
15
|
import { applyFnToProps } from '../../../common/util/traverse';
|
|
17
16
|
import { IDEAL_PAYLOAD_SIZE } from '../../../common/constants/agent-constants';
|
|
17
|
+
import { FEATURE_TO_ENDPOINT } from '../../../loaders/features/features';
|
|
18
18
|
import { UserActionsAggregator } from './user-actions/user-actions-aggregator';
|
|
19
19
|
import { isIFrameWindow } from '../../../common/dom/iframe';
|
|
20
20
|
export class Aggregate extends AggregateBase {
|
|
@@ -24,14 +24,12 @@ export class Aggregate extends AggregateBase {
|
|
|
24
24
|
this.eventsPerHarvest = 1000;
|
|
25
25
|
this.harvestTimeSeconds = agentRef.init.generic_events.harvestTimeSeconds;
|
|
26
26
|
this.referrerUrl = isBrowserScope && document.referrer ? cleanURL(document.referrer) : undefined;
|
|
27
|
-
this.events = new EventBuffer();
|
|
28
27
|
this.waitForFlags(['ins']).then(([ins]) => {
|
|
29
28
|
if (!ins) {
|
|
30
29
|
this.blocked = true;
|
|
31
30
|
this.deregisterDrain();
|
|
32
31
|
return;
|
|
33
32
|
}
|
|
34
|
-
const preHarvestMethods = [];
|
|
35
33
|
if (agentRef.init.page_action.enabled) {
|
|
36
34
|
registerHandler('api-addPageAction', (timestamp, name, attributes) => {
|
|
37
35
|
this.addEvent({
|
|
@@ -48,9 +46,10 @@ export class Aggregate extends AggregateBase {
|
|
|
48
46
|
});
|
|
49
47
|
}, this.featureName, this.ee);
|
|
50
48
|
}
|
|
49
|
+
let addUserAction;
|
|
51
50
|
if (isBrowserScope && agentRef.init.user_actions.enabled) {
|
|
52
51
|
this.userActionAggregator = new UserActionsAggregator();
|
|
53
|
-
|
|
52
|
+
addUserAction = aggregatedUserAction => {
|
|
54
53
|
try {
|
|
55
54
|
/** The aggregator process only returns an event when it is "done" aggregating -
|
|
56
55
|
* so we still need to validate that an event was given to this method before we try to add */
|
|
@@ -92,21 +91,53 @@ export class Aggregate extends AggregateBase {
|
|
|
92
91
|
};
|
|
93
92
|
registerHandler('ua', evt => {
|
|
94
93
|
/** the processor will return the previously aggregated event if it has been completed by processing the current event */
|
|
95
|
-
|
|
94
|
+
addUserAction(this.userActionAggregator.process(evt));
|
|
96
95
|
}, this.featureName, this.ee);
|
|
97
|
-
preHarvestMethods.push((options = {}) => {
|
|
98
|
-
/** send whatever UserActions have been aggregated up to this point
|
|
99
|
-
* if we are in a final harvest. By accessing the aggregationEvent, the aggregation is then force-cleared */
|
|
100
|
-
if (options.isFinalHarvest) this.addUserAction(this.userActionAggregator.aggregationEvent);
|
|
101
|
-
});
|
|
102
96
|
}
|
|
103
|
-
|
|
104
|
-
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* is it worth complicating the agent and skipping the POs for single repeating queries? maybe,
|
|
100
|
+
* but right now it was less desirable simply because it is a nice benefit of populating the event buffer
|
|
101
|
+
* immediately as events happen for payload evaluation purposes and that becomes a little more chaotic
|
|
102
|
+
* with an arbitrary query method. note: eventTypes: [...types] does not support the 'buffered' flag so we have
|
|
103
|
+
* to create up to two PO's here.
|
|
104
|
+
*/
|
|
105
|
+
const performanceTypesToCapture = [...(agentRef.init.performance.capture_marks ? ['mark'] : []), ...(agentRef.init.performance.capture_measures ? ['measure'] : [])];
|
|
106
|
+
if (performanceTypesToCapture.length) {
|
|
107
|
+
try {
|
|
108
|
+
performanceTypesToCapture.forEach(type => {
|
|
109
|
+
if (PerformanceObserver.supportedEntryTypes.includes(type)) {
|
|
110
|
+
const observer = new PerformanceObserver(list => {
|
|
111
|
+
list.getEntries().forEach(entry => {
|
|
112
|
+
try {
|
|
113
|
+
this.addEvent({
|
|
114
|
+
eventType: 'BrowserPerformance',
|
|
115
|
+
timestamp: Math.floor(agentRef.runtime.timeKeeper.correctRelativeTimestamp(entry.startTime)),
|
|
116
|
+
entryName: entry.name,
|
|
117
|
+
entryDuration: entry.duration,
|
|
118
|
+
entryType: type,
|
|
119
|
+
...(entry.detail && {
|
|
120
|
+
entryDetail: entry.detail
|
|
121
|
+
})
|
|
122
|
+
});
|
|
123
|
+
} catch (err) {}
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
observer.observe({
|
|
127
|
+
buffered: true,
|
|
128
|
+
type
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
} catch (err) {
|
|
133
|
+
// Something failed in our set up, likely the browser does not support PO's... do nothing
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
this.harvestScheduler = new HarvestScheduler(FEATURE_TO_ENDPOINT[this.featureName], {
|
|
137
|
+
onFinished: result => this.postHarvestCleanup(result.sent && result.retry),
|
|
138
|
+
onUnload: () => addUserAction?.(this.userActionAggregator.aggregationEvent)
|
|
105
139
|
}, this);
|
|
106
|
-
this.harvestScheduler.harvest.on(
|
|
107
|
-
preHarvestMethods.forEach(fn => fn(...args));
|
|
108
|
-
return this.onHarvestStarted(...args);
|
|
109
|
-
});
|
|
140
|
+
this.harvestScheduler.harvest.on(FEATURE_TO_ENDPOINT[this.featureName], options => this.makeHarvestPayload(options.retry));
|
|
110
141
|
this.harvestScheduler.startTimer(this.harvestTimeSeconds, 0);
|
|
111
142
|
this.drain();
|
|
112
143
|
});
|
|
@@ -153,30 +184,20 @@ export class Aggregate extends AggregateBase {
|
|
|
153
184
|
this.events.add(eventAttributes);
|
|
154
185
|
this.checkEventLimits();
|
|
155
186
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
} = this.agentRef.info;
|
|
161
|
-
if (!this.events.hasData) return;
|
|
162
|
-
var payload = {
|
|
163
|
-
qs: {
|
|
164
|
-
ua: userAttributes,
|
|
165
|
-
at: atts
|
|
166
|
-
},
|
|
167
|
-
body: applyFnToProps({
|
|
168
|
-
ins: this.events.buffer
|
|
169
|
-
}, this.obfuscator.obfuscateString.bind(this.obfuscator), 'string')
|
|
170
|
-
};
|
|
171
|
-
if (options.retry) this.events.hold();else this.events.clear();
|
|
172
|
-
return payload;
|
|
187
|
+
serializer(eventBuffer) {
|
|
188
|
+
return applyFnToProps({
|
|
189
|
+
ins: eventBuffer
|
|
190
|
+
}, this.obfuscator.obfuscateString.bind(this.obfuscator), 'string');
|
|
173
191
|
}
|
|
174
|
-
|
|
175
|
-
|
|
192
|
+
queryStringsBuilder() {
|
|
193
|
+
return {
|
|
194
|
+
ua: this.agentRef.info.userAttributes,
|
|
195
|
+
at: this.agentRef.info.atts
|
|
196
|
+
};
|
|
176
197
|
}
|
|
177
198
|
checkEventLimits() {
|
|
178
199
|
// check if we've reached any harvest limits...
|
|
179
|
-
if (this.events.
|
|
200
|
+
if (this.events.byteSize() > IDEAL_PAYLOAD_SIZE) {
|
|
180
201
|
this.ee.emit(SUPPORTABILITY_METRIC_CHANNEL, ['GenericEvents/Harvest/Max/Seen']);
|
|
181
202
|
this.harvestScheduler.runHarvest();
|
|
182
203
|
}
|
|
@@ -11,7 +11,7 @@ export class Instrument extends InstrumentBase {
|
|
|
11
11
|
static featureName = FEATURE_NAME;
|
|
12
12
|
constructor(agentRef, auto = true) {
|
|
13
13
|
super(agentRef, FEATURE_NAME, auto);
|
|
14
|
-
const genericEventSourceConfigs = [agentRef.init.page_action.enabled, agentRef.init.user_actions.enabled
|
|
14
|
+
const genericEventSourceConfigs = [agentRef.init.page_action.enabled, agentRef.init.performance.capture_marks, agentRef.init.performance.capture_measures, agentRef.init.user_actions.enabled
|
|
15
15
|
// other future generic event source configs to go here, like M&Ms, PageResouce, etc.
|
|
16
16
|
];
|
|
17
17
|
if (isBrowserScope && agentRef.init.user_actions.enabled) {
|
|
@@ -13,9 +13,8 @@ import { stringify } from '../../../common/util/stringify';
|
|
|
13
13
|
import { handle } from '../../../common/event-emitter/handle';
|
|
14
14
|
import { globalScope } from '../../../common/constants/runtime';
|
|
15
15
|
import { FEATURE_NAME } from '../constants';
|
|
16
|
-
import { FEATURE_NAMES } from '../../../loaders/features/features';
|
|
16
|
+
import { FEATURE_NAMES, FEATURE_TO_ENDPOINT } from '../../../loaders/features/features';
|
|
17
17
|
import { AggregateBase } from '../../utils/aggregate-base';
|
|
18
|
-
import { getNREUMInitializedAgent } from '../../../common/window/nreum';
|
|
19
18
|
import { now } from '../../../common/timing/now';
|
|
20
19
|
import { applyFnToProps } from '../../../common/util/traverse';
|
|
21
20
|
import { evaluateInternalError } from './internal-errors';
|
|
@@ -33,7 +32,6 @@ export class Aggregate extends AggregateBase {
|
|
|
33
32
|
this.observedAt = {};
|
|
34
33
|
this.pageviewReported = {};
|
|
35
34
|
this.bufferedErrorsUnderSpa = {};
|
|
36
|
-
this.currentBody = undefined;
|
|
37
35
|
this.errorOnPage = false;
|
|
38
36
|
|
|
39
37
|
// this will need to change to match whatever ee we use in the instrument
|
|
@@ -43,14 +41,19 @@ export class Aggregate extends AggregateBase {
|
|
|
43
41
|
register('softNavFlush', (interactionId, wasFinished, softNavAttrs) => this.onSoftNavNotification(interactionId, wasFinished, softNavAttrs), this.featureName, this.ee); // when an ixn is done or cancelled
|
|
44
42
|
|
|
45
43
|
const harvestTimeSeconds = agentRef.init.jserrors.harvestTimeSeconds || 10;
|
|
44
|
+
const aggregatorTypes = ['err', 'ierr', 'xhr']; // the types in EventAggregator this feature cares about
|
|
46
45
|
|
|
47
46
|
// 0 == off, 1 == on
|
|
48
47
|
this.waitForFlags(['err']).then(([errFlag]) => {
|
|
49
48
|
if (errFlag) {
|
|
50
|
-
const scheduler = new HarvestScheduler(
|
|
51
|
-
onFinished:
|
|
49
|
+
const scheduler = new HarvestScheduler(FEATURE_TO_ENDPOINT[this.featureName], {
|
|
50
|
+
onFinished: result => this.postHarvestCleanup(result.sent && result.retry, {
|
|
51
|
+
aggregatorTypes
|
|
52
|
+
})
|
|
52
53
|
}, this);
|
|
53
|
-
scheduler.harvest.on(
|
|
54
|
+
scheduler.harvest.on(FEATURE_TO_ENDPOINT[this.featureName], options => this.makeHarvestPayload(options.retry, {
|
|
55
|
+
aggregatorTypes
|
|
56
|
+
}));
|
|
54
57
|
scheduler.startTimer(harvestTimeSeconds);
|
|
55
58
|
this.drain();
|
|
56
59
|
} else {
|
|
@@ -59,49 +62,22 @@ export class Aggregate extends AggregateBase {
|
|
|
59
62
|
}
|
|
60
63
|
});
|
|
61
64
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
qs: {}
|
|
71
|
-
};
|
|
72
|
-
var releaseIds = stringify(this.agentRef.runtime.releaseIds);
|
|
73
|
-
if (releaseIds !== '{}') {
|
|
74
|
-
payload.qs.ri = releaseIds;
|
|
75
|
-
}
|
|
76
|
-
if (body && body.err && body.err.length) {
|
|
77
|
-
this.#runCrossFeatureChecks(body.err);
|
|
65
|
+
serializer(aggregatorTypeToBucketsMap) {
|
|
66
|
+
return applyFnToProps(aggregatorTypeToBucketsMap, this.obfuscator.obfuscateString.bind(this.obfuscator), 'string');
|
|
67
|
+
}
|
|
68
|
+
queryStringsBuilder(aggregatorTakeReturnedData) {
|
|
69
|
+
const qs = {};
|
|
70
|
+
const releaseIds = stringify(this.agentRef.runtime.releaseIds);
|
|
71
|
+
if (releaseIds !== '{}') qs.ri = releaseIds;
|
|
72
|
+
if (aggregatorTakeReturnedData?.err?.length) {
|
|
78
73
|
if (!this.errorOnPage) {
|
|
79
|
-
|
|
74
|
+
qs.pve = '1';
|
|
80
75
|
this.errorOnPage = true;
|
|
81
76
|
}
|
|
77
|
+
// For assurance, erase any `hasReplay` flag from all errors if replay is not recording, not-yet imported, or not running at all.
|
|
78
|
+
if (!this.agentRef.features?.[FEATURE_NAMES.sessionReplay]?.featAggregate?.replayIsActive()) aggregatorTakeReturnedData.err.forEach(error => delete error.params.hasReplay);
|
|
82
79
|
}
|
|
83
|
-
return
|
|
84
|
-
}
|
|
85
|
-
onHarvestFinished(result) {
|
|
86
|
-
if (result.retry && this.currentBody) {
|
|
87
|
-
Object.entries(this.currentBody || {}).forEach(([key, value]) => {
|
|
88
|
-
for (var i = 0; i < value.length; i++) {
|
|
89
|
-
var bucket = value[i];
|
|
90
|
-
var name = this.getBucketName(key, bucket.params, bucket.custom);
|
|
91
|
-
this.agentRef.sharedAggregator.merge(key, name, bucket.metrics, bucket.params, bucket.custom);
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
this.currentBody = null;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
nameHash(params) {
|
|
98
|
-
return stringHashCode("".concat(params.exceptionClass, "_").concat(params.message, "_").concat(params.stack_trace || params.browser_stack_hash));
|
|
99
|
-
}
|
|
100
|
-
getBucketName(objType, params, customParams) {
|
|
101
|
-
if (objType === 'xhr') {
|
|
102
|
-
return stringHashCode(stringify(params)) + ':' + stringHashCode(stringify(customParams));
|
|
103
|
-
}
|
|
104
|
-
return this.nameHash(params) + ':' + stringHashCode(stringify(customParams));
|
|
80
|
+
return qs;
|
|
105
81
|
}
|
|
106
82
|
|
|
107
83
|
/**
|
|
@@ -208,7 +184,7 @@ export class Aggregate extends AggregateBase {
|
|
|
208
184
|
params._interactionId = err.__newrelic[this.agentIdentifier].interactionId;
|
|
209
185
|
params._interactionNodeId = err.__newrelic[this.agentIdentifier].interactionNodeId;
|
|
210
186
|
}
|
|
211
|
-
const softNavInUse = Boolean(
|
|
187
|
+
const softNavInUse = Boolean(this.agentRef.features?.[FEATURE_NAMES.softNav]);
|
|
212
188
|
// Note: the following are subject to potential race cond wherein if the other feature aren't fully initialized, it'll be treated as there being no associated interaction.
|
|
213
189
|
// They each will also tack on their respective properties to the params object as part of the decision flow.
|
|
214
190
|
if (softNavInUse) handle('jserror', [params, time], undefined, FEATURE_NAMES.softNav, this.ee);else handle('spa-jserror', jsErrorEvent, undefined, FEATURE_NAMES.spa, this.ee);
|
|
@@ -243,7 +219,7 @@ export class Aggregate extends AggregateBase {
|
|
|
243
219
|
|
|
244
220
|
const jsAttributesHash = stringHashCode(stringify(allCustomAttrs));
|
|
245
221
|
const aggregateHash = bucketHash + ':' + jsAttributesHash;
|
|
246
|
-
this.
|
|
222
|
+
this.events.add(type, aggregateHash, params, newMetrics, allCustomAttrs);
|
|
247
223
|
function setCustom(key, val) {
|
|
248
224
|
allCustomAttrs[key] = val && typeof val === 'object' ? stringify(val) : val;
|
|
249
225
|
}
|
|
@@ -267,7 +243,7 @@ export class Aggregate extends AggregateBase {
|
|
|
267
243
|
var hash = wasSaved ? item[1] + interaction.root.attrs.id : item[1];
|
|
268
244
|
var jsAttributesHash = stringHashCode(stringify(allCustomAttrs));
|
|
269
245
|
var aggregateHash = hash + ':' + jsAttributesHash;
|
|
270
|
-
this.
|
|
246
|
+
this.events.add(item[0], aggregateHash, params, item[3], allCustomAttrs);
|
|
271
247
|
function setCustom([key, val]) {
|
|
272
248
|
allCustomAttrs[key] = val && typeof val === 'object' ? stringify(val) : val;
|
|
273
249
|
}
|
|
@@ -280,26 +256,4 @@ export class Aggregate extends AggregateBase {
|
|
|
280
256
|
);
|
|
281
257
|
delete this.bufferedErrorsUnderSpa[interactionId]; // wipe the list of jserrors so they aren't duplicated by another call to the same id
|
|
282
258
|
}
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* Dispatches a cross-feature communication event to allow other
|
|
286
|
-
* features to provide flags and data that can be used to mutation
|
|
287
|
-
* to the payload and to allow features to know about a feature
|
|
288
|
-
* harvest happening.
|
|
289
|
-
* @param {any[]} errors Array of errors from the payload body
|
|
290
|
-
*/
|
|
291
|
-
#runCrossFeatureChecks(errors) {
|
|
292
|
-
const errorHashes = errors.map(error => error.params.stackHash);
|
|
293
|
-
const crossFeatureData = {
|
|
294
|
-
errorHashes
|
|
295
|
-
};
|
|
296
|
-
this.ee.emit("cfc.".concat(this.featureName), [crossFeatureData]);
|
|
297
|
-
let hasReplayFlag = errors.find(err => err.params.hasReplay);
|
|
298
|
-
if (hasReplayFlag && !crossFeatureData.hasReplay) {
|
|
299
|
-
// Some errors have `hasReplay` and a replay is not being recorded
|
|
300
|
-
errors.forEach(error => {
|
|
301
|
-
delete error.params.hasReplay;
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
259
|
}
|
|
@@ -10,20 +10,17 @@ import { Log } from '../shared/log';
|
|
|
10
10
|
import { isValidLogLevel } from '../shared/utils';
|
|
11
11
|
import { applyFnToProps } from '../../../common/util/traverse';
|
|
12
12
|
import { MAX_PAYLOAD_SIZE } from '../../../common/constants/agent-constants';
|
|
13
|
-
import {
|
|
13
|
+
import { FEATURE_TO_ENDPOINT } from '../../../loaders/features/features';
|
|
14
14
|
export class Aggregate extends AggregateBase {
|
|
15
15
|
static featureName = FEATURE_NAME;
|
|
16
16
|
constructor(agentRef) {
|
|
17
17
|
super(agentRef, FEATURE_NAME);
|
|
18
|
-
|
|
19
|
-
/** held logs before sending */
|
|
20
|
-
this.bufferedLogs = new EventBuffer();
|
|
21
18
|
this.harvestTimeSeconds = agentRef.init.logging.harvestTimeSeconds;
|
|
22
19
|
this.waitForFlags([]).then(() => {
|
|
23
|
-
this.scheduler = new HarvestScheduler(
|
|
24
|
-
onFinished: this.
|
|
20
|
+
this.scheduler = new HarvestScheduler(FEATURE_TO_ENDPOINT[this.featureName], {
|
|
21
|
+
onFinished: result => this.postHarvestCleanup(result.sent && result.retry),
|
|
25
22
|
retryDelay: this.harvestTimeSeconds,
|
|
26
|
-
getPayload: this.
|
|
23
|
+
getPayload: options => this.makeHarvestPayload(options.retry),
|
|
27
24
|
raw: true
|
|
28
25
|
}, this);
|
|
29
26
|
/** emitted by instrument class (wrapped loggers) or the api methods directly */
|
|
@@ -56,63 +53,59 @@ export class Aggregate extends AggregateBase {
|
|
|
56
53
|
const log = new Log(Math.floor(this.agentRef.runtime.timeKeeper.correctRelativeTimestamp(timestamp)), message, attributes, level);
|
|
57
54
|
const logBytes = log.message.length + stringify(log.attributes).length + log.level.length + 10; // timestamp == 10 chars
|
|
58
55
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
} else {
|
|
65
|
-
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Logging/Harvest/Failed/Seen', logBytes]);
|
|
66
|
-
warn(31, log.message.slice(0, 25) + '...');
|
|
67
|
-
}
|
|
56
|
+
const failToHarvestMessage = 'Logging/Harvest/Failed/Seen';
|
|
57
|
+
if (logBytes > MAX_PAYLOAD_SIZE) {
|
|
58
|
+
// cannot possibly send this, even with an empty buffer
|
|
59
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, [failToHarvestMessage, logBytes]);
|
|
60
|
+
warn(31, log.message.slice(0, 25) + '...');
|
|
68
61
|
return;
|
|
69
62
|
}
|
|
70
|
-
this.
|
|
63
|
+
if (this.events.wouldExceedMaxSize(logBytes)) {
|
|
64
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Logging/Harvest/Early/Seen', this.events.bytes + logBytes]);
|
|
65
|
+
this.scheduler.runHarvest(); // force a harvest to try adding again
|
|
66
|
+
}
|
|
67
|
+
if (!this.events.add(log)) {
|
|
68
|
+
// still failed after a harvest attempt despite not being too large would mean harvest failed with options.retry
|
|
69
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, [failToHarvestMessage, logBytes]);
|
|
70
|
+
warn(31, log.message.slice(0, 25) + '...');
|
|
71
|
+
}
|
|
71
72
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
qs: {
|
|
83
|
-
browser_monitoring_key: this.agentRef.info.licenseKey
|
|
84
|
-
},
|
|
85
|
-
body: [{
|
|
86
|
-
common: {
|
|
87
|
-
/** Attributes in the `common` section are added to `all` logs generated in the payload */
|
|
88
|
-
attributes: {
|
|
89
|
-
'entity.guid': this.agentRef.runtime.appMetadata?.agents?.[0]?.entityGuid,
|
|
90
|
-
// browser entity guid as provided from RUM response
|
|
91
|
-
session: this.agentRef.runtime.session?.state.value || '0',
|
|
73
|
+
serializer(eventBuffer) {
|
|
74
|
+
const sessionEntity = this.agentRef.runtime.session;
|
|
75
|
+
return [{
|
|
76
|
+
common: {
|
|
77
|
+
/** Attributes in the `common` section are added to `all` logs generated in the payload */
|
|
78
|
+
attributes: {
|
|
79
|
+
'entity.guid': this.agentRef.runtime.appMetadata?.agents?.[0]?.entityGuid,
|
|
80
|
+
// browser entity guid as provided from RUM response
|
|
81
|
+
...(sessionEntity && {
|
|
82
|
+
session: sessionEntity.state.value || '0',
|
|
92
83
|
// The session ID that we generate and keep across page loads
|
|
93
|
-
hasReplay:
|
|
84
|
+
hasReplay: sessionEntity.state.sessionReplayMode === 1,
|
|
94
85
|
// True if a session replay recording is running
|
|
95
|
-
hasTrace:
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
86
|
+
hasTrace: sessionEntity.state.sessionTraceMode === 1 // True if a session trace recording is running
|
|
87
|
+
}),
|
|
88
|
+
ptid: this.agentRef.runtime.ptid,
|
|
89
|
+
// page trace id
|
|
90
|
+
appId: this.agentRef.info.applicationID,
|
|
91
|
+
// Application ID from info object,
|
|
92
|
+
standalone: Boolean(this.agentRef.info.sa),
|
|
93
|
+
// copy paste (true) vs APM (false)
|
|
94
|
+
agentVersion: this.agentRef.runtime.version,
|
|
95
|
+
// browser agent version
|
|
96
|
+
// The following 3 attributes are evaluated and dropped at ingest processing time and do not get stored on NRDB:
|
|
97
|
+
'instrumentation.provider': 'browser',
|
|
98
|
+
'instrumentation.version': this.agentRef.runtime.version,
|
|
99
|
+
'instrumentation.name': this.agentRef.runtime.loaderType
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
/** logs section contains individual unique log entries */
|
|
103
|
+
logs: applyFnToProps(eventBuffer, this.obfuscator.obfuscateString.bind(this.obfuscator), 'string')
|
|
104
|
+
}];
|
|
114
105
|
}
|
|
115
|
-
|
|
116
|
-
|
|
106
|
+
queryStringsBuilder() {
|
|
107
|
+
return {
|
|
108
|
+
browser_monitoring_key: this.agentRef.info.licenseKey
|
|
109
|
+
};
|
|
117
110
|
}
|
|
118
111
|
}
|
|
@@ -7,6 +7,7 @@ import { onDOMContentLoaded } from '../../../common/window/load';
|
|
|
7
7
|
import { windowAddEventListener } from '../../../common/event-listener/event-listener-opts';
|
|
8
8
|
import { isBrowserScope, isWorkerScope } from '../../../common/constants/runtime';
|
|
9
9
|
import { AggregateBase } from '../../utils/aggregate-base';
|
|
10
|
+
import { FEATURE_TO_ENDPOINT } from '../../../loaders/features/features';
|
|
10
11
|
import { isIFrameWindow } from '../../../common/dom/iframe';
|
|
11
12
|
// import { WEBSOCKET_TAG } from '../../../common/wrap/wrap-websocket'
|
|
12
13
|
// import { handleWebsocketEvents } from './websocket-detection'
|
|
@@ -15,15 +16,17 @@ export class Aggregate extends AggregateBase {
|
|
|
15
16
|
static featureName = FEATURE_NAME;
|
|
16
17
|
constructor(agentRef) {
|
|
17
18
|
super(agentRef, FEATURE_NAME);
|
|
19
|
+
const aggregatorTypes = ['cm', 'sm']; // the types in EventAggregator this feature cares about
|
|
20
|
+
|
|
18
21
|
this.waitForFlags(['err']).then(([errFlag]) => {
|
|
19
22
|
if (errFlag) {
|
|
20
23
|
// *cli, Mar 23 - Per NR-94597, this feature should only harvest ONCE at the (potential) EoL time of the page.
|
|
21
|
-
const scheduler = new HarvestScheduler(
|
|
24
|
+
const scheduler = new HarvestScheduler(FEATURE_TO_ENDPOINT[this.featureName], {
|
|
22
25
|
onUnload: () => this.unload()
|
|
23
26
|
}, this);
|
|
24
27
|
// this is needed to ensure EoL is "on" and sent
|
|
25
|
-
scheduler.harvest.on(
|
|
26
|
-
|
|
28
|
+
scheduler.harvest.on(FEATURE_TO_ENDPOINT[this.featureName], () => this.makeHarvestPayload(undefined, {
|
|
29
|
+
aggregatorTypes
|
|
27
30
|
}));
|
|
28
31
|
this.drain();
|
|
29
32
|
} else {
|
|
@@ -44,7 +47,7 @@ export class Aggregate extends AggregateBase {
|
|
|
44
47
|
const params = {
|
|
45
48
|
name
|
|
46
49
|
};
|
|
47
|
-
this.
|
|
50
|
+
this.events.addMetric(type, name, params, value);
|
|
48
51
|
}
|
|
49
52
|
storeEventMetrics(name, metrics) {
|
|
50
53
|
if (this.blocked) return;
|
|
@@ -52,7 +55,7 @@ export class Aggregate extends AggregateBase {
|
|
|
52
55
|
const params = {
|
|
53
56
|
name
|
|
54
57
|
};
|
|
55
|
-
this.
|
|
58
|
+
this.events.add(type, name, params, metrics);
|
|
56
59
|
}
|
|
57
60
|
singleChecks() {
|
|
58
61
|
// report loaderType
|
|
@@ -8,7 +8,7 @@ import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler';
|
|
|
8
8
|
import { registerHandler } from '../../../common/event-emitter/register-handler';
|
|
9
9
|
import { handle } from '../../../common/event-emitter/handle';
|
|
10
10
|
import { FEATURE_NAME } from '../constants';
|
|
11
|
-
import { FEATURE_NAMES } from '../../../loaders/features/features';
|
|
11
|
+
import { FEATURE_NAMES, FEATURE_TO_ENDPOINT } from '../../../loaders/features/features';
|
|
12
12
|
import { AggregateBase } from '../../utils/aggregate-base';
|
|
13
13
|
import { cumulativeLayoutShift } from '../../../common/vitals/cumulative-layout-shift';
|
|
14
14
|
import { firstContentfulPaint } from '../../../common/vitals/first-contentful-paint';
|
|
@@ -19,7 +19,6 @@ import { largestContentfulPaint } from '../../../common/vitals/largest-contentfu
|
|
|
19
19
|
import { timeToFirstByte } from '../../../common/vitals/time-to-first-byte';
|
|
20
20
|
import { subscribeToVisibilityChange } from '../../../common/window/page-visibility';
|
|
21
21
|
import { VITAL_NAMES } from '../../../common/vitals/constants';
|
|
22
|
-
import { EventBuffer } from '../../utils/event-buffer';
|
|
23
22
|
export class Aggregate extends AggregateBase {
|
|
24
23
|
static featureName = FEATURE_NAME;
|
|
25
24
|
#handleVitalMetric = ({
|
|
@@ -31,7 +30,6 @@ export class Aggregate extends AggregateBase {
|
|
|
31
30
|
};
|
|
32
31
|
constructor(agentRef) {
|
|
33
32
|
super(agentRef, FEATURE_NAME);
|
|
34
|
-
this.timings = new EventBuffer();
|
|
35
33
|
this.curSessEndRecorded = false;
|
|
36
34
|
registerHandler('docHidden', msTimestamp => this.endCurrentSession(msTimestamp), this.featureName, this.ee);
|
|
37
35
|
// Add the time of _window pagehide event_ firing to the next PVT harvest == NRDB windowUnload attr:
|
|
@@ -63,9 +61,9 @@ export class Aggregate extends AggregateBase {
|
|
|
63
61
|
this.addTiming(name, value * 1000, attrs);
|
|
64
62
|
}, true); // CLS node should only reports on vis change rather than on every change
|
|
65
63
|
|
|
66
|
-
const scheduler = new HarvestScheduler(
|
|
67
|
-
onFinished:
|
|
68
|
-
getPayload:
|
|
64
|
+
const scheduler = new HarvestScheduler(FEATURE_TO_ENDPOINT[this.featureName], {
|
|
65
|
+
onFinished: result => this.postHarvestCleanup(result.sent && result.retry),
|
|
66
|
+
getPayload: options => this.makeHarvestPayload(options.retry)
|
|
69
67
|
}, this);
|
|
70
68
|
scheduler.startTimer(harvestTimeSeconds);
|
|
71
69
|
this.drain();
|
|
@@ -98,16 +96,13 @@ export class Aggregate extends AggregateBase {
|
|
|
98
96
|
if (name !== VITAL_NAMES.CUMULATIVE_LAYOUT_SHIFT && cumulativeLayoutShift.current.value >= 0) {
|
|
99
97
|
attrs.cls = cumulativeLayoutShift.current.value;
|
|
100
98
|
}
|
|
101
|
-
this.
|
|
99
|
+
this.events.add({
|
|
102
100
|
name,
|
|
103
101
|
value,
|
|
104
102
|
attrs
|
|
105
103
|
});
|
|
106
104
|
handle('pvtAdded', [name, value, attrs], undefined, FEATURE_NAMES.sessionTrace, this.ee);
|
|
107
105
|
}
|
|
108
|
-
onHarvestFinished(result) {
|
|
109
|
-
if (result.retry && this.timings.held.hasData) this.timings.unhold();else this.timings.held.clear();
|
|
110
|
-
}
|
|
111
106
|
appendGlobalCustomAttributes(timing) {
|
|
112
107
|
var timingAttributes = timing.attrs || {};
|
|
113
108
|
var reservedAttributes = ['size', 'eid', 'cls', 'type', 'fid', 'elTag', 'elUrl', 'net-type', 'net-etype', 'net-rtt', 'net-dlink'];
|
|
@@ -118,24 +113,12 @@ export class Aggregate extends AggregateBase {
|
|
|
118
113
|
});
|
|
119
114
|
}
|
|
120
115
|
|
|
121
|
-
// serialize and return current timing data, clear and save current data for retry
|
|
122
|
-
prepareHarvest(options) {
|
|
123
|
-
if (!this.timings.hasData) return;
|
|
124
|
-
var payload = this.getPayload(this.timings.buffer);
|
|
125
|
-
if (options.retry) this.timings.hold();else this.timings.clear();
|
|
126
|
-
return {
|
|
127
|
-
body: {
|
|
128
|
-
e: payload
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
|
|
133
116
|
// serialize array of timing data
|
|
134
|
-
|
|
117
|
+
serializer(eventBuffer) {
|
|
135
118
|
var addString = getAddStringContext(this.agentIdentifier);
|
|
136
119
|
var payload = 'bel.6;';
|
|
137
|
-
for (var i = 0; i <
|
|
138
|
-
var timing =
|
|
120
|
+
for (var i = 0; i < eventBuffer.length; i++) {
|
|
121
|
+
var timing = eventBuffer[i];
|
|
139
122
|
payload += 'e,';
|
|
140
123
|
payload += addString(timing.name) + ',';
|
|
141
124
|
payload += nullable(timing.value, numeric, false) + ',';
|
|
@@ -144,7 +127,7 @@ export class Aggregate extends AggregateBase {
|
|
|
144
127
|
if (attrParts && attrParts.length > 0) {
|
|
145
128
|
payload += numeric(attrParts.length) + ';' + attrParts.join(';');
|
|
146
129
|
}
|
|
147
|
-
if (i + 1 <
|
|
130
|
+
if (i + 1 < eventBuffer.length) payload += ';';
|
|
148
131
|
}
|
|
149
132
|
return payload;
|
|
150
133
|
}
|
|
@@ -16,7 +16,7 @@ import { warn } from '../../../common/util/console';
|
|
|
16
16
|
import { globalScope } from '../../../common/constants/runtime';
|
|
17
17
|
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants';
|
|
18
18
|
import { handle } from '../../../common/event-emitter/handle';
|
|
19
|
-
import { FEATURE_NAMES } from '../../../loaders/features/features';
|
|
19
|
+
import { FEATURE_NAMES, FEATURE_TO_ENDPOINT } from '../../../loaders/features/features';
|
|
20
20
|
import { RRWEB_VERSION } from "../../../common/constants/env.npm";
|
|
21
21
|
import { MODE, SESSION_EVENTS, SESSION_EVENT_TYPES } from '../../../common/session/constants';
|
|
22
22
|
import { stringify } from '../../../common/util/stringify';
|
|
@@ -50,9 +50,6 @@ export class Aggregate extends AggregateBase {
|
|
|
50
50
|
this.recorder = args?.recorder;
|
|
51
51
|
this.errorNoticed = args?.errorNoticed || false;
|
|
52
52
|
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/Enabled'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
53
|
-
this.ee.on("cfc.".concat(FEATURE_NAMES.jserrors), crossFeatureData => {
|
|
54
|
-
crossFeatureData.hasReplay = !!(this.scheduler?.started && this.recorder && this.mode === MODE.FULL && !this.blocked && this.entitled);
|
|
55
|
-
});
|
|
56
53
|
|
|
57
54
|
// The SessionEntity class can emit a message indicating the session was cleared and reset (expiry, inactivity). This feature must abort and never resume if that occurs.
|
|
58
55
|
this.ee.on(SESSION_EVENTS.RESET, () => {
|
|
@@ -78,10 +75,13 @@ export class Aggregate extends AggregateBase {
|
|
|
78
75
|
});
|
|
79
76
|
|
|
80
77
|
// Bespoke logic for blobs endpoint.
|
|
81
|
-
this.scheduler = new HarvestScheduler(
|
|
82
|
-
onFinished: this.
|
|
78
|
+
this.scheduler = new HarvestScheduler(FEATURE_TO_ENDPOINT[this.featureName], {
|
|
79
|
+
onFinished: result => this.postHarvestCleanup(result),
|
|
83
80
|
retryDelay: this.harvestTimeSeconds,
|
|
84
|
-
getPayload:
|
|
81
|
+
getPayload: ({
|
|
82
|
+
retry,
|
|
83
|
+
...opts
|
|
84
|
+
}) => this.makeHarvestPayload(retry, opts),
|
|
85
85
|
raw: true
|
|
86
86
|
}, this);
|
|
87
87
|
registerHandler(SR_EVENT_EMITTER_TYPES.PAUSE, () => {
|
|
@@ -130,6 +130,9 @@ export class Aggregate extends AggregateBase {
|
|
|
130
130
|
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/SamplingRate/Value', sampling_rate], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
131
131
|
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/ErrorSamplingRate/Value', error_sampling_rate], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
132
132
|
}
|
|
133
|
+
replayIsActive() {
|
|
134
|
+
return Boolean(this.scheduler?.started && this.recorder && this.mode === MODE.FULL && !this.blocked && this.entitled);
|
|
135
|
+
}
|
|
133
136
|
handleError(e) {
|
|
134
137
|
if (this.recorder) this.recorder.currentBufferTarget.hasError = true;
|
|
135
138
|
// run once
|
|
@@ -237,9 +240,7 @@ export class Aggregate extends AggregateBase {
|
|
|
237
240
|
// compressor failed to load, but we can still record without compression as a last ditch effort
|
|
238
241
|
}
|
|
239
242
|
}
|
|
240
|
-
|
|
241
|
-
opts
|
|
242
|
-
} = {}) {
|
|
243
|
+
makeHarvestPayload(shouldRetryOnFail, opts) {
|
|
243
244
|
if (!this.recorder || !this.timeKeeper?.ready || !this.recorder.hasSeenSnapshot) return;
|
|
244
245
|
const recorderEvents = this.recorder.getEvents();
|
|
245
246
|
// get the event type and use that to trigger another harvest if needed
|
|
@@ -375,7 +376,7 @@ export class Aggregate extends AggregateBase {
|
|
|
375
376
|
body: events
|
|
376
377
|
};
|
|
377
378
|
}
|
|
378
|
-
|
|
379
|
+
postHarvestCleanup(result) {
|
|
379
380
|
// The mutual decision for now is to stop recording and clear buffers if ingest is experiencing 429 rate limiting
|
|
380
381
|
if (result.status === 429) {
|
|
381
382
|
this.abort(ABORT_REASONS.TOO_MANY);
|