@newrelic/browser-agent 1.258.2 → 1.260.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 +20 -0
- package/dist/cjs/cdn/polyfills.js +3 -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/drain/drain.js +1 -1
- package/dist/cjs/common/harvest/harvest-scheduler.js +4 -2
- package/dist/cjs/common/session/session-entity.js +8 -1
- package/dist/cjs/common/timing/time-keeper.js +9 -30
- package/dist/cjs/features/ajax/constants.js +3 -2
- package/dist/cjs/features/jserrors/instrument/index.js +3 -4
- package/dist/cjs/features/metrics/aggregate/index.js +0 -8
- package/dist/cjs/features/page_view_event/aggregate/index.js +8 -6
- package/dist/cjs/features/session_replay/aggregate/index.js +31 -36
- package/dist/cjs/features/session_replay/constants.js +5 -2
- package/dist/cjs/features/session_replay/instrument/index.js +53 -13
- package/dist/cjs/features/session_replay/shared/recorder.js +8 -1
- package/dist/cjs/features/session_replay/shared/utils.js +3 -5
- package/dist/cjs/features/session_trace/aggregate/index.js +181 -527
- package/dist/cjs/features/session_trace/aggregate/trace/node.js +19 -0
- package/dist/cjs/features/session_trace/aggregate/trace/storage.js +289 -0
- package/dist/cjs/features/session_trace/constants.js +3 -2
- package/dist/cjs/features/session_trace/instrument/index.js +7 -3
- package/dist/cjs/features/utils/aggregate-base.js +1 -0
- package/dist/cjs/features/utils/feature-gates.js +17 -0
- package/dist/cjs/features/utils/instrument-base.js +2 -1
- package/dist/cjs/loaders/agent-base.js +4 -0
- package/dist/cjs/loaders/api/api-methods.js +1 -1
- package/dist/cjs/loaders/api/api.js +2 -2
- package/dist/cjs/loaders/configure/configure.js +1 -0
- package/dist/esm/cdn/polyfills.js +3 -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/drain/drain.js +1 -1
- package/dist/esm/common/harvest/harvest-scheduler.js +4 -2
- package/dist/esm/common/session/session-entity.js +8 -1
- package/dist/esm/common/timing/time-keeper.js +9 -30
- package/dist/esm/features/ajax/constants.js +2 -1
- package/dist/esm/features/jserrors/instrument/index.js +3 -4
- package/dist/esm/features/metrics/aggregate/index.js +0 -8
- package/dist/esm/features/page_view_event/aggregate/index.js +8 -6
- package/dist/esm/features/session_replay/aggregate/index.js +32 -37
- package/dist/esm/features/session_replay/constants.js +4 -1
- package/dist/esm/features/session_replay/instrument/index.js +54 -14
- package/dist/esm/features/session_replay/shared/recorder.js +8 -1
- package/dist/esm/features/session_replay/shared/utils.js +4 -6
- package/dist/esm/features/session_trace/aggregate/index.js +182 -527
- package/dist/esm/features/session_trace/aggregate/trace/node.js +12 -0
- package/dist/esm/features/session_trace/aggregate/trace/storage.js +282 -0
- package/dist/esm/features/session_trace/constants.js +2 -1
- package/dist/esm/features/session_trace/instrument/index.js +7 -3
- package/dist/esm/features/utils/aggregate-base.js +1 -0
- package/dist/esm/features/utils/feature-gates.js +11 -0
- package/dist/esm/features/utils/instrument-base.js +3 -2
- package/dist/esm/loaders/agent-base.js +4 -0
- package/dist/esm/loaders/api/api-methods.js +1 -1
- package/dist/esm/loaders/api/api.js +2 -2
- package/dist/esm/loaders/configure/configure.js +1 -0
- package/dist/types/common/harvest/harvest-scheduler.d.ts +1 -0
- package/dist/types/common/harvest/harvest-scheduler.d.ts.map +1 -1
- package/dist/types/common/session/session-entity.d.ts.map +1 -1
- package/dist/types/common/timing/time-keeper.d.ts +2 -0
- package/dist/types/common/timing/time-keeper.d.ts.map +1 -1
- package/dist/types/features/ajax/constants.d.ts +1 -0
- package/dist/types/features/ajax/constants.d.ts.map +1 -1
- package/dist/types/features/jserrors/instrument/index.d.ts.map +1 -1
- package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_event/aggregate/index.d.ts +2 -0
- package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/constants.d.ts +3 -0
- package/dist/types/features/session_replay/instrument/index.d.ts +0 -1
- package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/utils.d.ts +1 -1
- package/dist/types/features/session_replay/shared/utils.d.ts.map +1 -1
- package/dist/types/features/session_trace/aggregate/index.d.ts +39 -52
- package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_trace/aggregate/trace/node.d.ts +12 -0
- package/dist/types/features/session_trace/aggregate/trace/node.d.ts.map +1 -0
- package/dist/types/features/session_trace/aggregate/trace/storage.d.ts +43 -0
- package/dist/types/features/session_trace/aggregate/trace/storage.d.ts.map +1 -0
- package/dist/types/features/session_trace/constants.d.ts +1 -0
- package/dist/types/features/session_trace/constants.d.ts.map +1 -1
- package/dist/types/features/session_trace/instrument/index.d.ts.map +1 -1
- package/dist/types/features/utils/aggregate-base.d.ts +1 -0
- package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
- package/dist/types/features/utils/feature-gates.d.ts +2 -0
- package/dist/types/features/utils/feature-gates.d.ts.map +1 -0
- package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
- package/dist/types/loaders/agent-base.d.ts +1 -0
- package/dist/types/loaders/agent-base.d.ts.map +1 -1
- package/dist/types/loaders/configure/configure.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cdn/polyfills.js +2 -0
- package/src/common/drain/drain.js +1 -1
- package/src/common/harvest/harvest-scheduler.js +4 -2
- package/src/common/session/session-entity.js +3 -1
- package/src/common/timing/time-keeper.js +9 -30
- package/src/features/ajax/constants.js +2 -0
- package/src/features/jserrors/instrument/index.js +3 -4
- package/src/features/metrics/aggregate/index.js +0 -8
- package/src/features/page_view_event/aggregate/index.js +9 -5
- package/src/features/session_replay/aggregate/index.js +30 -39
- package/src/features/session_replay/constants.js +4 -0
- package/src/features/session_replay/instrument/index.js +48 -8
- package/src/features/session_replay/shared/__mocks__/utils.js +0 -1
- package/src/features/session_replay/shared/recorder.js +8 -1
- package/src/features/session_replay/shared/utils.js +4 -7
- package/src/features/session_trace/aggregate/index.js +157 -493
- package/src/features/session_trace/aggregate/trace/node.js +12 -0
- package/src/features/session_trace/aggregate/trace/storage.js +287 -0
- package/src/features/session_trace/constants.js +1 -0
- package/src/features/session_trace/instrument/index.js +7 -2
- package/src/features/utils/__mocks__/feature-gates.js +1 -0
- package/src/features/utils/aggregate-base.js +1 -0
- package/src/features/utils/feature-gates.js +11 -0
- package/src/features/utils/instrument-base.js +3 -2
- package/src/loaders/agent-base.js +4 -0
- package/src/loaders/api/api-methods.js +1 -1
- package/src/loaders/api/api.js +2 -2
- package/src/loaders/configure/configure.js +1 -0
- package/dist/cjs/features/session_replay/shared/replay-mode.js +0 -28
- package/dist/cjs/features/utils/handler-cache.js +0 -70
- package/dist/esm/features/session_replay/shared/replay-mode.js +0 -23
- package/dist/esm/features/utils/handler-cache.js +0 -63
- package/dist/types/features/session_replay/shared/replay-mode.d.ts +0 -9
- package/dist/types/features/session_replay/shared/replay-mode.d.ts.map +0 -1
- package/dist/types/features/utils/handler-cache.d.ts +0 -23
- package/dist/types/features/utils/handler-cache.d.ts.map +0 -1
- package/src/features/session_replay/shared/replay-mode.js +0 -23
- package/src/features/utils/handler-cache.js +0 -65
|
@@ -118,8 +118,6 @@ export class Aggregate extends AggregateBase {
|
|
|
118
118
|
if (this.resourcesSent) return;
|
|
119
119
|
this.resourcesSent = true; // make sure this only gets sent once
|
|
120
120
|
|
|
121
|
-
const agentRuntime = getRuntime(this.agentIdentifier);
|
|
122
|
-
|
|
123
121
|
// Capture SMs around network resources using the performance API to assess
|
|
124
122
|
// work to split this out from the ST nodes
|
|
125
123
|
// differentiate between internal+external and ajax+non-ajax
|
|
@@ -140,12 +138,6 @@ export class Aggregate extends AggregateBase {
|
|
|
140
138
|
}
|
|
141
139
|
});
|
|
142
140
|
|
|
143
|
-
// Capture SMs for session trace if active (`ptid` is set when returned by replay ingest).
|
|
144
|
-
// Retain these SMs while we are working through the session_replay feature
|
|
145
|
-
if (agentRuntime.ptid) {
|
|
146
|
-
this.storeSupportabilityMetrics('PageSession/Feature/SessionTrace/DurationMs', Math.round(performance.now()));
|
|
147
|
-
}
|
|
148
|
-
|
|
149
141
|
// Capture SMs for performance markers and measures to assess the usage and possible inclusion of this
|
|
150
142
|
// data in the agent for use in NR
|
|
151
143
|
if (typeof performance !== 'undefined') {
|
|
@@ -24,7 +24,7 @@ export class Aggregate extends AggregateBase {
|
|
|
24
24
|
this.timeToFirstByte = 0;
|
|
25
25
|
this.firstByteToWindowLoad = 0; // our "frontend" duration
|
|
26
26
|
this.firstByteToDomContent = 0; // our "dom processing" duration
|
|
27
|
-
|
|
27
|
+
this.timeKeeper = new TimeKeeper(this.agentIdentifier);
|
|
28
28
|
if (isBrowserScope) {
|
|
29
29
|
timeToFirstByte.subscribe(_ref => {
|
|
30
30
|
let {
|
|
@@ -110,6 +110,9 @@ export class Aggregate extends AggregateBase {
|
|
|
110
110
|
}
|
|
111
111
|
queryParameters.fp = firstPaint.current.value;
|
|
112
112
|
queryParameters.fcp = firstContentfulPaint.current.value;
|
|
113
|
+
if (this.timeKeeper?.ready) {
|
|
114
|
+
queryParameters.timestamp = this.timeKeeper.convertRelativeTimestamp(now());
|
|
115
|
+
}
|
|
113
116
|
const rumStartTime = now();
|
|
114
117
|
harvester.send({
|
|
115
118
|
endpoint: 'rum',
|
|
@@ -134,15 +137,14 @@ export class Aggregate extends AggregateBase {
|
|
|
134
137
|
return;
|
|
135
138
|
}
|
|
136
139
|
try {
|
|
137
|
-
|
|
138
|
-
timeKeeper.
|
|
139
|
-
|
|
140
|
-
agentRuntime.timeKeeper = timeKeeper;
|
|
140
|
+
this.timeKeeper.processRumRequest(xhr, rumStartTime, rumEndTime);
|
|
141
|
+
if (!this.timeKeeper.ready) throw new Error('TimeKeeper not ready');
|
|
142
|
+
agentRuntime.timeKeeper = this.timeKeeper;
|
|
141
143
|
} catch (error) {
|
|
142
144
|
handle(SUPPORTABILITY_METRIC_CHANNEL, ['PVE/NRTime/Calculation/Failed'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
143
145
|
drain(this.agentIdentifier, FEATURE_NAMES.metrics, true);
|
|
144
146
|
this.ee.abort();
|
|
145
|
-
warn('Could not calculate New Relic server time. Agent shutting down.');
|
|
147
|
+
warn('Could not calculate New Relic server time. Agent shutting down.', error);
|
|
146
148
|
return;
|
|
147
149
|
}
|
|
148
150
|
try {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { registerHandler } from '../../../common/event-emitter/register-handler';
|
|
14
14
|
import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler';
|
|
15
|
-
import { ABORT_REASONS, FEATURE_NAME, MAX_PAYLOAD_SIZE, QUERY_PARAM_PADDING, RRWEB_EVENT_TYPES, SR_EVENT_EMITTER_TYPES } from '../constants';
|
|
15
|
+
import { ABORT_REASONS, FEATURE_NAME, MAX_PAYLOAD_SIZE, QUERY_PARAM_PADDING, RRWEB_EVENT_TYPES, SR_EVENT_EMITTER_TYPES, TRIGGERS } from '../constants';
|
|
16
16
|
import { getConfigurationValue, getInfo, getRuntime } from '../../../common/config/config';
|
|
17
17
|
import { AggregateBase } from '../../utils/aggregate-base';
|
|
18
18
|
import { sharedChannel } from '../../../common/constants/shared-channel';
|
|
@@ -91,15 +91,6 @@ export class Aggregate extends AggregateBase {
|
|
|
91
91
|
getPayload: this.prepareHarvest.bind(this),
|
|
92
92
|
raw: true
|
|
93
93
|
}, this);
|
|
94
|
-
registerHandler(SR_EVENT_EMITTER_TYPES.RECORD, () => {
|
|
95
|
-
// if it has aborted or BCS returned bad entitlements, do not allow
|
|
96
|
-
if (this.blocked || !this.entitled) return;
|
|
97
|
-
// if it isnt already (fully) initialized... initialize it
|
|
98
|
-
if (!this.recorder) this.initializeRecording(false, true, true);
|
|
99
|
-
// its been initialized and imported the recorder but its not recording (mode === off || error)
|
|
100
|
-
else if (this.mode !== MODE.FULL) this.switchToFull();
|
|
101
|
-
// if it gets all the way to here, that means a full session is already recording... do nothing
|
|
102
|
-
}, this.featureName, this.ee);
|
|
103
94
|
registerHandler(SR_EVENT_EMITTER_TYPES.PAUSE, () => {
|
|
104
95
|
this.forceStop(this.mode !== MODE.ERROR);
|
|
105
96
|
}, this.featureName, this.ee);
|
|
@@ -117,9 +108,9 @@ export class Aggregate extends AggregateBase {
|
|
|
117
108
|
inline_images,
|
|
118
109
|
collect_fonts
|
|
119
110
|
} = getConfigurationValue(this.agentIdentifier, 'session_replay');
|
|
120
|
-
this.waitForFlags(['sr']).then(_ref => {
|
|
121
|
-
let [
|
|
122
|
-
this.entitled =
|
|
111
|
+
this.waitForFlags(['srs', 'sr']).then(_ref => {
|
|
112
|
+
let [srMode, entitled] = _ref;
|
|
113
|
+
this.entitled = !!entitled;
|
|
123
114
|
if (!this.entitled) {
|
|
124
115
|
deregisterDrain(this.agentIdentifier, this.featureName);
|
|
125
116
|
if (this.recorder?.recording) {
|
|
@@ -129,11 +120,14 @@ export class Aggregate extends AggregateBase {
|
|
|
129
120
|
return;
|
|
130
121
|
}
|
|
131
122
|
this.drain();
|
|
132
|
-
this.initializeRecording(
|
|
123
|
+
this.initializeRecording(srMode);
|
|
133
124
|
}).then(() => {
|
|
134
|
-
if (this.mode === MODE.OFF)
|
|
135
|
-
|
|
136
|
-
|
|
125
|
+
if (this.mode === MODE.OFF) {
|
|
126
|
+
this.recorder?.stopRecording(); // stop any conservative preload recording launched by instrument
|
|
127
|
+
while (this.recorder?.getEvents().events.length) this.recorder?.clearBuffer?.();
|
|
128
|
+
}
|
|
129
|
+
sharedChannel.onReplayReady(this.mode);
|
|
130
|
+
}); // notify watchers that replay started with the mode
|
|
137
131
|
|
|
138
132
|
/** Detect if the default configs have been altered and report a SM. This is useful to evaluate what the reasonable defaults are across a customer base over time */
|
|
139
133
|
if (!autoStart) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/AutoStart/Modified'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
@@ -176,7 +170,7 @@ export class Aggregate extends AggregateBase {
|
|
|
176
170
|
* @param {boolean} ignoreSession - whether to force the method to ignore the session state and use just the sample flags
|
|
177
171
|
* @returns {void}
|
|
178
172
|
*/
|
|
179
|
-
async initializeRecording(
|
|
173
|
+
async initializeRecording(srMode, ignoreSession) {
|
|
180
174
|
this.initialized = true;
|
|
181
175
|
if (!this.entitled) return;
|
|
182
176
|
|
|
@@ -191,23 +185,17 @@ export class Aggregate extends AggregateBase {
|
|
|
191
185
|
timeKeeper
|
|
192
186
|
} = getRuntime(this.agentIdentifier);
|
|
193
187
|
this.timeKeeper = timeKeeper;
|
|
194
|
-
if (
|
|
188
|
+
if (this.recorder?.parent.trigger === TRIGGERS.API && this.recorder?.recording) {
|
|
189
|
+
this.mode = MODE.FULL;
|
|
190
|
+
} else if (!session.isNew && !ignoreSession) {
|
|
195
191
|
// inherit the mode of the existing session
|
|
196
192
|
this.mode = session.state.sessionReplayMode;
|
|
197
193
|
} else {
|
|
198
194
|
// The session is new... determine the mode the new session should start in
|
|
199
|
-
|
|
200
|
-
else if (errorSample) this.mode = MODE.ERROR;
|
|
201
|
-
// If neither are selected, then don't record (early return)
|
|
202
|
-
else {
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
if (this.recorder?.getEvents().type === 'preloaded') {
|
|
207
|
-
this.prepUtils().then(() => {
|
|
208
|
-
this.scheduler.runHarvest();
|
|
209
|
-
});
|
|
195
|
+
this.mode = srMode;
|
|
210
196
|
}
|
|
197
|
+
// If off, then don't record (early return)
|
|
198
|
+
if (this.mode === MODE.OFF) return;
|
|
211
199
|
if (!this.recorder) {
|
|
212
200
|
try {
|
|
213
201
|
// Do not change the webpackChunkName or it will break the webpack nrba-chunking plugin
|
|
@@ -225,13 +213,20 @@ export class Aggregate extends AggregateBase {
|
|
|
225
213
|
|
|
226
214
|
// If an error was noticed before the mode could be set (like in the early lifecycle of the page), immediately set to FULL mode
|
|
227
215
|
if (this.mode === MODE.ERROR && this.errorNoticed) this.mode = MODE.FULL;
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
216
|
+
if (this.mode === MODE.FULL) {
|
|
217
|
+
// If theres preloaded events and we are in full mode, just harvest immediately to clear up space and for consistency
|
|
218
|
+
if (this.recorder?.getEvents().type === 'preloaded') {
|
|
219
|
+
this.prepUtils().then(() => {
|
|
220
|
+
this.scheduler.runHarvest();
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
// FULL mode records AND reports from the beginning, while ERROR mode only records (but does not report).
|
|
224
|
+
// ERROR mode will do this until an error is thrown, and then switch into FULL mode.
|
|
225
|
+
// If an error happened in ERROR mode before we've gotten to this stage, it will have already set the mode to FULL
|
|
226
|
+
if (!this.scheduler.started) {
|
|
227
|
+
// We only report (harvest) in FULL mode
|
|
228
|
+
this.scheduler.startTimer(this.harvestTimeSeconds);
|
|
229
|
+
}
|
|
235
230
|
}
|
|
236
231
|
await this.prepUtils();
|
|
237
232
|
if (!this.recorder.recording) this.recorder.startRecording();
|
|
@@ -12,10 +12,11 @@
|
|
|
12
12
|
import { handle } from '../../../common/event-emitter/handle';
|
|
13
13
|
import { DEFAULT_KEY, MODE, PREFIX } from '../../../common/session/constants';
|
|
14
14
|
import { InstrumentBase } from '../../utils/instrument-base';
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
15
|
+
import { hasReplayPrerequisite, isPreloadAllowed } from '../shared/utils';
|
|
16
|
+
import { FEATURE_NAME, SR_EVENT_EMITTER_TYPES, TRIGGERS } from '../constants';
|
|
17
17
|
export class Instrument extends InstrumentBase {
|
|
18
18
|
static featureName = FEATURE_NAME;
|
|
19
|
+
#mode;
|
|
19
20
|
constructor(agentIdentifier, aggregator) {
|
|
20
21
|
let auto = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
21
22
|
super(agentIdentifier, aggregator, FEATURE_NAME, auto);
|
|
@@ -24,8 +25,12 @@ export class Instrument extends InstrumentBase {
|
|
|
24
25
|
try {
|
|
25
26
|
session = JSON.parse(localStorage.getItem("".concat(PREFIX, "_").concat(DEFAULT_KEY)));
|
|
26
27
|
} catch (err) {}
|
|
28
|
+
if (hasReplayPrerequisite(agentIdentifier)) {
|
|
29
|
+
this.ee.on('recordReplay', () => this.#apiStartOrRestartReplay());
|
|
30
|
+
}
|
|
27
31
|
if (this.#canPreloadRecorder(session)) {
|
|
28
|
-
this.#
|
|
32
|
+
this.#mode = session?.sessionReplayMode;
|
|
33
|
+
this.#preloadStartRecording();
|
|
29
34
|
} else {
|
|
30
35
|
this.importAggregator();
|
|
31
36
|
}
|
|
@@ -58,20 +63,55 @@ export class Instrument extends InstrumentBase {
|
|
|
58
63
|
return isPreloadAllowed(this.agentIdentifier);
|
|
59
64
|
}
|
|
60
65
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
#alreadyStarted = false;
|
|
67
|
+
/**
|
|
68
|
+
* This func is use for early pre-load recording prior to replay feature (agg) being loaded onto the page. It should only setup once, including if already called and in-progress.
|
|
69
|
+
*/
|
|
70
|
+
async #preloadStartRecording(trigger) {
|
|
71
|
+
if (this.#alreadyStarted) return;
|
|
72
|
+
this.#alreadyStarted = true;
|
|
73
|
+
try {
|
|
74
|
+
const {
|
|
75
|
+
Recorder
|
|
76
|
+
} = await import( /* webpackChunkName: "recorder" */'../shared/recorder');
|
|
77
|
+
|
|
78
|
+
// If startReplay() has been used by this point, we must record in full mode regardless of session preload:
|
|
79
|
+
// Note: recorder starts here with w/e the mode is at this time, but this may be changed later (see #apiStartOrRestartReplay else-case)
|
|
80
|
+
this.recorder ??= new Recorder({
|
|
81
|
+
mode: this.#mode,
|
|
82
|
+
agentIdentifier: this.agentIdentifier,
|
|
83
|
+
trigger,
|
|
84
|
+
ee: this.ee
|
|
85
|
+
});
|
|
86
|
+
this.recorder.startRecording();
|
|
87
|
+
this.abortHandler = this.recorder.stopRecording;
|
|
88
|
+
} catch (e) {}
|
|
72
89
|
this.importAggregator({
|
|
73
90
|
recorder: this.recorder,
|
|
74
91
|
errorNoticed: this.errorNoticed
|
|
75
92
|
});
|
|
76
93
|
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Called whenever startReplay API is used. That could occur any time, pre or post load.
|
|
97
|
+
*/
|
|
98
|
+
#apiStartOrRestartReplay() {
|
|
99
|
+
if (this.featAggregate) {
|
|
100
|
+
// post-load; there's possibly already an ongoing recording
|
|
101
|
+
if (this.featAggregate.mode !== MODE.FULL) this.featAggregate.initializeRecording(MODE.FULL, true);
|
|
102
|
+
} else {
|
|
103
|
+
// pre-load
|
|
104
|
+
this.#mode = MODE.FULL;
|
|
105
|
+
this.#preloadStartRecording(TRIGGERS.API);
|
|
106
|
+
// There's a race here wherein either:
|
|
107
|
+
// a. Recorder has not been initialized, and we've set the enforced mode, so we're good, or;
|
|
108
|
+
// b. Record has been initialized, possibly with the "wrong" mode, so we have to correct that + restart.
|
|
109
|
+
if (this.recorder && this.recorder.parent.mode !== MODE.FULL) {
|
|
110
|
+
this.recorder.parent.mode = MODE.FULL;
|
|
111
|
+
this.recorder.stopRecording();
|
|
112
|
+
this.recorder.startRecording();
|
|
113
|
+
this.abortHandler = this.recorder.stopRecording;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
77
117
|
}
|
|
@@ -95,7 +95,14 @@ export class Recorder {
|
|
|
95
95
|
inlineStylesheet: inline_stylesheet,
|
|
96
96
|
inlineImages: inline_images,
|
|
97
97
|
collectFonts: collect_fonts,
|
|
98
|
-
checkoutEveryNms: CHECKOUT_MS[this.parent.mode]
|
|
98
|
+
checkoutEveryNms: CHECKOUT_MS[this.parent.mode],
|
|
99
|
+
/** Emits errors thrown by rrweb directly before bubbling them up to the window */
|
|
100
|
+
errorHandler: err => {
|
|
101
|
+
/** capture rrweb errors as "internal" errors only */
|
|
102
|
+
this.parent.ee.emit('internal-error', [err]);
|
|
103
|
+
/** returning true informs rrweb to swallow the error instead of throwing it to the window */
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
99
106
|
});
|
|
100
107
|
this.stopRecording = () => {
|
|
101
108
|
this.recording = false;
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { getConfigurationValue, originals } from '../../../common/config/config';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
function hasReplayPrerequisite(agentId) {
|
|
2
|
+
import { canEnableSessionTracking } from '../../utils/feature-gates';
|
|
3
|
+
import { originTime } from '../../../common/constants/runtime';
|
|
4
|
+
export function hasReplayPrerequisite(agentId) {
|
|
7
5
|
return !!originals.MO &&
|
|
8
6
|
// Session Replay cannot work without Mutation Observer
|
|
9
|
-
|
|
7
|
+
canEnableSessionTracking(agentId) &&
|
|
10
8
|
// requires session tracking to be running (hence "session" replay...)
|
|
11
9
|
getConfigurationValue(agentId, 'session_trace.enabled') === true; // Session Replay as of now is tightly coupled with Session Trace in the UI
|
|
12
10
|
}
|