@newrelic/browser-agent 1.272.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.
Files changed (115) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/cjs/common/aggregate/aggregator.js +23 -30
  3. package/dist/cjs/common/aggregate/event-aggregator.js +84 -0
  4. package/dist/cjs/common/constants/env.cdn.js +1 -1
  5. package/dist/cjs/common/constants/env.npm.js +1 -1
  6. package/dist/cjs/common/harvest/harvest-scheduler.js +1 -1
  7. package/dist/cjs/common/harvest/harvest.js +1 -5
  8. package/dist/cjs/common/harvest/types.js +0 -1
  9. package/dist/cjs/features/ajax/aggregate/index.js +52 -62
  10. package/dist/cjs/features/generic_events/aggregate/index.js +18 -36
  11. package/dist/cjs/features/jserrors/aggregate/index.js +23 -69
  12. package/dist/cjs/features/logging/aggregate/index.js +52 -59
  13. package/dist/cjs/features/metrics/aggregate/index.js +8 -5
  14. package/dist/cjs/features/page_view_timing/aggregate/index.js +8 -25
  15. package/dist/cjs/features/session_replay/aggregate/index.js +11 -10
  16. package/dist/cjs/features/session_replay/shared/recorder-events.js +2 -2
  17. package/dist/cjs/features/session_trace/aggregate/index.js +77 -88
  18. package/dist/cjs/features/session_trace/aggregate/trace/storage.js +22 -13
  19. package/dist/cjs/features/soft_navigations/aggregate/index.js +10 -20
  20. package/dist/cjs/features/soft_navigations/instrument/index.js +5 -9
  21. package/dist/cjs/features/spa/aggregate/index.js +10 -26
  22. package/dist/cjs/features/utils/aggregate-base.js +37 -0
  23. package/dist/cjs/features/utils/event-buffer.js +36 -87
  24. package/dist/cjs/features/utils/instrument-base.js +3 -3
  25. package/dist/cjs/loaders/features/features.js +13 -1
  26. package/dist/esm/common/aggregate/aggregator.js +23 -30
  27. package/dist/esm/common/aggregate/event-aggregator.js +78 -0
  28. package/dist/esm/common/constants/env.cdn.js +1 -1
  29. package/dist/esm/common/constants/env.npm.js +1 -1
  30. package/dist/esm/common/harvest/harvest-scheduler.js +1 -1
  31. package/dist/esm/common/harvest/harvest.js +1 -5
  32. package/dist/esm/common/harvest/types.js +0 -1
  33. package/dist/esm/features/ajax/aggregate/index.js +53 -62
  34. package/dist/esm/features/generic_events/aggregate/index.js +18 -36
  35. package/dist/esm/features/jserrors/aggregate/index.js +24 -70
  36. package/dist/esm/features/logging/aggregate/index.js +52 -59
  37. package/dist/esm/features/metrics/aggregate/index.js +8 -5
  38. package/dist/esm/features/page_view_timing/aggregate/index.js +9 -26
  39. package/dist/esm/features/session_replay/aggregate/index.js +12 -11
  40. package/dist/esm/features/session_replay/shared/recorder-events.js +2 -2
  41. package/dist/esm/features/session_trace/aggregate/index.js +77 -88
  42. package/dist/esm/features/session_trace/aggregate/trace/storage.js +22 -13
  43. package/dist/esm/features/soft_navigations/aggregate/index.js +11 -21
  44. package/dist/esm/features/soft_navigations/instrument/index.js +5 -9
  45. package/dist/esm/features/spa/aggregate/index.js +11 -27
  46. package/dist/esm/features/utils/aggregate-base.js +37 -0
  47. package/dist/esm/features/utils/event-buffer.js +36 -88
  48. package/dist/esm/features/utils/instrument-base.js +3 -3
  49. package/dist/esm/loaders/features/features.js +12 -0
  50. package/dist/types/common/aggregate/aggregator.d.ts +4 -6
  51. package/dist/types/common/aggregate/aggregator.d.ts.map +1 -1
  52. package/dist/types/common/aggregate/event-aggregator.d.ts +26 -0
  53. package/dist/types/common/aggregate/event-aggregator.d.ts.map +1 -0
  54. package/dist/types/common/harvest/harvest.d.ts.map +1 -1
  55. package/dist/types/common/harvest/types.d.ts +1 -4
  56. package/dist/types/common/harvest/types.d.ts.map +1 -1
  57. package/dist/types/features/ajax/aggregate/index.d.ts +2 -10
  58. package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
  59. package/dist/types/features/generic_events/aggregate/index.d.ts +5 -11
  60. package/dist/types/features/generic_events/aggregate/index.d.ts.map +1 -1
  61. package/dist/types/features/jserrors/aggregate/index.d.ts +4 -7
  62. package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
  63. package/dist/types/features/logging/aggregate/index.d.ts +10 -28
  64. package/dist/types/features/logging/aggregate/index.d.ts.map +1 -1
  65. package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
  66. package/dist/types/features/page_view_timing/aggregate/index.d.ts +1 -9
  67. package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
  68. package/dist/types/features/session_replay/aggregate/index.d.ts +3 -4
  69. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
  70. package/dist/types/features/session_replay/shared/recorder-events.d.ts +1 -1
  71. package/dist/types/features/session_replay/shared/recorder-events.d.ts.map +1 -1
  72. package/dist/types/features/session_replay/shared/recorder.d.ts +1 -1
  73. package/dist/types/features/session_trace/aggregate/index.d.ts +17 -19
  74. package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
  75. package/dist/types/features/session_trace/aggregate/trace/storage.d.ts +10 -6
  76. package/dist/types/features/session_trace/aggregate/trace/storage.d.ts.map +1 -1
  77. package/dist/types/features/soft_navigations/aggregate/index.d.ts +3 -9
  78. package/dist/types/features/soft_navigations/aggregate/index.d.ts.map +1 -1
  79. package/dist/types/features/soft_navigations/instrument/index.d.ts.map +1 -1
  80. package/dist/types/features/spa/aggregate/index.d.ts +2 -3
  81. package/dist/types/features/spa/aggregate/index.d.ts.map +1 -1
  82. package/dist/types/features/utils/aggregate-base.d.ts +14 -0
  83. package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
  84. package/dist/types/features/utils/event-buffer.d.ts +19 -56
  85. package/dist/types/features/utils/event-buffer.d.ts.map +1 -1
  86. package/dist/types/loaders/features/features.d.ts +3 -0
  87. package/dist/types/loaders/features/features.d.ts.map +1 -1
  88. package/package.json +1 -1
  89. package/src/common/aggregate/aggregator.js +22 -32
  90. package/src/common/aggregate/event-aggregator.js +76 -0
  91. package/src/common/harvest/harvest-scheduler.js +1 -1
  92. package/src/common/harvest/harvest.js +1 -5
  93. package/src/common/harvest/types.js +0 -1
  94. package/src/features/ajax/aggregate/index.js +60 -67
  95. package/src/features/generic_events/aggregate/index.js +14 -39
  96. package/src/features/jserrors/aggregate/index.js +21 -77
  97. package/src/features/logging/aggregate/index.js +46 -60
  98. package/src/features/metrics/aggregate/index.js +6 -4
  99. package/src/features/page_view_timing/aggregate/index.js +9 -30
  100. package/src/features/session_replay/aggregate/index.js +10 -14
  101. package/src/features/session_replay/shared/recorder-events.js +2 -2
  102. package/src/features/session_trace/aggregate/index.js +64 -73
  103. package/src/features/session_trace/aggregate/trace/storage.js +25 -14
  104. package/src/features/soft_navigations/aggregate/index.js +11 -22
  105. package/src/features/soft_navigations/instrument/index.js +6 -9
  106. package/src/features/spa/aggregate/index.js +12 -27
  107. package/src/features/utils/aggregate-base.js +39 -0
  108. package/src/features/utils/event-buffer.js +36 -83
  109. package/src/features/utils/instrument-base.js +3 -3
  110. package/src/loaders/features/features.js +13 -0
  111. package/dist/cjs/features/ajax/aggregate/chunk.js +0 -51
  112. package/dist/esm/features/ajax/aggregate/chunk.js +0 -44
  113. package/dist/types/features/ajax/aggregate/chunk.d.ts +0 -8
  114. package/dist/types/features/ajax/aggregate/chunk.d.ts.map +0 -1
  115. package/src/features/ajax/aggregate/chunk.js +0 -52
