@newrelic/browser-agent 1.276.0 → 1.278.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/dist/cjs/common/aggregate/event-aggregator.js +1 -1
- package/dist/cjs/common/config/init.js +1 -10
- package/dist/cjs/common/config/runtime.js +2 -1
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/harvest/harvester.js +255 -0
- package/dist/cjs/common/harvest/types.js +5 -21
- package/dist/cjs/features/ajax/aggregate/index.js +2 -11
- package/dist/cjs/features/generic_events/aggregate/index.js +17 -13
- package/dist/cjs/features/generic_events/constants.js +2 -1
- package/dist/cjs/features/jserrors/aggregate/index.js +3 -14
- package/dist/cjs/features/logging/aggregate/index.js +4 -12
- package/dist/cjs/features/metrics/aggregate/index.js +7 -15
- package/dist/cjs/features/page_view_event/aggregate/index.js +46 -48
- package/dist/cjs/features/page_view_timing/aggregate/index.js +0 -9
- package/dist/cjs/features/session_replay/aggregate/index.js +21 -43
- package/dist/cjs/features/session_replay/instrument/index.js +2 -1
- package/dist/cjs/features/session_replay/shared/recorder.js +6 -6
- package/dist/cjs/features/session_trace/aggregate/index.js +9 -24
- package/dist/cjs/features/session_trace/aggregate/trace/storage.js +8 -2
- package/dist/cjs/features/soft_navigations/aggregate/index.js +31 -21
- package/dist/cjs/features/soft_navigations/aggregate/initial-page-load-interaction.js +2 -1
- package/dist/cjs/features/soft_navigations/aggregate/interaction.js +12 -12
- package/dist/cjs/features/soft_navigations/constants.js +5 -2
- package/dist/cjs/features/spa/aggregate/index.js +7 -10
- package/dist/cjs/features/utils/aggregate-base.js +66 -27
- package/dist/cjs/features/utils/event-buffer.js +0 -1
- package/dist/cjs/features/utils/event-store-manager.js +109 -0
- package/dist/cjs/features/utils/instrument-base.js +1 -10
- package/dist/cjs/loaders/api/api-methods.js +1 -1
- package/dist/cjs/loaders/api/api.js +2 -1
- package/dist/cjs/loaders/features/features.js +16 -10
- package/dist/cjs/loaders/micro-agent-base.js +10 -0
- package/dist/cjs/loaders/micro-agent.js +1 -0
- package/dist/esm/common/aggregate/event-aggregator.js +1 -1
- package/dist/esm/common/config/init.js +1 -10
- package/dist/esm/common/config/runtime.js +2 -1
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/harvest/harvester.js +249 -0
- package/dist/esm/common/harvest/types.js +5 -21
- package/dist/esm/features/ajax/aggregate/index.js +3 -12
- package/dist/esm/features/generic_events/aggregate/index.js +18 -14
- package/dist/esm/features/generic_events/constants.js +1 -0
- package/dist/esm/features/jserrors/aggregate/index.js +4 -15
- package/dist/esm/features/logging/aggregate/index.js +4 -12
- package/dist/esm/features/metrics/aggregate/index.js +7 -15
- package/dist/esm/features/page_view_event/aggregate/index.js +46 -48
- package/dist/esm/features/page_view_timing/aggregate/index.js +1 -10
- package/dist/esm/features/session_replay/aggregate/index.js +22 -44
- package/dist/esm/features/session_replay/instrument/index.js +2 -1
- package/dist/esm/features/session_replay/shared/recorder.js +6 -6
- package/dist/esm/features/session_trace/aggregate/index.js +9 -24
- package/dist/esm/features/session_trace/aggregate/trace/storage.js +8 -2
- package/dist/esm/features/soft_navigations/aggregate/index.js +33 -23
- package/dist/esm/features/soft_navigations/aggregate/initial-page-load-interaction.js +2 -1
- package/dist/esm/features/soft_navigations/aggregate/interaction.js +13 -13
- package/dist/esm/features/soft_navigations/constants.js +4 -1
- package/dist/esm/features/spa/aggregate/index.js +8 -11
- package/dist/esm/features/utils/aggregate-base.js +66 -27
- package/dist/esm/features/utils/event-buffer.js +0 -1
- package/dist/esm/features/utils/event-store-manager.js +103 -0
- package/dist/esm/features/utils/instrument-base.js +1 -10
- package/dist/esm/loaders/api/api-methods.js +1 -1
- package/dist/esm/loaders/api/api.js +2 -1
- package/dist/esm/loaders/features/features.js +15 -9
- package/dist/esm/loaders/micro-agent-base.js +10 -0
- package/dist/esm/loaders/micro-agent.js +1 -0
- package/dist/types/common/aggregate/event-aggregator.d.ts +1 -1
- package/dist/types/common/aggregate/event-aggregator.d.ts.map +1 -1
- package/dist/types/common/config/init.d.ts.map +1 -1
- package/dist/types/common/config/runtime.d.ts.map +1 -1
- package/dist/types/common/harvest/harvester.d.ts +16 -0
- package/dist/types/common/harvest/harvester.d.ts.map +1 -0
- package/dist/types/common/harvest/types.d.ts +8 -45
- package/dist/types/common/harvest/types.d.ts.map +1 -1
- package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/generic_events/aggregate/index.d.ts +1 -3
- package/dist/types/features/generic_events/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/generic_events/constants.d.ts +1 -0
- package/dist/types/features/generic_events/constants.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/logging/aggregate/index.d.ts +0 -3
- package/dist/types/features/logging/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/metrics/aggregate/index.d.ts +1 -1
- package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_event/aggregate/index.d.ts +6 -2
- package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts +12 -15
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
- package/dist/types/features/session_trace/aggregate/index.d.ts +0 -5
- package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_trace/aggregate/trace/storage.d.ts +8 -5
- package/dist/types/features/session_trace/aggregate/trace/storage.d.ts.map +1 -1
- package/dist/types/features/soft_navigations/aggregate/index.d.ts +1 -0
- package/dist/types/features/soft_navigations/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/soft_navigations/aggregate/initial-page-load-interaction.d.ts.map +1 -1
- package/dist/types/features/soft_navigations/aggregate/interaction.d.ts +3 -3
- package/dist/types/features/soft_navigations/aggregate/interaction.d.ts.map +1 -1
- package/dist/types/features/soft_navigations/constants.d.ts +1 -0
- package/dist/types/features/soft_navigations/constants.d.ts.map +1 -1
- package/dist/types/features/spa/aggregate/index.d.ts +0 -1
- package/dist/types/features/spa/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/utils/aggregate-base.d.ts +12 -7
- package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
- package/dist/types/features/utils/event-buffer.d.ts +1 -2
- package/dist/types/features/utils/event-buffer.d.ts.map +1 -1
- package/dist/types/features/utils/event-store-manager.d.ts +43 -0
- package/dist/types/features/utils/event-store-manager.d.ts.map +1 -0
- package/dist/types/features/utils/instrument-base.d.ts +0 -1
- package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
- package/dist/types/loaders/api/api.d.ts +1 -0
- package/dist/types/loaders/api/api.d.ts.map +1 -1
- package/dist/types/loaders/features/features.d.ts +15 -12
- package/dist/types/loaders/features/features.d.ts.map +1 -1
- package/dist/types/loaders/micro-agent-base.d.ts +7 -0
- package/dist/types/loaders/micro-agent-base.d.ts.map +1 -1
- package/dist/types/loaders/micro-agent.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/common/aggregate/event-aggregator.js +1 -1
- package/src/common/config/init.js +9 -10
- package/src/common/config/runtime.js +2 -1
- package/src/common/harvest/__mocks__/harvester.js +6 -0
- package/src/common/harvest/harvester.js +230 -0
- package/src/common/harvest/types.js +5 -21
- package/src/features/ajax/aggregate/index.js +3 -14
- package/src/features/generic_events/aggregate/index.js +20 -17
- package/src/features/generic_events/constants.js +2 -0
- package/src/features/jserrors/aggregate/index.js +4 -11
- package/src/features/logging/aggregate/index.js +4 -12
- package/src/features/metrics/aggregate/index.js +5 -12
- package/src/features/page_view_event/aggregate/index.js +38 -38
- package/src/features/page_view_timing/aggregate/index.js +1 -12
- package/src/features/session_replay/aggregate/index.js +19 -42
- package/src/features/session_replay/instrument/index.js +1 -1
- package/src/features/session_replay/shared/recorder.js +6 -6
- package/src/features/session_trace/aggregate/index.js +8 -25
- package/src/features/session_trace/aggregate/trace/storage.js +5 -2
- package/src/features/soft_navigations/aggregate/index.js +26 -23
- package/src/features/soft_navigations/aggregate/initial-page-load-interaction.js +2 -1
- package/src/features/soft_navigations/aggregate/interaction.js +13 -12
- package/src/features/soft_navigations/constants.js +3 -1
- package/src/features/spa/aggregate/index.js +8 -11
- package/src/features/utils/aggregate-base.js +59 -27
- package/src/features/utils/event-buffer.js +0 -1
- package/src/features/utils/event-store-manager.js +101 -0
- package/src/features/utils/instrument-base.js +2 -8
- package/src/loaders/api/api-methods.js +1 -1
- package/src/loaders/api/api.js +3 -1
- package/src/loaders/features/features.js +16 -9
- package/src/loaders/micro-agent-base.js +10 -0
- package/src/loaders/micro-agent.js +1 -0
- package/dist/cjs/common/harvest/harvest-scheduler.js +0 -168
- package/dist/cjs/common/harvest/harvest.js +0 -295
- package/dist/esm/common/harvest/harvest-scheduler.js +0 -160
- package/dist/esm/common/harvest/harvest.js +0 -286
- package/dist/types/common/harvest/harvest-scheduler.d.ts +0 -50
- package/dist/types/common/harvest/harvest-scheduler.d.ts.map +0 -1
- package/dist/types/common/harvest/harvest.d.ts +0 -65
- package/dist/types/common/harvest/harvest.d.ts.map +0 -1
- package/src/common/harvest/__mocks__/harvest.js +0 -13
- package/src/common/harvest/harvest-scheduler.js +0 -166
- package/src/common/harvest/harvest.js +0 -282
|
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.Aggregate = void 0;
|
|
7
7
|
var _handle = require("../../../common/event-emitter/handle");
|
|
8
8
|
var _registerHandler = require("../../../common/event-emitter/register-handler");
|
|
9
|
-
var _harvestScheduler = require("../../../common/harvest/harvest-scheduler");
|
|
10
9
|
var _console = require("../../../common/util/console");
|
|
11
10
|
var _stringify = require("../../../common/util/stringify");
|
|
12
11
|
var _constants = require("../../metrics/constants");
|
|
@@ -16,24 +15,17 @@ var _log = require("../shared/log");
|
|
|
16
15
|
var _utils = require("../shared/utils");
|
|
17
16
|
var _traverse = require("../../../common/util/traverse");
|
|
18
17
|
var _agentConstants = require("../../../common/constants/agent-constants");
|
|
19
|
-
var _features = require("../../../loaders/features/features");
|
|
20
18
|
class Aggregate extends _aggregateBase.AggregateBase {
|
|
21
19
|
static featureName = _constants2.FEATURE_NAME;
|
|
22
20
|
constructor(agentRef) {
|
|
23
21
|
super(agentRef, _constants2.FEATURE_NAME);
|
|
24
|
-
this.
|
|
22
|
+
this.harvestOpts.raw = true;
|
|
25
23
|
this.waitForFlags([]).then(() => {
|
|
26
|
-
this.scheduler = new _harvestScheduler.HarvestScheduler(_features.FEATURE_TO_ENDPOINT[this.featureName], {
|
|
27
|
-
onFinished: result => this.postHarvestCleanup(result.sent && result.retry),
|
|
28
|
-
retryDelay: this.harvestTimeSeconds,
|
|
29
|
-
getPayload: options => this.makeHarvestPayload(options.retry),
|
|
30
|
-
raw: true
|
|
31
|
-
}, this);
|
|
32
24
|
/** emitted by instrument class (wrapped loggers) or the api methods directly */
|
|
33
25
|
(0, _registerHandler.registerHandler)(_constants2.LOGGING_EVENT_EMITTER_CHANNEL, this.handleLog.bind(this), this.featureName, this.ee);
|
|
34
26
|
this.drain();
|
|
35
27
|
/** harvest immediately once started to purge pre-load logs collected */
|
|
36
|
-
|
|
28
|
+
agentRef.runtime.harvester.triggerHarvestFor(this);
|
|
37
29
|
});
|
|
38
30
|
}
|
|
39
31
|
handleLog(timestamp, message, attributes = {}, level = _constants2.LOG_LEVELS.INFO) {
|
|
@@ -67,8 +59,8 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
67
59
|
return;
|
|
68
60
|
}
|
|
69
61
|
if (this.events.wouldExceedMaxSize(logBytes)) {
|
|
70
|
-
(0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ['Logging/Harvest/Early/Seen', this.events.
|
|
71
|
-
this.
|
|
62
|
+
(0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ['Logging/Harvest/Early/Seen', this.events.byteSize() + logBytes]);
|
|
63
|
+
this.agentRef.runtime.harvester.triggerHarvestFor(this); // force a harvest synchronously to try adding again
|
|
72
64
|
}
|
|
73
65
|
if (!this.events.add(log)) {
|
|
74
66
|
// still failed after a harvest attempt despite not being too large would mean harvest failed with options.retry
|
|
@@ -5,7 +5,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.Aggregate = void 0;
|
|
7
7
|
var _registerHandler = require("../../../common/event-emitter/register-handler");
|
|
8
|
-
var _harvestScheduler = require("../../../common/harvest/harvest-scheduler");
|
|
9
8
|
var _constants = require("../constants");
|
|
10
9
|
var _frameworkDetection = require("./framework-detection");
|
|
11
10
|
var _protocol = require("../../../common/url/protocol");
|
|
@@ -13,7 +12,6 @@ var _load = require("../../../common/window/load");
|
|
|
13
12
|
var _eventListenerOpts = require("../../../common/event-listener/event-listener-opts");
|
|
14
13
|
var _runtime = require("../../../common/constants/runtime");
|
|
15
14
|
var _aggregateBase = require("../../utils/aggregate-base");
|
|
16
|
-
var _features = require("../../../loaders/features/features");
|
|
17
15
|
var _iframe = require("../../../common/dom/iframe");
|
|
18
16
|
// import { WEBSOCKET_TAG } from '../../../common/wrap/wrap-websocket'
|
|
19
17
|
// import { handleWebsocketEvents } from './websocket-detection'
|
|
@@ -22,18 +20,11 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
22
20
|
static featureName = _constants.FEATURE_NAME;
|
|
23
21
|
constructor(agentRef) {
|
|
24
22
|
super(agentRef, _constants.FEATURE_NAME);
|
|
25
|
-
|
|
23
|
+
this.harvestOpts.aggregatorTypes = ['cm', 'sm']; // the types in EventAggregator this feature cares about
|
|
24
|
+
// This feature only harvests once per potential EoL of the page, which is handled by the central harvester.
|
|
26
25
|
|
|
27
26
|
this.waitForFlags(['err']).then(([errFlag]) => {
|
|
28
27
|
if (errFlag) {
|
|
29
|
-
// *cli, Mar 23 - Per NR-94597, this feature should only harvest ONCE at the (potential) EoL time of the page.
|
|
30
|
-
const scheduler = new _harvestScheduler.HarvestScheduler(_features.FEATURE_TO_ENDPOINT[this.featureName], {
|
|
31
|
-
onUnload: () => this.unload()
|
|
32
|
-
}, this);
|
|
33
|
-
// this is needed to ensure EoL is "on" and sent
|
|
34
|
-
scheduler.harvest.on(_features.FEATURE_TO_ENDPOINT[this.featureName], () => this.makeHarvestPayload(undefined, {
|
|
35
|
-
aggregatorTypes
|
|
36
|
-
}));
|
|
37
28
|
this.drain();
|
|
38
29
|
} else {
|
|
39
30
|
this.blocked = true; // if rum response determines that customer lacks entitlements for spa endpoint, this feature shouldn't harvest
|
|
@@ -47,6 +38,10 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
47
38
|
this.singleChecks(); // checks that are run only one time, at script load
|
|
48
39
|
this.eachSessionChecks(); // the start of every time user engages with page
|
|
49
40
|
}
|
|
41
|
+
preHarvestChecks() {
|
|
42
|
+
return this.drained;
|
|
43
|
+
} // only allow any metrics to be sent if we know for sure it has gotten the go-ahead RUM flag
|
|
44
|
+
|
|
50
45
|
storeSupportabilityMetrics(name, value) {
|
|
51
46
|
if (this.blocked) return;
|
|
52
47
|
const type = _constants.SUPPORTABILITY_METRIC;
|
|
@@ -61,7 +56,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
61
56
|
const params = {
|
|
62
57
|
name
|
|
63
58
|
};
|
|
64
|
-
this.events.add(type, name, params, metrics);
|
|
59
|
+
this.events.add([type, name, params, metrics]);
|
|
65
60
|
}
|
|
66
61
|
singleChecks() {
|
|
67
62
|
// report loaderType
|
|
@@ -153,8 +148,5 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
153
148
|
}
|
|
154
149
|
});
|
|
155
150
|
}
|
|
156
|
-
unload() {
|
|
157
|
-
// do nothing for now, marks and measures and resources stats are now being captured by the ge feature
|
|
158
|
-
}
|
|
159
151
|
}
|
|
160
152
|
exports.Aggregate = Aggregate;
|
|
@@ -8,7 +8,6 @@ var _runtime = require("../../../common/constants/runtime");
|
|
|
8
8
|
var _navTiming = require("../../../common/timing/nav-timing");
|
|
9
9
|
var _stringify = require("../../../common/util/stringify");
|
|
10
10
|
var _info = require("../../../common/config/info");
|
|
11
|
-
var _harvest = require("../../../common/harvest/harvest");
|
|
12
11
|
var CONSTANTS = _interopRequireWildcard(require("../constants"));
|
|
13
12
|
var _initializedFeatures = require("./initialized-features");
|
|
14
13
|
var _featureFlags = require("../../../common/util/feature-flags");
|
|
@@ -29,11 +28,12 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
29
28
|
this.timeToFirstByte = 0;
|
|
30
29
|
this.firstByteToWindowLoad = 0; // our "frontend" duration
|
|
31
30
|
this.firstByteToDomContent = 0; // our "dom processing" duration
|
|
32
|
-
|
|
31
|
+
|
|
33
32
|
if (!(0, _info.isValid)(agentRef.agentIdentifier)) {
|
|
34
33
|
this.ee.abort();
|
|
35
34
|
return (0, _console.warn)(43);
|
|
36
35
|
}
|
|
36
|
+
agentRef.runtime.timeKeeper = new _timeKeeper.TimeKeeper(agentRef.agentIdentifier);
|
|
37
37
|
if (_runtime.isBrowserScope) {
|
|
38
38
|
_timeToFirstByte.timeToFirstByte.subscribe(({
|
|
39
39
|
value,
|
|
@@ -53,7 +53,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
53
53
|
}
|
|
54
54
|
sendRum() {
|
|
55
55
|
const info = this.agentRef.info;
|
|
56
|
-
const harvester = new _harvest.Harvest(this);
|
|
57
56
|
const measures = {};
|
|
58
57
|
if (info.queueTime) measures.qt = info.queueTime;
|
|
59
58
|
if (info.applicationTime) measures.ap = info.applicationTime;
|
|
@@ -103,54 +102,53 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
103
102
|
}
|
|
104
103
|
queryParameters.fp = _firstPaint.firstPaint.current.value;
|
|
105
104
|
queryParameters.fcp = _firstContentfulPaint.firstContentfulPaint.current.value;
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
const timeKeeper = this.agentRef.runtime.timeKeeper;
|
|
106
|
+
if (timeKeeper?.ready) {
|
|
107
|
+
queryParameters.timestamp = Math.floor(timeKeeper.correctRelativeTimestamp((0, _now.now)()));
|
|
108
108
|
}
|
|
109
|
-
|
|
110
|
-
harvester.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
opts: {
|
|
117
|
-
needResponse: true,
|
|
118
|
-
sendEmptyBody: true
|
|
119
|
-
},
|
|
120
|
-
cbFinished: ({
|
|
121
|
-
status,
|
|
122
|
-
responseText,
|
|
123
|
-
xhr
|
|
124
|
-
}) => {
|
|
125
|
-
const rumEndTime = (0, _now.now)();
|
|
126
|
-
if (status >= 400 || status === 0) {
|
|
127
|
-
// Adding retry logic for the rum call will be a separate change
|
|
128
|
-
this.ee.abort();
|
|
129
|
-
return;
|
|
109
|
+
this.rumStartTime = (0, _now.now)();
|
|
110
|
+
this.agentRef.runtime.harvester.triggerHarvestFor(this, {
|
|
111
|
+
directSend: {
|
|
112
|
+
targetApp: this.agentRef.mainAppKey,
|
|
113
|
+
payload: {
|
|
114
|
+
qs: queryParameters,
|
|
115
|
+
body
|
|
130
116
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
...flags
|
|
135
|
-
} = JSON.parse(responseText);
|
|
136
|
-
try {
|
|
137
|
-
this.timeKeeper.processRumRequest(xhr, rumStartTime, rumEndTime, app.nrServerTime);
|
|
138
|
-
if (!this.timeKeeper.ready) throw new Error('TimeKeeper not ready');
|
|
139
|
-
this.agentRef.runtime.timeKeeper = this.timeKeeper;
|
|
140
|
-
} catch (error) {
|
|
141
|
-
this.ee.abort();
|
|
142
|
-
(0, _console.warn)(17, error);
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
this.agentRef.runtime.appMetadata = app;
|
|
146
|
-
(0, _featureFlags.activateFeatures)(flags, this.agentIdentifier);
|
|
147
|
-
this.drain();
|
|
148
|
-
} catch (err) {
|
|
149
|
-
this.ee.abort();
|
|
150
|
-
(0, _console.warn)(18, err);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
117
|
+
},
|
|
118
|
+
needResponse: true,
|
|
119
|
+
sendEmptyBody: true
|
|
153
120
|
});
|
|
154
121
|
}
|
|
122
|
+
postHarvestCleanup({
|
|
123
|
+
status,
|
|
124
|
+
responseText,
|
|
125
|
+
xhr
|
|
126
|
+
}) {
|
|
127
|
+
const rumEndTime = (0, _now.now)();
|
|
128
|
+
this.blocked = true; // this prevents harvester from polling this feature's event buffer (DNE) on interval; in other words, harvests will skip PVE
|
|
129
|
+
|
|
130
|
+
if (status >= 400 || status === 0) {
|
|
131
|
+
(0, _console.warn)(18, status);
|
|
132
|
+
// Adding retry logic for the rum call will be a separate change; this.blocked will need to be changed since that prevents another triggerHarvestFor()
|
|
133
|
+
this.ee.abort();
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const {
|
|
137
|
+
app,
|
|
138
|
+
...flags
|
|
139
|
+
} = JSON.parse(responseText);
|
|
140
|
+
try {
|
|
141
|
+
this.agentRef.runtime.timeKeeper.processRumRequest(xhr, this.rumStartTime, rumEndTime, app.nrServerTime);
|
|
142
|
+
if (!this.agentRef.runtime.timeKeeper.ready) throw new Error('TimeKeeper not ready');
|
|
143
|
+
} catch (error) {
|
|
144
|
+
this.ee.abort();
|
|
145
|
+
(0, _console.warn)(17, error);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
this.agentRef.runtime.appMetadata = app;
|
|
149
|
+
(0, _featureFlags.activateFeatures)(flags, this.agentIdentifier);
|
|
150
|
+
this.drain();
|
|
151
|
+
this.agentRef.runtime.harvester.startTimer();
|
|
152
|
+
}
|
|
155
153
|
}
|
|
156
154
|
exports.Aggregate = Aggregate;
|
|
@@ -5,7 +5,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.Aggregate = void 0;
|
|
7
7
|
var _belSerializer = require("../../../common/serialize/bel-serializer");
|
|
8
|
-
var _harvestScheduler = require("../../../common/harvest/harvest-scheduler");
|
|
9
8
|
var _registerHandler = require("../../../common/event-emitter/register-handler");
|
|
10
9
|
var _handle = require("../../../common/event-emitter/handle");
|
|
11
10
|
var _constants = require("../constants");
|
|
@@ -40,10 +39,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
40
39
|
(0, _registerHandler.registerHandler)('docHidden', msTimestamp => this.endCurrentSession(msTimestamp), this.featureName, this.ee);
|
|
41
40
|
// Add the time of _window pagehide event_ firing to the next PVT harvest == NRDB windowUnload attr:
|
|
42
41
|
(0, _registerHandler.registerHandler)('winPagehide', msTimestamp => this.addTiming('unload', msTimestamp, null), this.featureName, this.ee);
|
|
43
|
-
const harvestTimeSeconds = agentRef.init.page_view_timing.harvestTimeSeconds || 30;
|
|
44
42
|
this.waitForFlags([]).then(() => {
|
|
45
|
-
/* It's important that CWV api, like "onLCP", is called before the **scheduler** is initialized. The reason is because they listen to the same
|
|
46
|
-
on vis change or pagehide events, and we'd want ex. onLCP to record the timing (win the race) before we try to send "final harvest". */
|
|
47
43
|
_firstPaint.firstPaint.subscribe(this.#handleVitalMetric);
|
|
48
44
|
_firstContentfulPaint.firstContentfulPaint.subscribe(this.#handleVitalMetric);
|
|
49
45
|
_firstInputDelay.firstInputDelay.subscribe(this.#handleVitalMetric);
|
|
@@ -67,11 +63,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
67
63
|
this.addTiming(name, value * 1000, attrs);
|
|
68
64
|
}, true); // CLS node should only reports on vis change rather than on every change
|
|
69
65
|
|
|
70
|
-
const scheduler = new _harvestScheduler.HarvestScheduler(_features.FEATURE_TO_ENDPOINT[this.featureName], {
|
|
71
|
-
onFinished: result => this.postHarvestCleanup(result.sent && result.retry),
|
|
72
|
-
getPayload: options => this.makeHarvestPayload(options.retry)
|
|
73
|
-
}, this);
|
|
74
|
-
scheduler.startTimer(harvestTimeSeconds);
|
|
75
66
|
this.drain();
|
|
76
67
|
});
|
|
77
68
|
}
|
|
@@ -5,7 +5,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.Aggregate = void 0;
|
|
7
7
|
var _registerHandler = require("../../../common/event-emitter/register-handler");
|
|
8
|
-
var _harvestScheduler = require("../../../common/harvest/harvest-scheduler");
|
|
9
8
|
var _constants = require("../constants");
|
|
10
9
|
var _aggregateBase = require("../../utils/aggregate-base");
|
|
11
10
|
var _sharedChannel = require("../../../common/constants/shared-channel");
|
|
@@ -37,8 +36,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
37
36
|
// pass the recorder into the aggregator
|
|
38
37
|
constructor(agentRef, args) {
|
|
39
38
|
super(agentRef, _constants.FEATURE_NAME);
|
|
40
|
-
/** The interval to harvest at. This gets overridden if the size of the payload exceeds certain thresholds */
|
|
41
|
-
this.harvestTimeSeconds = agentRef.init.session_replay.harvestTimeSeconds || 60;
|
|
42
39
|
/** Set once the recorder has fully initialized after flag checks and sampling */
|
|
43
40
|
this.initialized = false;
|
|
44
41
|
/** Set once the feature has been "aborted" to prevent other side-effects from continuing */
|
|
@@ -54,6 +51,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
54
51
|
this.timeKeeper = undefined;
|
|
55
52
|
this.recorder = args?.recorder;
|
|
56
53
|
this.errorNoticed = args?.errorNoticed || false;
|
|
54
|
+
this.harvestOpts.raw = true;
|
|
57
55
|
(0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/Enabled'], undefined, _features.FEATURE_NAMES.metrics, this.ee);
|
|
58
56
|
|
|
59
57
|
// 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.
|
|
@@ -78,19 +76,8 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
78
76
|
if (this.mode !== _constants3.MODE.OFF && data.sessionReplayMode === _constants3.MODE.OFF) this.abort(_constants.ABORT_REASONS.CROSS_TAB);
|
|
79
77
|
this.mode = data.sessionReplay;
|
|
80
78
|
});
|
|
81
|
-
|
|
82
|
-
// Bespoke logic for blobs endpoint.
|
|
83
|
-
this.scheduler = new _harvestScheduler.HarvestScheduler(_features.FEATURE_TO_ENDPOINT[this.featureName], {
|
|
84
|
-
onFinished: result => this.postHarvestCleanup(result),
|
|
85
|
-
retryDelay: this.harvestTimeSeconds,
|
|
86
|
-
getPayload: ({
|
|
87
|
-
retry,
|
|
88
|
-
...opts
|
|
89
|
-
}) => this.makeHarvestPayload(retry, opts),
|
|
90
|
-
raw: true
|
|
91
|
-
}, this);
|
|
92
79
|
(0, _registerHandler.registerHandler)(_constants.SR_EVENT_EMITTER_TYPES.PAUSE, () => {
|
|
93
|
-
this.forceStop(this.mode
|
|
80
|
+
this.forceStop(this.mode === _constants3.MODE.FULL);
|
|
94
81
|
}, this.featureName, this.ee);
|
|
95
82
|
(0, _registerHandler.registerHandler)(_constants.SR_EVENT_EMITTER_TYPES.ERROR_DURING_REPLAY, e => {
|
|
96
83
|
this.handleError(e);
|
|
@@ -136,7 +123,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
136
123
|
(0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/ErrorSamplingRate/Value', error_sampling_rate], undefined, _features.FEATURE_NAMES.metrics, this.ee);
|
|
137
124
|
}
|
|
138
125
|
replayIsActive() {
|
|
139
|
-
return Boolean(this.
|
|
126
|
+
return Boolean(this.recorder && this.mode === _constants3.MODE.FULL && !this.blocked && this.entitled);
|
|
140
127
|
}
|
|
141
128
|
handleError(e) {
|
|
142
129
|
if (this.recorder) this.recorder.currentBufferTarget.hasError = true;
|
|
@@ -151,20 +138,17 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
151
138
|
// if the error was noticed AFTER the recorder was already imported....
|
|
152
139
|
if (this.recorder && this.initialized) {
|
|
153
140
|
if (!this.recorder.recording) this.recorder.startRecording();
|
|
154
|
-
this.scheduler.startTimer(this.harvestTimeSeconds);
|
|
155
141
|
this.syncWithSessionManager({
|
|
156
142
|
sessionReplayMode: this.mode
|
|
157
143
|
});
|
|
158
144
|
} else {
|
|
159
|
-
this.initializeRecording(
|
|
145
|
+
this.initializeRecording(_constants3.MODE.FULL, true);
|
|
160
146
|
}
|
|
161
147
|
}
|
|
162
148
|
|
|
163
149
|
/**
|
|
164
150
|
* Evaluate entitlements and sampling before starting feature mechanics, importing and configuring recording library, and setting storage state
|
|
165
151
|
* @param {boolean} entitlements - the true/false state of the "sr" flag from RUM response
|
|
166
|
-
* @param {boolean} errorSample - the true/false state of the error sampling decision
|
|
167
|
-
* @param {boolean} fullSample - the true/false state of the full sampling decision
|
|
168
152
|
* @param {boolean} ignoreSession - whether to force the method to ignore the session state and use just the sample flags
|
|
169
153
|
* @returns {void}
|
|
170
154
|
*/
|
|
@@ -211,20 +195,14 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
211
195
|
|
|
212
196
|
// If an error was noticed before the mode could be set (like in the early lifecycle of the page), immediately set to FULL mode
|
|
213
197
|
if (this.mode === _constants3.MODE.ERROR && this.errorNoticed) this.mode = _constants3.MODE.FULL;
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
// ERROR mode will do this until an error is thrown, and then switch into FULL mode.
|
|
223
|
-
// If an error happened in ERROR mode before we've gotten to this stage, it will have already set the mode to FULL
|
|
224
|
-
if (!this.scheduler.started) {
|
|
225
|
-
// We only report (harvest) in FULL mode
|
|
226
|
-
this.scheduler.startTimer(this.harvestTimeSeconds);
|
|
227
|
-
}
|
|
198
|
+
|
|
199
|
+
// FULL mode records AND reports from the beginning, while ERROR mode only records (but does not report).
|
|
200
|
+
// ERROR mode will do this until an error is thrown, and then switch into FULL mode.
|
|
201
|
+
// The makeHarvestPayload should ensure that no payload is returned if we're not in FULL mode...
|
|
202
|
+
|
|
203
|
+
// If theres preloaded events and we are in full mode, just harvest immediately to clear up space and for consistency
|
|
204
|
+
if (this.mode === _constants3.MODE.FULL && this.recorder?.getEvents().type === 'preloaded') {
|
|
205
|
+
this.prepUtils().then(() => this.agentRef.runtime.harvester.triggerHarvestFor(this));
|
|
228
206
|
}
|
|
229
207
|
await this.prepUtils();
|
|
230
208
|
if (!this.recorder.recording) this.recorder.startRecording();
|
|
@@ -245,11 +223,12 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
245
223
|
// compressor failed to load, but we can still record without compression as a last ditch effort
|
|
246
224
|
}
|
|
247
225
|
}
|
|
248
|
-
makeHarvestPayload(shouldRetryOnFail
|
|
226
|
+
makeHarvestPayload(shouldRetryOnFail) {
|
|
227
|
+
if (this.mode !== _constants3.MODE.FULL || this.blocked) return;
|
|
249
228
|
if (!this.recorder || !this.timeKeeper?.ready || !this.recorder.hasSeenSnapshot) return;
|
|
250
229
|
const recorderEvents = this.recorder.getEvents();
|
|
251
230
|
// get the event type and use that to trigger another harvest if needed
|
|
252
|
-
if (!recorderEvents.events.length
|
|
231
|
+
if (!recorderEvents.events.length) return;
|
|
253
232
|
const payload = this.getHarvestContents(recorderEvents);
|
|
254
233
|
if (!payload.body.length) {
|
|
255
234
|
this.recorder.clearBuffer();
|
|
@@ -273,7 +252,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
273
252
|
return (0, _stringify.stringify)(output);
|
|
274
253
|
}).join(','), "]")));
|
|
275
254
|
len = payload.body.length;
|
|
276
|
-
this.scheduler.opts.gzip = true;
|
|
277
255
|
} else {
|
|
278
256
|
payload.body = payload.body.map(({
|
|
279
257
|
__serialized,
|
|
@@ -288,7 +266,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
288
266
|
return output;
|
|
289
267
|
});
|
|
290
268
|
len = (0, _stringify.stringify)(payload.body).length;
|
|
291
|
-
this.scheduler.opts.gzip = false;
|
|
292
269
|
}
|
|
293
270
|
if (len > _agentConstants.MAX_PAYLOAD_SIZE) {
|
|
294
271
|
this.abort(_constants.ABORT_REASONS.TOO_BIG, len);
|
|
@@ -299,8 +276,11 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
299
276
|
sessionReplaySentFirstChunk: true
|
|
300
277
|
});
|
|
301
278
|
this.recorder.clearBuffer();
|
|
302
|
-
if (recorderEvents.type === 'preloaded') this.
|
|
303
|
-
return [
|
|
279
|
+
if (recorderEvents.type === 'preloaded') this.agentRef.runtime.harvester.triggerHarvestFor(this);
|
|
280
|
+
return [{
|
|
281
|
+
targetApp: undefined,
|
|
282
|
+
payload
|
|
283
|
+
}]; // SR doesn't need a targetApp as it only works for the main, but format needs to make AggregateBase
|
|
304
284
|
}
|
|
305
285
|
getCorrectedTimestamp(node) {
|
|
306
286
|
if (!node?.timestamp) return;
|
|
@@ -386,7 +366,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
386
366
|
if (result.status === 429) {
|
|
387
367
|
this.abort(_constants.ABORT_REASONS.TOO_MANY);
|
|
388
368
|
}
|
|
389
|
-
if (this.blocked) this.scheduler.stopTimer(true);
|
|
390
369
|
}
|
|
391
370
|
|
|
392
371
|
/**
|
|
@@ -395,7 +374,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
395
374
|
* the stopRecording API.
|
|
396
375
|
*/
|
|
397
376
|
forceStop(forceHarvest) {
|
|
398
|
-
if (forceHarvest) this.
|
|
377
|
+
if (forceHarvest) this.agentRef.runtime.harvester.triggerHarvestFor(this);
|
|
399
378
|
this.mode = _constants3.MODE.OFF;
|
|
400
379
|
this.recorder?.stopRecording?.();
|
|
401
380
|
this.syncWithSessionManager({
|
|
@@ -414,7 +393,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
414
393
|
sessionReplayMode: this.mode
|
|
415
394
|
});
|
|
416
395
|
this.recorder?.clearTimestamps?.();
|
|
417
|
-
this.ee.emit('REPLAY_ABORTED');
|
|
418
396
|
while (this.recorder?.getEvents().events.length) this.recorder?.clearBuffer?.();
|
|
419
397
|
}
|
|
420
398
|
syncWithSessionManager(state = {}) {
|
|
@@ -84,7 +84,8 @@ class Instrument extends _instrumentBase.InstrumentBase {
|
|
|
84
84
|
mode: this.#mode,
|
|
85
85
|
agentIdentifier: this.agentIdentifier,
|
|
86
86
|
trigger,
|
|
87
|
-
ee: this.ee
|
|
87
|
+
ee: this.ee,
|
|
88
|
+
agentRef: this.#agentRef
|
|
88
89
|
});
|
|
89
90
|
this.recorder.startRecording();
|
|
90
91
|
this.abortHandler = this.recorder.stopRecording;
|
|
@@ -7,7 +7,6 @@ exports.Recorder = void 0;
|
|
|
7
7
|
var _rrweb = require("rrweb");
|
|
8
8
|
var _stringify = require("../../../common/util/stringify");
|
|
9
9
|
var _constants = require("../constants");
|
|
10
|
-
var _init = require("../../../common/config/init");
|
|
11
10
|
var _recorderEvents = require("./recorder-events");
|
|
12
11
|
var _constants2 = require("../../../common/session/constants");
|
|
13
12
|
var _stylesheetEvaluator = require("./stylesheet-evaluator");
|
|
@@ -16,6 +15,7 @@ var _constants3 = require("../../metrics/constants");
|
|
|
16
15
|
var _features = require("../../../loaders/features/features");
|
|
17
16
|
var _utils = require("./utils");
|
|
18
17
|
var _agentConstants = require("../../../common/constants/agent-constants");
|
|
18
|
+
var _aggregateBase = require("../../utils/aggregate-base");
|
|
19
19
|
class Recorder {
|
|
20
20
|
/** Each page mutation or event will be stored (raw) in this array. This array will be cleared on each harvest */
|
|
21
21
|
#events;
|
|
@@ -40,7 +40,7 @@ class Recorder {
|
|
|
40
40
|
/** The parent class that instantiated the recorder */
|
|
41
41
|
this.parent = parent;
|
|
42
42
|
/** A flag that can be set to false by failing conversions to stop the fetching process */
|
|
43
|
-
this.shouldFix =
|
|
43
|
+
this.shouldFix = this.parent.agentRef.init.session_replay.fix_stylesheets;
|
|
44
44
|
/** The method to stop recording. This defaults to a noop, but is overwritten once the recording library is imported and initialized */
|
|
45
45
|
this.stopRecording = () => {/* no-op until set by rrweb initializer */};
|
|
46
46
|
}
|
|
@@ -84,7 +84,7 @@ class Recorder {
|
|
|
84
84
|
mask_all_inputs,
|
|
85
85
|
inline_images,
|
|
86
86
|
collect_fonts
|
|
87
|
-
} =
|
|
87
|
+
} = this.parent.agentRef.init.session_replay;
|
|
88
88
|
const customMasker = (text, element) => {
|
|
89
89
|
try {
|
|
90
90
|
if (typeof element?.type === 'string' && element.type.toLowerCase() !== 'password' && (element?.dataset?.nrUnmask !== undefined || element?.classList?.contains('nr-unmask'))) return text;
|
|
@@ -160,7 +160,7 @@ class Recorder {
|
|
|
160
160
|
/** Store a payload in the buffer (this.#events). This should be the callback to the recording lib noticing a mutation */
|
|
161
161
|
store(event, isCheckout) {
|
|
162
162
|
if (!event) return;
|
|
163
|
-
if (!this.parent.
|
|
163
|
+
if (!(this.parent instanceof _aggregateBase.AggregateBase) && this.#preloaded.length) this.currentBufferTarget = this.#preloaded[this.#preloaded.length - 1];else this.currentBufferTarget = this.#events;
|
|
164
164
|
if (this.parent.blocked) return;
|
|
165
165
|
if (!this.notified) {
|
|
166
166
|
this.parent.ee.emit(_constants.SR_EVENT_EMITTER_TYPES.REPLAY_RUNNING, [true, this.parent.mode]);
|
|
@@ -198,8 +198,8 @@ class Recorder {
|
|
|
198
198
|
// it will send immediately. This often happens on the first snapshot, which can be significantly larger than the other payloads.
|
|
199
199
|
if ((event.type === _constants.RRWEB_EVENT_TYPES.FullSnapshot && this.currentBufferTarget.hasMeta || payloadSize > _agentConstants.IDEAL_PAYLOAD_SIZE) && this.parent.mode === _constants2.MODE.FULL) {
|
|
200
200
|
// if we've made it to the ideal size of ~64kb before the interval timer, we should send early.
|
|
201
|
-
if (this.parent.
|
|
202
|
-
this.parent.
|
|
201
|
+
if (this.parent instanceof _aggregateBase.AggregateBase) {
|
|
202
|
+
this.parent.agentRef.runtime.harvester.triggerHarvestFor(this.parent);
|
|
203
203
|
} else {
|
|
204
204
|
// we are still in "preload" and it triggered a "stop point". Make a new set, which will get pointed at on next cycle
|
|
205
205
|
this.#preloaded.push(new _recorderEvents.RecorderEvents());
|
|
@@ -5,7 +5,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.Aggregate = void 0;
|
|
7
7
|
var _registerHandler = require("../../../common/event-emitter/register-handler");
|
|
8
|
-
var _harvestScheduler = require("../../../common/harvest/harvest-scheduler");
|
|
9
8
|
var _constants = require("../constants");
|
|
10
9
|
var _aggregateBase = require("../../utils/aggregate-base");
|
|
11
10
|
var _storage = require("./trace/storage");
|
|
@@ -13,7 +12,6 @@ var _encode = require("../../../common/url/encode");
|
|
|
13
12
|
var _runtime = require("../../../common/constants/runtime");
|
|
14
13
|
var _constants2 = require("../../../common/session/constants");
|
|
15
14
|
var _traverse = require("../../../common/util/traverse");
|
|
16
|
-
var _features = require("../../../loaders/features/features");
|
|
17
15
|
var _cleanUrl = require("../../../common/url/clean-url");
|
|
18
16
|
const ERROR_MODE_SECONDS_WINDOW = 30 * 1000; // sliding window of nodes to track when simply monitoring (but not harvesting) in error mode
|
|
19
17
|
/** Reserved room for query param attrs */
|
|
@@ -22,7 +20,8 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
22
20
|
static featureName = _constants.FEATURE_NAME;
|
|
23
21
|
constructor(agentRef) {
|
|
24
22
|
super(agentRef, _constants.FEATURE_NAME);
|
|
25
|
-
this.
|
|
23
|
+
this.harvestOpts.raw = true;
|
|
24
|
+
|
|
26
25
|
/** Tied to the entitlement flag response from BCS. Will short circuit operations of the agg if false */
|
|
27
26
|
this.entitled = undefined;
|
|
28
27
|
/** A flag used to decide if the 30 node threshold should be ignored on the first harvest to ensure sending on the first payload */
|
|
@@ -31,14 +30,16 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
31
30
|
this.harvesting = false;
|
|
32
31
|
/** TraceStorage is the mechanism that holds, normalizes and aggregates ST nodes. It will be accessed and purged when harvests occur */
|
|
33
32
|
this.events = new _storage.TraceStorage(this);
|
|
34
|
-
|
|
33
|
+
|
|
34
|
+
/* This agg needs information about sampling (sts) and entitlements (st) to make the appropriate decisions on running */
|
|
35
35
|
this.waitForFlags(['sts', 'st']).then(([stMode, stEntitled]) => this.initialize(stMode, stEntitled));
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/** Sets up event listeners, and initializes this module to run in the correct "mode". Can be triggered from a few places, but makes an effort to only set up listeners once */
|
|
39
39
|
initialize(stMode, stEntitled, ignoreSession) {
|
|
40
40
|
this.entitled ??= stEntitled;
|
|
41
|
-
if (
|
|
41
|
+
if (!this.entitled) this.blocked = true;
|
|
42
|
+
if (this.blocked) return this.deregisterDrain();
|
|
42
43
|
if (!this.initialized) {
|
|
43
44
|
this.initialized = true;
|
|
44
45
|
/** Store session identifiers at initialization time to be cross-checked later at harvest time for session changes that are subject to race conditions */
|
|
@@ -56,7 +57,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
56
57
|
// this will only have an effect if ST is NOT already in full mode
|
|
57
58
|
if (this.mode !== _constants2.MODE.FULL && (sessionState.sessionReplayMode === _constants2.MODE.FULL || sessionState.sessionTraceMode === _constants2.MODE.FULL)) this.switchToFull();
|
|
58
59
|
// if another page's session entity has expired, or another page has transitioned to off and this one hasn't... we can just abort straight away here
|
|
59
|
-
if (this.sessionId !== sessionState.value || eventType === 'cross-tab' &&
|
|
60
|
+
if (this.sessionId !== sessionState.value || eventType === 'cross-tab' && sessionState.sessionTraceMode === _constants2.MODE.OFF) this.abort(2);
|
|
60
61
|
});
|
|
61
62
|
if (typeof PerformanceNavigationTiming !== 'undefined') {
|
|
62
63
|
this.events.storeTiming(_runtime.globalScope.performance?.getEntriesByType?.('navigation')[0]);
|
|
@@ -73,12 +74,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
73
74
|
* If it drains later (due to a mode change), data and handlers will instantly drain instead of waiting for the registry. */
|
|
74
75
|
if (this.mode === _constants2.MODE.OFF) return this.deregisterDrain();
|
|
75
76
|
this.timeKeeper ??= this.agentRef.runtime.timeKeeper;
|
|
76
|
-
this.scheduler = new _harvestScheduler.HarvestScheduler(_features.FEATURE_TO_ENDPOINT[this.featureName], {
|
|
77
|
-
onFinished: result => this.postHarvestCleanup(result.sent && result.retry),
|
|
78
|
-
retryDelay: this.harvestTimeSeconds,
|
|
79
|
-
getPayload: options => this.makeHarvestPayload(options.retry),
|
|
80
|
-
raw: true
|
|
81
|
-
}, this);
|
|
82
77
|
|
|
83
78
|
/** The handlers set up by the Inst file */
|
|
84
79
|
(0, _registerHandler.registerHandler)('bst', (...args) => this.events.storeEvent(...args), this.featureName, this.ee);
|
|
@@ -88,9 +83,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
88
83
|
(0, _registerHandler.registerHandler)('bstApi', (...args) => this.events.storeSTN(...args), this.featureName, this.ee);
|
|
89
84
|
(0, _registerHandler.registerHandler)('trace-jserror', (...args) => this.events.storeErrorAgg(...args), this.featureName, this.ee);
|
|
90
85
|
(0, _registerHandler.registerHandler)('pvtAdded', (...args) => this.events.processPVT(...args), this.featureName, this.ee);
|
|
91
|
-
|
|
92
|
-
/** Only start actually harvesting if running in full mode at init time */
|
|
93
|
-
if (this.mode === _constants2.MODE.FULL) this.startHarvesting();else {
|
|
86
|
+
if (this.mode !== _constants2.MODE.FULL) {
|
|
94
87
|
/** A separate handler for noticing errors, and switching to "full" mode if running in "error" mode */
|
|
95
88
|
(0, _registerHandler.registerHandler)('trace-jserror', () => {
|
|
96
89
|
if (this.mode === _constants2.MODE.ERROR) this.switchToFull();
|
|
@@ -101,13 +94,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
101
94
|
});
|
|
102
95
|
this.drain();
|
|
103
96
|
}
|
|
104
|
-
|
|
105
|
-
/** This module does not auto harvest by default -- it needs to be kicked off. Once this method is called, it will then harvest on an interval */
|
|
106
|
-
startHarvesting() {
|
|
107
|
-
if (this.scheduler.started || this.blocked) return;
|
|
108
|
-
this.scheduler.runHarvest();
|
|
109
|
-
this.scheduler.startTimer(this.harvestTimeSeconds);
|
|
110
|
-
}
|
|
111
97
|
preHarvestChecks() {
|
|
112
98
|
if (this.mode !== _constants2.MODE.FULL) return; // only allow harvest if running in full mode
|
|
113
99
|
if (!this.timeKeeper?.ready) return; // this should likely never happen, but just to be safe, we should never harvest if we cant correct time
|
|
@@ -198,8 +184,8 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
198
184
|
if (prevMode === _constants2.MODE.OFF || !this.initialized) return this.initialize(this.mode, this.entitled);
|
|
199
185
|
if (this.initialized) {
|
|
200
186
|
this.events.trimSTNs(ERROR_MODE_SECONDS_WINDOW); // up until now, Trace would've been just buffering nodes up to max, which needs to be trimmed to last X seconds
|
|
187
|
+
this.agentRef.runtime.harvester.triggerHarvestFor(this);
|
|
201
188
|
}
|
|
202
|
-
this.startHarvesting();
|
|
203
189
|
}
|
|
204
190
|
|
|
205
191
|
/** Stop running for the remainder of the page lifecycle */
|
|
@@ -209,7 +195,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
209
195
|
this.agentRef.runtime.session.write({
|
|
210
196
|
sessionTraceMode: this.mode
|
|
211
197
|
});
|
|
212
|
-
this.scheduler?.stopTimer();
|
|
213
198
|
this.events.clear();
|
|
214
199
|
}
|
|
215
200
|
}
|
|
@@ -275,14 +275,20 @@ class TraceStorage {
|
|
|
275
275
|
this.storeSTN(new _node.TraceNode('Ajax', metrics.time, metrics.time + metrics.duration, "".concat(params.status, " ").concat(params.method, ": ").concat(params.host).concat(params.pathname), 'ajax'));
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
-
/* Below are the interface expected & required of whatever storage is used across all features on an individual basis. This allows a common `.events` property on Trace.
|
|
278
|
+
/* Below are the interface expected & required of whatever storage is used across all features on an individual basis. This allows a common `.events` property on Trace shared with AggregateBase.
|
|
279
|
+
Note that the usage must be in sync with the EventStoreManager class such that AggregateBase.makeHarvestPayload can run the same regardless of which storage class a feature is using. */
|
|
279
280
|
isEmpty() {
|
|
280
281
|
return this.nodeCount === 0;
|
|
281
282
|
}
|
|
282
283
|
save() {
|
|
283
284
|
this.#backupTrace = this.trace;
|
|
284
285
|
}
|
|
285
|
-
get
|
|
286
|
+
get() {
|
|
287
|
+
return [{
|
|
288
|
+
targetApp: this.parent.agentRef.mainAppKey,
|
|
289
|
+
data: this.takeSTNs()
|
|
290
|
+
}];
|
|
291
|
+
}
|
|
286
292
|
clear() {
|
|
287
293
|
this.trace = {};
|
|
288
294
|
this.nodeCount = 0;
|