@@ -16,7 +16,6 @@ var _runtime = require("../../../common/constants/runtime");
16
16
  var _constants = require("../constants");
17
17
  var _features = require("../../../loaders/features/features");
18
18
  var _aggregateBase = require("../../utils/aggregate-base");
19
- var _nreum = require("../../../common/window/nreum");
20
19
  var _now = require("../../../common/timing/now");
21
20
  var _traverse = require("../../../common/util/traverse");
22
21
  var _internalErrors = require("./internal-errors");
@@ -38,7 +37,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
38
37
  this.observedAt = {};
39
38
  this.pageviewReported = {};
40
39
  this.bufferedErrorsUnderSpa = {};
41
- this.currentBody = undefined;
42
40
  this.errorOnPage = false;
43
41
 
44
42
  // this will need to change to match whatever ee we use in the instrument
@@ -48,14 +46,19 @@ class Aggregate extends _aggregateBase.AggregateBase {
48
46
  (0, _registerHandler.registerHandler)('softNavFlush', (interactionId, wasFinished, softNavAttrs) => this.onSoftNavNotification(interactionId, wasFinished, softNavAttrs), this.featureName, this.ee); // when an ixn is done or cancelled
49
47
 
50
48
  const harvestTimeSeconds = agentRef.init.jserrors.harvestTimeSeconds || 10;
49
+ const aggregatorTypes = ['err', 'ierr', 'xhr']; // the types in EventAggregator this feature cares about
51
50
 
52
51
  // 0 == off, 1 == on
53
52
  this.waitForFlags(['err']).then(([errFlag]) => {
54
53
  if (errFlag) {
55
- const scheduler = new _harvestScheduler.HarvestScheduler('jserrors', {
56
- onFinished: (...args) => this.onHarvestFinished(...args)
54
+ const scheduler = new _harvestScheduler.HarvestScheduler(_features.FEATURE_TO_ENDPOINT[this.featureName], {
55
+ onFinished: result => this.postHarvestCleanup(result.sent && result.retry, {
56
+ aggregatorTypes
57
+ })
57
58
  }, this);
58
- scheduler.harvest.on('jserrors', (...args) => this.onHarvestStarted(...args));
59
+ scheduler.harvest.on(_features.FEATURE_TO_ENDPOINT[this.featureName], options => this.makeHarvestPayload(options.retry, {
60
+ aggregatorTypes
61
+ }));
59
62
  scheduler.startTimer(harvestTimeSeconds);
60
63
  this.drain();
61
64
  } else {
@@ -64,49 +67,22 @@ class Aggregate extends _aggregateBase.AggregateBase {
64
67
  }
65
68
  });
66
69
  }
67
- onHarvestStarted(options) {
68
- // this gets rid of dependency in AJAX module
69
- var body = (0, _traverse.applyFnToProps)(this.agentRef.sharedAggregator.take(['err', 'ierr', 'xhr']), this.obfuscator.obfuscateString.bind(this.obfuscator), 'string');
70
- if (options.retry) {
71
- this.currentBody = body;
72
- }
73
- var payload = {
74
- body,
75
- qs: {}
76
- };
77
- var releaseIds = (0, _stringify.stringify)(this.agentRef.runtime.releaseIds);
78
- if (releaseIds !== '{}') {
79
- payload.qs.ri = releaseIds;
80
- }
81
- if (body && body.err && body.err.length) {
82
- this.#runCrossFeatureChecks(body.err);
70
+ serializer(aggregatorTypeToBucketsMap) {
71
+ return (0, _traverse.applyFnToProps)(aggregatorTypeToBucketsMap, this.obfuscator.obfuscateString.bind(this.obfuscator), 'string');
72
+ }
73
+ queryStringsBuilder(aggregatorTakeReturnedData) {
74
+ const qs = {};
75
+ const releaseIds = (0, _stringify.stringify)(this.agentRef.runtime.releaseIds);
76
+ if (releaseIds !== '{}') qs.ri = releaseIds;
77
+ if (aggregatorTakeReturnedData?.err?.length) {
83
78
  if (!this.errorOnPage) {
84
- payload.qs.pve = '1';
79
+ qs.pve = '1';
85
80
  this.errorOnPage = true;
86
81
  }
82
+ // For assurance, erase any `hasReplay` flag from all errors if replay is not recording, not-yet imported, or not running at all.
83
+ if (!this.agentRef.features?.[_features.FEATURE_NAMES.sessionReplay]?.featAggregate?.replayIsActive()) aggregatorTakeReturnedData.err.forEach(error => delete error.params.hasReplay);
87
84
  }
88
- return payload;
89
- }
90
- onHarvestFinished(result) {
91
- if (result.retry && this.currentBody) {
92
- Object.entries(this.currentBody || {}).forEach(([key, value]) => {
93
- for (var i = 0; i < value.length; i++) {
94
- var bucket = value[i];
95
- var name = this.getBucketName(key, bucket.params, bucket.custom);
96
- this.agentRef.sharedAggregator.merge(key, name, bucket.metrics, bucket.params, bucket.custom);
97
- }
98
- });
99
- this.currentBody = null;
100
- }
101
- }
102
- nameHash(params) {
103
- return (0, _stringHashCode.stringHashCode)("".concat(params.exceptionClass, "_").concat(params.message, "_").concat(params.stack_trace || params.browser_stack_hash));
104
- }
105
- getBucketName(objType, params, customParams) {
106
- if (objType === 'xhr') {
107
- return (0, _stringHashCode.stringHashCode)((0, _stringify.stringify)(params)) + ':' + (0, _stringHashCode.stringHashCode)((0, _stringify.stringify)(customParams));
108
- }
109
- return this.nameHash(params) + ':' + (0, _stringHashCode.stringHashCode)((0, _stringify.stringify)(customParams));
85
+ return qs;
110
86
  }
111
87
 
112
88
  /**
@@ -213,7 +189,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
213
189
  params._interactionId = err.__newrelic[this.agentIdentifier].interactionId;
214
190
  params._interactionNodeId = err.__newrelic[this.agentIdentifier].interactionNodeId;
215
191
  }
216
- const softNavInUse = Boolean((0, _nreum.getNREUMInitializedAgent)(this.agentIdentifier)?.features[_features.FEATURE_NAMES.softNav]);
192
+ const softNavInUse = Boolean(this.agentRef.features?.[_features.FEATURE_NAMES.softNav]);
217
193
  // 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.
218
194
  // They each will also tack on their respective properties to the params object as part of the decision flow.
219
195
  if (softNavInUse) (0, _handle.handle)('jserror', [params, time], undefined, _features.FEATURE_NAMES.softNav, this.ee);else (0, _handle.handle)('spa-jserror', jsErrorEvent, undefined, _features.FEATURE_NAMES.spa, this.ee);
@@ -248,7 +224,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
248
224
 
249
225
  const jsAttributesHash = (0, _stringHashCode.stringHashCode)((0, _stringify.stringify)(allCustomAttrs));
250
226
  const aggregateHash = bucketHash + ':' + jsAttributesHash;
251
- this.agentRef.sharedAggregator.store(type, aggregateHash, params, newMetrics, allCustomAttrs);
227
+ this.events.add(type, aggregateHash, params, newMetrics, allCustomAttrs);
252
228
  function setCustom(key, val) {
253
229
  allCustomAttrs[key] = val && typeof val === 'object' ? (0, _stringify.stringify)(val) : val;
254
230
  }
@@ -272,7 +248,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
272
248
  var hash = wasSaved ? item[1] + interaction.root.attrs.id : item[1];
273
249
  var jsAttributesHash = (0, _stringHashCode.stringHashCode)((0, _stringify.stringify)(allCustomAttrs));
274
250
  var aggregateHash = hash + ':' + jsAttributesHash;
275
- this.agentRef.sharedAggregator.store(item[0], aggregateHash, params, item[3], allCustomAttrs);
251
+ this.events.add(item[0], aggregateHash, params, item[3], allCustomAttrs);
276
252
  function setCustom([key, val]) {
277
253
  allCustomAttrs[key] = val && typeof val === 'object' ? (0, _stringify.stringify)(val) : val;
278
254
  }
@@ -285,27 +261,5 @@ class Aggregate extends _aggregateBase.AggregateBase {
285
261
  );
286
262
  delete this.bufferedErrorsUnderSpa[interactionId]; // wipe the list of jserrors so they aren't duplicated by another call to the same id
287
263
  }
288
-
289
- /**
290
- * Dispatches a cross-feature communication event to allow other
291
- * features to provide flags and data that can be used to mutation
292
- * to the payload and to allow features to know about a feature
293
- * harvest happening.
294
- * @param {any[]} errors Array of errors from the payload body
295
- */
296
- #runCrossFeatureChecks(errors) {
297
- const errorHashes = errors.map(error => error.params.stackHash);
298
- const crossFeatureData = {
299
- errorHashes
300
- };
301
- this.ee.emit("cfc.".concat(this.featureName), [crossFeatureData]);
302
- let hasReplayFlag = errors.find(err => err.params.hasReplay);
303
- if (hasReplayFlag && !crossFeatureData.hasReplay) {
304
- // Some errors have `hasReplay` and a replay is not being recorded
305
- errors.forEach(error => {
306
- delete error.params.hasReplay;
307
- });
308
- }
309
- }
310
264
  }
311
265
  exports.Aggregate = Aggregate;
@@ -16,20 +16,17 @@ var _log = require("../shared/log");
16
16
  var _utils = require("../shared/utils");
17
17
  var _traverse = require("../../../common/util/traverse");
18
18
  var _agentConstants = require("../../../common/constants/agent-constants");
19
- var _eventBuffer = require("../../utils/event-buffer");
19
+ var _features = require("../../../loaders/features/features");
20
20
  class Aggregate extends _aggregateBase.AggregateBase {
21
21
  static featureName = _constants2.FEATURE_NAME;
22
22
  constructor(agentRef) {
23
23
  super(agentRef, _constants2.FEATURE_NAME);
24
-
25
- /** held logs before sending */
26
- this.bufferedLogs = new _eventBuffer.EventBuffer();
27
24
  this.harvestTimeSeconds = agentRef.init.logging.harvestTimeSeconds;
28
25
  this.waitForFlags([]).then(() => {
29
- this.scheduler = new _harvestScheduler.HarvestScheduler('browser/logs', {
30
- onFinished: this.onHarvestFinished.bind(this),
26
+ this.scheduler = new _harvestScheduler.HarvestScheduler(_features.FEATURE_TO_ENDPOINT[this.featureName], {
27
+ onFinished: result => this.postHarvestCleanup(result.sent && result.retry),
31
28
  retryDelay: this.harvestTimeSeconds,
32
- getPayload: this.prepareHarvest.bind(this),
29
+ getPayload: options => this.makeHarvestPayload(options.retry),
33
30
  raw: true
34
31
  }, this);
35
32
  /** emitted by instrument class (wrapped loggers) or the api methods directly */
@@ -62,64 +59,60 @@ class Aggregate extends _aggregateBase.AggregateBase {
62
59
  const log = new _log.Log(Math.floor(this.agentRef.runtime.timeKeeper.correctRelativeTimestamp(timestamp)), message, attributes, level);
63
60
  const logBytes = log.message.length + (0, _stringify.stringify)(log.attributes).length + log.level.length + 10; // timestamp == 10 chars
64
61
 
65
- if (!this.bufferedLogs.canMerge(logBytes)) {
66
- if (this.bufferedLogs.hasData) {
67
- (0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ['Logging/Harvest/Early/Seen', this.bufferedLogs.bytes + logBytes]);
68
- this.scheduler.runHarvest({});
69
- if (logBytes < _agentConstants.MAX_PAYLOAD_SIZE) this.bufferedLogs.add(log);
70
- } else {
71
- (0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ['Logging/Harvest/Failed/Seen', logBytes]);
72
- (0, _console.warn)(31, log.message.slice(0, 25) + '...');
73
- }
62
+ const failToHarvestMessage = 'Logging/Harvest/Failed/Seen';
63
+ if (logBytes > _agentConstants.MAX_PAYLOAD_SIZE) {
64
+ // cannot possibly send this, even with an empty buffer
65
+ (0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, [failToHarvestMessage, logBytes]);
66
+ (0, _console.warn)(31, log.message.slice(0, 25) + '...');
74
67
  return;
75
68
  }
76
- this.bufferedLogs.add(log);
69
+ if (this.events.wouldExceedMaxSize(logBytes)) {
70
+ (0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ['Logging/Harvest/Early/Seen', this.events.bytes + logBytes]);
71
+ this.scheduler.runHarvest(); // force a harvest to try adding again
72
+ }
73
+ if (!this.events.add(log)) {
74
+ // still failed after a harvest attempt despite not being too large would mean harvest failed with options.retry
75
+ (0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, [failToHarvestMessage, logBytes]);
76
+ (0, _console.warn)(31, log.message.slice(0, 25) + '...');
77
+ }
77
78
  }
78
- prepareHarvest(options = {}) {
79
- if (this.blocked || !this.bufferedLogs.hasData) return;
80
- /** These attributes are evaluated and dropped at ingest processing time and do not get stored on NRDB */
81
- const unbilledAttributes = {
82
- 'instrumentation.provider': 'browser',
83
- 'instrumentation.version': this.agentRef.runtime.version,
84
- 'instrumentation.name': this.agentRef.runtime.loaderType
85
- };
86
- /** see https://source.datanerd.us/agents/rum-specs/blob/main/browser/Log for logging spec */
87
- const payload = {
88
- qs: {
89
- browser_monitoring_key: this.agentRef.info.licenseKey
90
- },
91
- body: [{
92
- common: {
93
- /** Attributes in the `common` section are added to `all` logs generated in the payload */
94
- attributes: {
95
- 'entity.guid': this.agentRef.runtime.appMetadata?.agents?.[0]?.entityGuid,
96
- // browser entity guid as provided from RUM response
97
- session: this.agentRef.runtime.session?.state.value || '0',
79
+ serializer(eventBuffer) {
80
+ const sessionEntity = this.agentRef.runtime.session;
81
+ return [{
82
+ common: {
83
+ /** Attributes in the `common` section are added to `all` logs generated in the payload */
84
+ attributes: {
85
+ 'entity.guid': this.agentRef.runtime.appMetadata?.agents?.[0]?.entityGuid,
86
+ // browser entity guid as provided from RUM response
87
+ ...(sessionEntity && {
88
+ session: sessionEntity.state.value || '0',
98
89
  // The session ID that we generate and keep across page loads
99
- hasReplay: this.agentRef.runtime.session?.state.sessionReplayMode === 1,
90
+ hasReplay: sessionEntity.state.sessionReplayMode === 1,
100
91
  // True if a session replay recording is running
101
- hasTrace: this.agentRef.runtime.session?.state.sessionTraceMode === 1,
102
- // True if a session trace recording is running
103
- ptid: this.agentRef.runtime.ptid,
104
- // page trace id
105
- appId: this.agentRef.info.applicationID,
106
- // Application ID from info object,
107
- standalone: Boolean(this.agentRef.info.sa),
108
- // copy paste (true) vs APM (false)
109
- agentVersion: this.agentRef.runtime.version,
110
- // browser agent version
111
- ...unbilledAttributes
112
- }
113
- },
114
- /** logs section contains individual unique log entries */
115
- logs: (0, _traverse.applyFnToProps)(this.bufferedLogs.buffer, this.obfuscator.obfuscateString.bind(this.obfuscator), 'string')
116
- }]
117
- };
118
- if (options.retry) this.bufferedLogs.hold();else this.bufferedLogs.clear();
119
- return payload;
92
+ hasTrace: sessionEntity.state.sessionTraceMode === 1 // True if a session trace recording is running
93
+ }),
94
+ ptid: this.agentRef.runtime.ptid,
95
+ // page trace id
96
+ appId: this.agentRef.info.applicationID,
97
+ // Application ID from info object,
98
+ standalone: Boolean(this.agentRef.info.sa),
99
+ // copy paste (true) vs APM (false)
100
+ agentVersion: this.agentRef.runtime.version,
101
+ // browser agent version
102
+ // The following 3 attributes are evaluated and dropped at ingest processing time and do not get stored on NRDB:
103
+ 'instrumentation.provider': 'browser',
104
+ 'instrumentation.version': this.agentRef.runtime.version,
105
+ 'instrumentation.name': this.agentRef.runtime.loaderType
106
+ }
107
+ },
108
+ /** logs section contains individual unique log entries */
109
+ logs: (0, _traverse.applyFnToProps)(eventBuffer, this.obfuscator.obfuscateString.bind(this.obfuscator), 'string')
110
+ }];
120
111
  }
121
- onHarvestFinished(result) {
122
- if (result.retry) this.bufferedLogs.unhold();else this.bufferedLogs.held.clear();
112
+ queryStringsBuilder() {
113
+ return {
114
+ browser_monitoring_key: this.agentRef.info.licenseKey
115
+ };
123
116
  }
124
117
  }
125
118
  exports.Aggregate = Aggregate;
@@ -13,6 +13,7 @@ var _load = require("../../../common/window/load");
13
13
  var _eventListenerOpts = require("../../../common/event-listener/event-listener-opts");
14
14
  var _runtime = require("../../../common/constants/runtime");
15
15
  var _aggregateBase = require("../../utils/aggregate-base");
16
+ var _features = require("../../../loaders/features/features");
16
17
  var _iframe = require("../../../common/dom/iframe");
17
18
  // import { WEBSOCKET_TAG } from '../../../common/wrap/wrap-websocket'
18
19
  // import { handleWebsocketEvents } from './websocket-detection'
@@ -21,15 +22,17 @@ class Aggregate extends _aggregateBase.AggregateBase {
21
22
  static featureName = _constants.FEATURE_NAME;
22
23
  constructor(agentRef) {
23
24
  super(agentRef, _constants.FEATURE_NAME);
25
+ const aggregatorTypes = ['cm', 'sm']; // the types in EventAggregator this feature cares about
26
+
24
27
  this.waitForFlags(['err']).then(([errFlag]) => {
25
28
  if (errFlag) {
26
29
  // *cli, Mar 23 - Per NR-94597, this feature should only harvest ONCE at the (potential) EoL time of the page.
27
- const scheduler = new _harvestScheduler.HarvestScheduler('jserrors', {
30
+ const scheduler = new _harvestScheduler.HarvestScheduler(_features.FEATURE_TO_ENDPOINT[this.featureName], {
28
31
  onUnload: () => this.unload()
29
32
  }, this);
30
33
  // this is needed to ensure EoL is "on" and sent
31
- scheduler.harvest.on('jserrors', () => ({
32
- body: this.agentRef.sharedAggregator.take(['cm', 'sm'])
34
+ scheduler.harvest.on(_features.FEATURE_TO_ENDPOINT[this.featureName], () => this.makeHarvestPayload(undefined, {
35
+ aggregatorTypes
33
36
  }));
34
37
  this.drain();
35
38
  } else {
@@ -50,7 +53,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
50
53
  const params = {
51
54
  name
52
55
  };
53
- this.agentRef.sharedAggregator.storeMetric(type, name, params, value);
56
+ this.events.addMetric(type, name, params, value);
54
57
  }
55
58
  storeEventMetrics(name, metrics) {
56
59
  if (this.blocked) return;
@@ -58,7 +61,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
58
61
  const params = {
59
62
  name
60
63
  };
61
- this.agentRef.sharedAggregator.store(type, name, params, metrics);
64
+ this.events.add(type, name, params, metrics);
62
65
  }
63
66
  singleChecks() {
64
67
  // report loaderType
@@ -20,7 +20,6 @@ var _largestContentfulPaint = require("../../../common/vitals/largest-contentful
20
20
  var _timeToFirstByte = require("../../../common/vitals/time-to-first-byte");
21
21
  var _pageVisibility = require("../../../common/window/page-visibility");
22
22
  var _constants2 = require("../../../common/vitals/constants");
23
- var _eventBuffer = require("../../utils/event-buffer");
24
23
  /*
25
24
  * Copyright 2020 New Relic Corporation. All rights reserved.
26
25
  * SPDX-License-Identifier: Apache-2.0
@@ -37,7 +36,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
37
36
  };
38
37
  constructor(agentRef) {
39
38
  super(agentRef, _constants.FEATURE_NAME);
40
- this.timings = new _eventBuffer.EventBuffer();
41
39
  this.curSessEndRecorded = false;
42
40
  (0, _registerHandler.registerHandler)('docHidden', msTimestamp => this.endCurrentSession(msTimestamp), this.featureName, this.ee);
43
41
  // Add the time of _window pagehide event_ firing to the next PVT harvest == NRDB windowUnload attr:
@@ -69,9 +67,9 @@ class Aggregate extends _aggregateBase.AggregateBase {
69
67
  this.addTiming(name, value * 1000, attrs);
70
68
  }, true); // CLS node should only reports on vis change rather than on every change
71
69
 
72
- const scheduler = new _harvestScheduler.HarvestScheduler('events', {
73
- onFinished: (...args) => this.onHarvestFinished(...args),
74
- getPayload: (...args) => this.prepareHarvest(...args)
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)
75
73
  }, this);
76
74
  scheduler.startTimer(harvestTimeSeconds);
77
75
  this.drain();
@@ -104,16 +102,13 @@ class Aggregate extends _aggregateBase.AggregateBase {
104
102
  if (name !== _constants2.VITAL_NAMES.CUMULATIVE_LAYOUT_SHIFT && _cumulativeLayoutShift.cumulativeLayoutShift.current.value >= 0) {
105
103
  attrs.cls = _cumulativeLayoutShift.cumulativeLayoutShift.current.value;
106
104
  }
107
- this.timings.add({
105
+ this.events.add({
108
106
  name,
109
107
  value,
110
108
  attrs
111
109
  });
112
110
  (0, _handle.handle)('pvtAdded', [name, value, attrs], undefined, _features.FEATURE_NAMES.sessionTrace, this.ee);
113
111
  }
114
- onHarvestFinished(result) {
115
- if (result.retry && this.timings.held.hasData) this.timings.unhold();else this.timings.held.clear();
116
- }
117
112
  appendGlobalCustomAttributes(timing) {
118
113
  var timingAttributes = timing.attrs || {};
119
114
  var reservedAttributes = ['size', 'eid', 'cls', 'type', 'fid', 'elTag', 'elUrl', 'net-type', 'net-etype', 'net-rtt', 'net-dlink'];
@@ -124,24 +119,12 @@ class Aggregate extends _aggregateBase.AggregateBase {
124
119
  });
125
120
  }
126
121
 
127
- // serialize and return current timing data, clear and save current data for retry
128
- prepareHarvest(options) {
129
- if (!this.timings.hasData) return;
130
- var payload = this.getPayload(this.timings.buffer);
131
- if (options.retry) this.timings.hold();else this.timings.clear();
132
- return {
133
- body: {
134
- e: payload
135
- }
136
- };
137
- }
138
-
139
122
  // serialize array of timing data
140
- getPayload(data) {
123
+ serializer(eventBuffer) {
141
124
  var addString = (0, _belSerializer.getAddStringContext)(this.agentIdentifier);
142
125
  var payload = 'bel.6;';
143
- for (var i = 0; i < data.length; i++) {
144
- var timing = data[i];
126
+ for (var i = 0; i < eventBuffer.length; i++) {
127
+ var timing = eventBuffer[i];
145
128
  payload += 'e,';
146
129
  payload += addString(timing.name) + ',';
147
130
  payload += (0, _belSerializer.nullable)(timing.value, _belSerializer.numeric, false) + ',';
@@ -150,7 +133,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
150
133
  if (attrParts && attrParts.length > 0) {
151
134
  payload += (0, _belSerializer.numeric)(attrParts.length) + ';' + attrParts.join(';');
152
135
  }
153
- if (i + 1 < data.length) payload += ';';
136
+ if (i + 1 < eventBuffer.length) payload += ';';
154
137
  }
155
138
  return payload;
156
139
  }
@@ -55,9 +55,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
55
55
  this.recorder = args?.recorder;
56
56
  this.errorNoticed = args?.errorNoticed || false;
57
57
  (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/Enabled'], undefined, _features.FEATURE_NAMES.metrics, this.ee);
58
- this.ee.on("cfc.".concat(_features.FEATURE_NAMES.jserrors), crossFeatureData => {
59
- crossFeatureData.hasReplay = !!(this.scheduler?.started && this.recorder && this.mode === _constants3.MODE.FULL && !this.blocked && this.entitled);
60
- });
61
58
 
62
59
  // 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.
63
60
  this.ee.on(_constants3.SESSION_EVENTS.RESET, () => {
@@ -83,10 +80,13 @@ class Aggregate extends _aggregateBase.AggregateBase {
83
80
  });
84
81
 
85
82
  // Bespoke logic for blobs endpoint.
86
- this.scheduler = new _harvestScheduler.HarvestScheduler('browser/blobs', {
87
- onFinished: this.onHarvestFinished.bind(this),
83
+ this.scheduler = new _harvestScheduler.HarvestScheduler(_features.FEATURE_TO_ENDPOINT[this.featureName], {
84
+ onFinished: result => this.postHarvestCleanup(result),
88
85
  retryDelay: this.harvestTimeSeconds,
89
- getPayload: this.prepareHarvest.bind(this),
86
+ getPayload: ({
87
+ retry,
88
+ ...opts
89
+ }) => this.makeHarvestPayload(retry, opts),
90
90
  raw: true
91
91
  }, this);
92
92
  (0, _registerHandler.registerHandler)(_constants.SR_EVENT_EMITTER_TYPES.PAUSE, () => {
@@ -135,6 +135,9 @@ class Aggregate extends _aggregateBase.AggregateBase {
135
135
  (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/SamplingRate/Value', sampling_rate], undefined, _features.FEATURE_NAMES.metrics, this.ee);
136
136
  (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/ErrorSamplingRate/Value', error_sampling_rate], undefined, _features.FEATURE_NAMES.metrics, this.ee);
137
137
  }
138
+ replayIsActive() {
139
+ return Boolean(this.scheduler?.started && this.recorder && this.mode === _constants3.MODE.FULL && !this.blocked && this.entitled);
140
+ }
138
141
  handleError(e) {
139
142
  if (this.recorder) this.recorder.currentBufferTarget.hasError = true;
140
143
  // run once
@@ -242,9 +245,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
242
245
  // compressor failed to load, but we can still record without compression as a last ditch effort
243
246
  }
244
247
  }
245
- prepareHarvest({
246
- opts
247
- } = {}) {
248
+ makeHarvestPayload(shouldRetryOnFail, opts) {
248
249
  if (!this.recorder || !this.timeKeeper?.ready || !this.recorder.hasSeenSnapshot) return;
249
250
  const recorderEvents = this.recorder.getEvents();
250
251
  // get the event type and use that to trigger another harvest if needed
@@ -380,7 +381,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
380
381
  body: events
381
382
  };
382
383
  }
383
- onHarvestFinished(result) {
384
+ postHarvestCleanup(result) {
384
385
  // The mutual decision for now is to stop recording and clear buffers if ingest is experiencing 429 rate limiting
385
386
  if (result.status === 429) {
386
387
  this.abort(_constants.ABORT_REASONS.TOO_MANY);
@@ -27,12 +27,12 @@ class RecorderEvents {
27
27
  this.#events.add(event);
28
28
  }
29
29
  get events() {
30
- return this.#events.buffer;
30
+ return this.#events.get();
31
31
  }
32
32
 
33
33
  /** A value which increments with every new mutation node reported. Resets after a harvest is sent */
34
34
  get payloadBytesEstimation() {
35
- return this.#events.bytes;
35
+ return this.#events.byteSize();
36
36
  }
37
37
  }
38
38
  exports.RecorderEvents = RecorderEvents;