@newrelic/browser-agent 1.268.0 → 1.269.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 +14 -0
- package/README.md +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/features/jserrors/aggregate/index.js +21 -1
- package/dist/cjs/features/jserrors/aggregate/internal-errors.js +42 -0
- package/dist/cjs/features/logging/aggregate/index.js +9 -1
- package/dist/cjs/features/session_trace/aggregate/index.js +5 -5
- package/dist/cjs/features/spa/instrument/index.js +4 -0
- package/dist/cjs/loaders/agent-base.js +1 -0
- package/dist/cjs/loaders/micro-agent.js +1 -1
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/features/jserrors/aggregate/index.js +21 -1
- package/dist/esm/features/jserrors/aggregate/internal-errors.js +36 -0
- package/dist/esm/features/logging/aggregate/index.js +9 -1
- package/dist/esm/features/session_trace/aggregate/index.js +5 -5
- package/dist/esm/features/spa/instrument/index.js +4 -0
- package/dist/esm/loaders/agent-base.js +1 -0
- package/dist/esm/loaders/micro-agent.js +1 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts +10 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/internal-errors.d.ts +7 -0
- package/dist/types/features/jserrors/aggregate/internal-errors.d.ts.map +1 -0
- package/dist/types/features/logging/aggregate/index.d.ts +3 -0
- package/dist/types/features/logging/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/spa/instrument/index.d.ts +3 -0
- package/dist/types/features/spa/instrument/index.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/micro-agent.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/features/jserrors/aggregate/index.js +19 -1
- package/src/features/jserrors/aggregate/internal-errors.js +33 -0
- package/src/features/logging/aggregate/index.js +8 -1
- package/src/features/session_trace/aggregate/index.js +6 -6
- package/src/features/spa/instrument/index.js +3 -0
- package/src/loaders/agent-base.js +1 -0
- package/src/loaders/micro-agent.js +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,20 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [1.269.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.268.0...v1.269.0) (2024-10-16)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* Add instrumentation metadata to logging ([#1208](https://github.com/newrelic/newrelic-browser-agent/issues/1208)) ([6926474](https://github.com/newrelic/newrelic-browser-agent/commit/6926474fe2530475e10daab2bb6bad745bb547e1))
|
|
12
|
+
* Include logging feature in micro agent loader ([#1210](https://github.com/newrelic/newrelic-browser-agent/issues/1210)) ([1b24484](https://github.com/newrelic/newrelic-browser-agent/commit/1b2448498cf285f36530f2107cb0403401958b1f))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* Handle Session Replay Security Policy Errors ([#1215](https://github.com/newrelic/newrelic-browser-agent/issues/1215)) ([f14b0fe](https://github.com/newrelic/newrelic-browser-agent/commit/f14b0fec81d7d21b418b6be6c5d415bdd813eca9))
|
|
18
|
+
* Only ever allow session traces to capture page load timings once ([#1212](https://github.com/newrelic/newrelic-browser-agent/issues/1212)) ([d189686](https://github.com/newrelic/newrelic-browser-agent/commit/d1896869858eca3320144113e168f17f524f3119))
|
|
19
|
+
|
|
6
20
|
## [1.268.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.267.0...v1.268.0) (2024-10-08)
|
|
7
21
|
|
|
8
22
|
|
package/README.md
CHANGED
|
@@ -238,7 +238,8 @@ A lot of new frameworks support the concept of server-side rendering the pages o
|
|
|
238
238
|
|
|
239
239
|
## Disclaimers
|
|
240
240
|
|
|
241
|
-
The session replay
|
|
241
|
+
* The session replay feature is not turned on by default. For information on the use of this feature, see [Session Replay](#session-replay)
|
|
242
|
+
* As part of the improvement efforts around our SPA capabilities, the `createTracer` API has been [deprecated](https://docs.newrelic.com/eol/2024/04/eol-04-24-24-createtracer/). Please engage in removing usage of that library. If tracking task duration, we recommend utilizing the generic browser performance mark and measure APIs, which will gain native detection support from the agent in a future update.
|
|
242
243
|
|
|
243
244
|
## Support
|
|
244
245
|
|
|
@@ -12,7 +12,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.DIST_METHOD = exports.BUILD_EN
|
|
|
12
12
|
/**
|
|
13
13
|
* Exposes the version of the agent
|
|
14
14
|
*/
|
|
15
|
-
const VERSION = exports.VERSION = "1.
|
|
15
|
+
const VERSION = exports.VERSION = "1.269.0";
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Exposes the build type of the agent
|
|
@@ -12,7 +12,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.DIST_METHOD = exports.BUILD_EN
|
|
|
12
12
|
/**
|
|
13
13
|
* Exposes the version of the agent
|
|
14
14
|
*/
|
|
15
|
-
const VERSION = exports.VERSION = "1.
|
|
15
|
+
const VERSION = exports.VERSION = "1.269.0";
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Exposes the build type of the agent
|
|
@@ -23,6 +23,8 @@ var _nreum = require("../../../common/window/nreum");
|
|
|
23
23
|
var _drain = require("../../../common/drain/drain");
|
|
24
24
|
var _now = require("../../../common/timing/now");
|
|
25
25
|
var _traverse = require("../../../common/util/traverse");
|
|
26
|
+
var _internalErrors = require("./internal-errors");
|
|
27
|
+
var _constants2 = require("../../metrics/constants");
|
|
26
28
|
/*
|
|
27
29
|
* Copyright 2020 New Relic Corporation. All rights reserved.
|
|
28
30
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -130,6 +132,16 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
130
132
|
}
|
|
131
133
|
return canonicalStackString;
|
|
132
134
|
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
*
|
|
138
|
+
* @param {Error|UncaughtError} err The error instance to be processed
|
|
139
|
+
* @param {number} time the relative ms (to origin) timestamp of occurence
|
|
140
|
+
* @param {boolean=} internal if the error was "caught" and deemed "internal" before reporting to the jserrors feature
|
|
141
|
+
* @param {object=} customAttributes any custom attributes to be included in the error payload
|
|
142
|
+
* @param {boolean=} hasReplay a flag indicating if the error occurred during a replay session
|
|
143
|
+
* @returns
|
|
144
|
+
*/
|
|
133
145
|
storeError(err, time, internal, customAttributes, hasReplay) {
|
|
134
146
|
if (!err) return;
|
|
135
147
|
// are we in an interaction
|
|
@@ -146,6 +158,14 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
146
158
|
// Again as with previous usage, all falsey values would include the error.
|
|
147
159
|
}
|
|
148
160
|
var stackInfo = (0, _computeStackTrace.computeStackTrace)(err);
|
|
161
|
+
const {
|
|
162
|
+
shouldSwallow,
|
|
163
|
+
reason
|
|
164
|
+
} = (0, _internalErrors.evaluateInternalError)(stackInfo, internal);
|
|
165
|
+
if (shouldSwallow) {
|
|
166
|
+
(0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ['Internal/Error/' + reason], undefined, _features.FEATURE_NAMES.metrics, this.ee);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
149
169
|
var canonicalStackString = this.buildCanonicalStackString(stackInfo);
|
|
150
170
|
const params = {
|
|
151
171
|
stackHash: (0, _stringHashCode.stringHashCode)(canonicalStackString),
|
|
@@ -184,7 +204,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
184
204
|
}
|
|
185
205
|
params.firstOccurrenceTimestamp = this.observedAt[bucketHash];
|
|
186
206
|
params.timestamp = Math.floor(agentRuntime.timeKeeper.correctRelativeTimestamp(time));
|
|
187
|
-
var type =
|
|
207
|
+
var type = 'err';
|
|
188
208
|
var newMetrics = {
|
|
189
209
|
time
|
|
190
210
|
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.evaluateInternalError = evaluateInternalError;
|
|
7
|
+
const REASON_RRWEB = 'Rrweb';
|
|
8
|
+
const REASON_SECURITY_POLICY = 'Security-Policy';
|
|
9
|
+
/**
|
|
10
|
+
* This function is responsible for determining if an error should be swallowed or not.
|
|
11
|
+
* @param {Object} stackInfo - The error stack information.
|
|
12
|
+
* @returns {boolean} - Whether the error should be swallowed or not.
|
|
13
|
+
*/
|
|
14
|
+
function evaluateInternalError(stackInfo, internal) {
|
|
15
|
+
const output = {
|
|
16
|
+
shouldSwallow: internal || false,
|
|
17
|
+
reason: 'Other'
|
|
18
|
+
};
|
|
19
|
+
const leadingFrame = stackInfo.frames?.[0];
|
|
20
|
+
/** If we cant otherwise determine from the frames and message, the default of internal + reason will be the fallback */
|
|
21
|
+
if (!leadingFrame || typeof stackInfo?.message !== 'string') return output;
|
|
22
|
+
|
|
23
|
+
// check if the error happened in expected modules or if messages match known patterns
|
|
24
|
+
const isNrRecorder = leadingFrame?.url?.match(/nr-(.*)-recorder.min.js/);
|
|
25
|
+
const isRrweb = leadingFrame?.url?.match(/rrweb/);
|
|
26
|
+
const isMaybeNrRecorder = leadingFrame?.url?.match(/recorder/);
|
|
27
|
+
const isSecurityPolicyAPIError = stackInfo.message.toLowerCase().match(/an attempt was made to break through the security policy of the user agent/);
|
|
28
|
+
|
|
29
|
+
// check if modules and patterns above fit known swallow cases
|
|
30
|
+
if (!!isNrRecorder || !!isRrweb) {
|
|
31
|
+
/** We know -for sure- that the error came from our recorder module or rrweb directly if these are true, so swallow it */
|
|
32
|
+
output.shouldSwallow = true;
|
|
33
|
+
output.reason = REASON_RRWEB;
|
|
34
|
+
if (isSecurityPolicyAPIError) output.reason += '-' + REASON_SECURITY_POLICY;
|
|
35
|
+
} else if (!!isMaybeNrRecorder && isSecurityPolicyAPIError) {
|
|
36
|
+
/** We -suspect- that the error came from NR, so if it matches the exact case we know about, swallow it */
|
|
37
|
+
output.shouldSwallow = true;
|
|
38
|
+
output.reason = REASON_RRWEB + '-' + REASON_SECURITY_POLICY;
|
|
39
|
+
}
|
|
40
|
+
// other swallow conditions could also be added here
|
|
41
|
+
return output;
|
|
42
|
+
}
|
|
@@ -84,6 +84,12 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
84
84
|
}
|
|
85
85
|
prepareHarvest(options = {}) {
|
|
86
86
|
if (this.blocked || !this.bufferedLogs.hasData) return;
|
|
87
|
+
/** These attributes are evaluated and dropped at ingest processing time and do not get stored on NRDB */
|
|
88
|
+
const unbilledAttributes = {
|
|
89
|
+
'instrumentation.provider': 'browser',
|
|
90
|
+
'instrumentation.version': this.#agentRuntime.version,
|
|
91
|
+
'instrumentation.name': this.#agentRuntime.loaderType
|
|
92
|
+
};
|
|
87
93
|
/** see https://source.datanerd.us/agents/rum-specs/blob/main/browser/Log for logging spec */
|
|
88
94
|
const payload = {
|
|
89
95
|
qs: {
|
|
@@ -107,7 +113,9 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
107
113
|
// Application ID from info object,
|
|
108
114
|
standalone: Boolean(this.#agentInfo.sa),
|
|
109
115
|
// copy paste (true) vs APM (false)
|
|
110
|
-
agentVersion: this.#agentRuntime.version
|
|
116
|
+
agentVersion: this.#agentRuntime.version,
|
|
117
|
+
// browser agent version,
|
|
118
|
+
...unbilledAttributes
|
|
111
119
|
}
|
|
112
120
|
},
|
|
113
121
|
/** logs section contains individual unique log entries */
|
|
@@ -66,6 +66,11 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
66
66
|
// 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
|
|
67
67
|
if (this.sessionId !== sessionState.value || eventType === 'cross-tab' && this.scheduler?.started && sessionState.sessionTraceMode === _constants2.MODE.OFF) this.abort(2);
|
|
68
68
|
});
|
|
69
|
+
if (typeof PerformanceNavigationTiming !== 'undefined') {
|
|
70
|
+
this.traceStorage.storeTiming(_runtime2.globalScope.performance?.getEntriesByType?.('navigation')[0]);
|
|
71
|
+
} else {
|
|
72
|
+
this.traceStorage.storeTiming(_runtime2.globalScope.performance?.timing, true);
|
|
73
|
+
}
|
|
69
74
|
}
|
|
70
75
|
|
|
71
76
|
/** ST/SR sampling flow in BCS - https://drive.google.com/file/d/19hwt2oft-8Hh4RrjpLqEXfpP_9wYBLcq/view?usp=sharing */
|
|
@@ -91,11 +96,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
91
96
|
(0, _registerHandler.registerHandler)('bstApi', (...args) => this.traceStorage.storeSTN(...args), this.featureName, this.ee);
|
|
92
97
|
(0, _registerHandler.registerHandler)('trace-jserror', (...args) => this.traceStorage.storeErrorAgg(...args), this.featureName, this.ee);
|
|
93
98
|
(0, _registerHandler.registerHandler)('pvtAdded', (...args) => this.traceStorage.processPVT(...args), this.featureName, this.ee);
|
|
94
|
-
if (typeof PerformanceNavigationTiming !== 'undefined') {
|
|
95
|
-
this.traceStorage.storeTiming(_runtime2.globalScope.performance?.getEntriesByType?.('navigation')[0]);
|
|
96
|
-
} else {
|
|
97
|
-
this.traceStorage.storeTiming(_runtime2.globalScope.performance?.timing, true);
|
|
98
|
-
}
|
|
99
99
|
|
|
100
100
|
/** Only start actually harvesting if running in full mode at init time */
|
|
101
101
|
if (this.mode === _constants2.MODE.FULL) this.startHarvesting();else {
|
|
@@ -36,6 +36,10 @@ const {
|
|
|
36
36
|
CB_START,
|
|
37
37
|
FN_END
|
|
38
38
|
} = CONSTANTS;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @deprecated This feature has been deprecated, in favor of `soft_navigations`, which is in limited preview. Consider using/importing `SoftNavigations` instead. To gain access to the limited preview, please see https://docs.newrelic.com/docs/browser/single-page-app-monitoring/get-started/browser-spa-v2/ for more information. This feature will be removed in a future release.
|
|
42
|
+
*/
|
|
39
43
|
class Instrument extends _instrumentBase.InstrumentBase {
|
|
40
44
|
static featureName = FEATURE_NAME;
|
|
41
45
|
constructor(agentIdentifier, aggregator, auto = true) {
|
|
@@ -176,6 +176,7 @@ class AgentBase {
|
|
|
176
176
|
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/interaction/}
|
|
177
177
|
* @returns {InteractionInstance} An API object that is bound to a specific BrowserInteraction event. Each time this method is called for the same BrowserInteraction, a new object is created, but it still references the same interaction.
|
|
178
178
|
* - Note: Does not apply to MicroAgent
|
|
179
|
+
* - Deprecation Notice: interaction.createTracer is deprecated. See https://docs.newrelic.com/eol/2024/04/eol-04-24-24-createtracer/ for more information.
|
|
179
180
|
*/
|
|
180
181
|
interaction() {
|
|
181
182
|
return this.#callMethod('interaction');
|
|
@@ -20,7 +20,7 @@ var _agentBase = require("./agent-base");
|
|
|
20
20
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
21
21
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } // loader files
|
|
22
22
|
// core files
|
|
23
|
-
const nonAutoFeatures = [_features.FEATURE_NAMES.jserrors, _features.FEATURE_NAMES.genericEvents, _features.FEATURE_NAMES.metrics];
|
|
23
|
+
const nonAutoFeatures = [_features.FEATURE_NAMES.jserrors, _features.FEATURE_NAMES.genericEvents, _features.FEATURE_NAMES.metrics, _features.FEATURE_NAMES.logging];
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* A minimal agent class designed to only respond to manual user input. As such, this class does not
|
|
@@ -22,6 +22,8 @@ import { getNREUMInitializedAgent } from '../../../common/window/nreum';
|
|
|
22
22
|
import { deregisterDrain } from '../../../common/drain/drain';
|
|
23
23
|
import { now } from '../../../common/timing/now';
|
|
24
24
|
import { applyFnToProps } from '../../../common/util/traverse';
|
|
25
|
+
import { evaluateInternalError } from './internal-errors';
|
|
26
|
+
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants';
|
|
25
27
|
|
|
26
28
|
/**
|
|
27
29
|
* @typedef {import('./compute-stack-trace.js').StackInfo} StackInfo
|
|
@@ -125,6 +127,16 @@ export class Aggregate extends AggregateBase {
|
|
|
125
127
|
}
|
|
126
128
|
return canonicalStackString;
|
|
127
129
|
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
*
|
|
133
|
+
* @param {Error|UncaughtError} err The error instance to be processed
|
|
134
|
+
* @param {number} time the relative ms (to origin) timestamp of occurence
|
|
135
|
+
* @param {boolean=} internal if the error was "caught" and deemed "internal" before reporting to the jserrors feature
|
|
136
|
+
* @param {object=} customAttributes any custom attributes to be included in the error payload
|
|
137
|
+
* @param {boolean=} hasReplay a flag indicating if the error occurred during a replay session
|
|
138
|
+
* @returns
|
|
139
|
+
*/
|
|
128
140
|
storeError(err, time, internal, customAttributes, hasReplay) {
|
|
129
141
|
if (!err) return;
|
|
130
142
|
// are we in an interaction
|
|
@@ -141,6 +153,14 @@ export class Aggregate extends AggregateBase {
|
|
|
141
153
|
// Again as with previous usage, all falsey values would include the error.
|
|
142
154
|
}
|
|
143
155
|
var stackInfo = computeStackTrace(err);
|
|
156
|
+
const {
|
|
157
|
+
shouldSwallow,
|
|
158
|
+
reason
|
|
159
|
+
} = evaluateInternalError(stackInfo, internal);
|
|
160
|
+
if (shouldSwallow) {
|
|
161
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Internal/Error/' + reason], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
144
164
|
var canonicalStackString = this.buildCanonicalStackString(stackInfo);
|
|
145
165
|
const params = {
|
|
146
166
|
stackHash: stringHashCode(canonicalStackString),
|
|
@@ -179,7 +199,7 @@ export class Aggregate extends AggregateBase {
|
|
|
179
199
|
}
|
|
180
200
|
params.firstOccurrenceTimestamp = this.observedAt[bucketHash];
|
|
181
201
|
params.timestamp = Math.floor(agentRuntime.timeKeeper.correctRelativeTimestamp(time));
|
|
182
|
-
var type =
|
|
202
|
+
var type = 'err';
|
|
183
203
|
var newMetrics = {
|
|
184
204
|
time
|
|
185
205
|
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const REASON_RRWEB = 'Rrweb';
|
|
2
|
+
const REASON_SECURITY_POLICY = 'Security-Policy';
|
|
3
|
+
/**
|
|
4
|
+
* This function is responsible for determining if an error should be swallowed or not.
|
|
5
|
+
* @param {Object} stackInfo - The error stack information.
|
|
6
|
+
* @returns {boolean} - Whether the error should be swallowed or not.
|
|
7
|
+
*/
|
|
8
|
+
export function evaluateInternalError(stackInfo, internal) {
|
|
9
|
+
const output = {
|
|
10
|
+
shouldSwallow: internal || false,
|
|
11
|
+
reason: 'Other'
|
|
12
|
+
};
|
|
13
|
+
const leadingFrame = stackInfo.frames?.[0];
|
|
14
|
+
/** If we cant otherwise determine from the frames and message, the default of internal + reason will be the fallback */
|
|
15
|
+
if (!leadingFrame || typeof stackInfo?.message !== 'string') return output;
|
|
16
|
+
|
|
17
|
+
// check if the error happened in expected modules or if messages match known patterns
|
|
18
|
+
const isNrRecorder = leadingFrame?.url?.match(/nr-(.*)-recorder.min.js/);
|
|
19
|
+
const isRrweb = leadingFrame?.url?.match(/rrweb/);
|
|
20
|
+
const isMaybeNrRecorder = leadingFrame?.url?.match(/recorder/);
|
|
21
|
+
const isSecurityPolicyAPIError = stackInfo.message.toLowerCase().match(/an attempt was made to break through the security policy of the user agent/);
|
|
22
|
+
|
|
23
|
+
// check if modules and patterns above fit known swallow cases
|
|
24
|
+
if (!!isNrRecorder || !!isRrweb) {
|
|
25
|
+
/** We know -for sure- that the error came from our recorder module or rrweb directly if these are true, so swallow it */
|
|
26
|
+
output.shouldSwallow = true;
|
|
27
|
+
output.reason = REASON_RRWEB;
|
|
28
|
+
if (isSecurityPolicyAPIError) output.reason += '-' + REASON_SECURITY_POLICY;
|
|
29
|
+
} else if (!!isMaybeNrRecorder && isSecurityPolicyAPIError) {
|
|
30
|
+
/** We -suspect- that the error came from NR, so if it matches the exact case we know about, swallow it */
|
|
31
|
+
output.shouldSwallow = true;
|
|
32
|
+
output.reason = REASON_RRWEB + '-' + REASON_SECURITY_POLICY;
|
|
33
|
+
}
|
|
34
|
+
// other swallow conditions could also be added here
|
|
35
|
+
return output;
|
|
36
|
+
}
|
|
@@ -78,6 +78,12 @@ export class Aggregate extends AggregateBase {
|
|
|
78
78
|
}
|
|
79
79
|
prepareHarvest(options = {}) {
|
|
80
80
|
if (this.blocked || !this.bufferedLogs.hasData) return;
|
|
81
|
+
/** These attributes are evaluated and dropped at ingest processing time and do not get stored on NRDB */
|
|
82
|
+
const unbilledAttributes = {
|
|
83
|
+
'instrumentation.provider': 'browser',
|
|
84
|
+
'instrumentation.version': this.#agentRuntime.version,
|
|
85
|
+
'instrumentation.name': this.#agentRuntime.loaderType
|
|
86
|
+
};
|
|
81
87
|
/** see https://source.datanerd.us/agents/rum-specs/blob/main/browser/Log for logging spec */
|
|
82
88
|
const payload = {
|
|
83
89
|
qs: {
|
|
@@ -101,7 +107,9 @@ export class Aggregate extends AggregateBase {
|
|
|
101
107
|
// Application ID from info object,
|
|
102
108
|
standalone: Boolean(this.#agentInfo.sa),
|
|
103
109
|
// copy paste (true) vs APM (false)
|
|
104
|
-
agentVersion: this.#agentRuntime.version
|
|
110
|
+
agentVersion: this.#agentRuntime.version,
|
|
111
|
+
// browser agent version,
|
|
112
|
+
...unbilledAttributes
|
|
105
113
|
}
|
|
106
114
|
},
|
|
107
115
|
/** logs section contains individual unique log entries */
|
|
@@ -60,6 +60,11 @@ export class Aggregate extends AggregateBase {
|
|
|
60
60
|
// 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
|
|
61
61
|
if (this.sessionId !== sessionState.value || eventType === 'cross-tab' && this.scheduler?.started && sessionState.sessionTraceMode === MODE.OFF) this.abort(2);
|
|
62
62
|
});
|
|
63
|
+
if (typeof PerformanceNavigationTiming !== 'undefined') {
|
|
64
|
+
this.traceStorage.storeTiming(globalScope.performance?.getEntriesByType?.('navigation')[0]);
|
|
65
|
+
} else {
|
|
66
|
+
this.traceStorage.storeTiming(globalScope.performance?.timing, true);
|
|
67
|
+
}
|
|
63
68
|
}
|
|
64
69
|
|
|
65
70
|
/** ST/SR sampling flow in BCS - https://drive.google.com/file/d/19hwt2oft-8Hh4RrjpLqEXfpP_9wYBLcq/view?usp=sharing */
|
|
@@ -85,11 +90,6 @@ export class Aggregate extends AggregateBase {
|
|
|
85
90
|
registerHandler('bstApi', (...args) => this.traceStorage.storeSTN(...args), this.featureName, this.ee);
|
|
86
91
|
registerHandler('trace-jserror', (...args) => this.traceStorage.storeErrorAgg(...args), this.featureName, this.ee);
|
|
87
92
|
registerHandler('pvtAdded', (...args) => this.traceStorage.processPVT(...args), this.featureName, this.ee);
|
|
88
|
-
if (typeof PerformanceNavigationTiming !== 'undefined') {
|
|
89
|
-
this.traceStorage.storeTiming(globalScope.performance?.getEntriesByType?.('navigation')[0]);
|
|
90
|
-
} else {
|
|
91
|
-
this.traceStorage.storeTiming(globalScope.performance?.timing, true);
|
|
92
|
-
}
|
|
93
93
|
|
|
94
94
|
/** Only start actually harvesting if running in full mode at init time */
|
|
95
95
|
if (this.mode === MODE.FULL) this.startHarvesting();else {
|
|
@@ -27,6 +27,10 @@ const {
|
|
|
27
27
|
CB_START,
|
|
28
28
|
FN_END
|
|
29
29
|
} = CONSTANTS;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @deprecated This feature has been deprecated, in favor of `soft_navigations`, which is in limited preview. Consider using/importing `SoftNavigations` instead. To gain access to the limited preview, please see https://docs.newrelic.com/docs/browser/single-page-app-monitoring/get-started/browser-spa-v2/ for more information. This feature will be removed in a future release.
|
|
33
|
+
*/
|
|
30
34
|
export class Instrument extends InstrumentBase {
|
|
31
35
|
static featureName = FEATURE_NAME;
|
|
32
36
|
constructor(agentIdentifier, aggregator, auto = true) {
|
|
@@ -171,6 +171,7 @@ export class AgentBase {
|
|
|
171
171
|
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/interaction/}
|
|
172
172
|
* @returns {InteractionInstance} An API object that is bound to a specific BrowserInteraction event. Each time this method is called for the same BrowserInteraction, a new object is created, but it still references the same interaction.
|
|
173
173
|
* - Note: Does not apply to MicroAgent
|
|
174
|
+
* - Deprecation Notice: interaction.createTracer is deprecated. See https://docs.newrelic.com/eol/2024/04/eol-04-24-24-createtracer/ for more information.
|
|
174
175
|
*/
|
|
175
176
|
interaction() {
|
|
176
177
|
return this.#callMethod('interaction');
|
|
@@ -13,7 +13,7 @@ import { FEATURE_NAMES } from './features/features';
|
|
|
13
13
|
import { warn } from '../common/util/console';
|
|
14
14
|
import { onWindowLoad } from '../common/window/load';
|
|
15
15
|
import { AgentBase } from './agent-base';
|
|
16
|
-
const nonAutoFeatures = [FEATURE_NAMES.jserrors, FEATURE_NAMES.genericEvents, FEATURE_NAMES.metrics];
|
|
16
|
+
const nonAutoFeatures = [FEATURE_NAMES.jserrors, FEATURE_NAMES.genericEvents, FEATURE_NAMES.metrics, FEATURE_NAMES.logging];
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* A minimal agent class designed to only respond to manual user input. As such, this class does not
|
|
@@ -25,7 +25,16 @@ export class Aggregate extends AggregateBase {
|
|
|
25
25
|
* @returns {string} A canonical stack string built from the URLs and function names in the given `stackInfo` object.
|
|
26
26
|
*/
|
|
27
27
|
buildCanonicalStackString(stackInfo: StackInfo): string;
|
|
28
|
-
|
|
28
|
+
/**
|
|
29
|
+
*
|
|
30
|
+
* @param {Error|UncaughtError} err The error instance to be processed
|
|
31
|
+
* @param {number} time the relative ms (to origin) timestamp of occurence
|
|
32
|
+
* @param {boolean=} internal if the error was "caught" and deemed "internal" before reporting to the jserrors feature
|
|
33
|
+
* @param {object=} customAttributes any custom attributes to be included in the error payload
|
|
34
|
+
* @param {boolean=} hasReplay a flag indicating if the error occurred during a replay session
|
|
35
|
+
* @returns
|
|
36
|
+
*/
|
|
37
|
+
storeError(err: Error | UncaughtError, time: number, internal?: boolean | undefined, customAttributes?: object | undefined, hasReplay?: boolean | undefined): void;
|
|
29
38
|
onInteractionDone(interaction: any, wasSaved: any): void;
|
|
30
39
|
onSoftNavNotification(interactionId: any, wasFinished: any, softNavAttrs: any): void;
|
|
31
40
|
#private;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/jserrors/aggregate/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/jserrors/aggregate/index.js"],"names":[],"mappings":"AA6BA;;GAEG;AAEH;IACE,2BAAiC;IACjC,mDAgCC;IA7BC,kBAAuB;IACvB,eAAoB;IACpB,qBAA0B;IAC1B,2BAAgC;IAChC,uCAA4B;IAC5B,qBAAwB;IA0B1B;;;MA2BC;IAED,qCAWC;IAED,8BAEC;IAED,oEAMC;IAED;;;;;;OAMG;IACH,qCAHW,SAAS,GACP,MAAM,CAgBlB;IAED;;;;;;;;OAQG;IACH,gBAPW,KAAK,GAAC,aAAa,QACnB,MAAM,aACN,OAAO,YAAC,qBACR,MAAM,YAAC,cACP,OAAO,YAAC,QAsGlB;IA4BD,yDA6BC;IAED,qFAOC;;CAwBF;wBA1TY,OAAO,0BAA0B,EAAE,SAAS;8BAT3B,4BAA4B"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This function is responsible for determining if an error should be swallowed or not.
|
|
3
|
+
* @param {Object} stackInfo - The error stack information.
|
|
4
|
+
* @returns {boolean} - Whether the error should be swallowed or not.
|
|
5
|
+
*/
|
|
6
|
+
export function evaluateInternalError(stackInfo: Object, internal: any): boolean;
|
|
7
|
+
//# sourceMappingURL=internal-errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal-errors.d.ts","sourceRoot":"","sources":["../../../../../src/features/jserrors/aggregate/internal-errors.js"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,iDAHW,MAAM,kBACJ,OAAO,CA2BnB"}
|
|
@@ -14,6 +14,9 @@ export class Aggregate extends AggregateBase {
|
|
|
14
14
|
common: {
|
|
15
15
|
/** Attributes in the `common` section are added to `all` logs generated in the payload */
|
|
16
16
|
attributes: {
|
|
17
|
+
'instrumentation.provider': string;
|
|
18
|
+
'instrumentation.version': any;
|
|
19
|
+
'instrumentation.name': any;
|
|
17
20
|
'entity.guid': any;
|
|
18
21
|
session: any;
|
|
19
22
|
hasReplay: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/logging/aggregate/index.js"],"names":[],"mappings":"AAiBA;IACE,2BAAiC;IAGjC,mDAwBC;IArBC,+BAA+B;IAC/B,0BAAqC;IAKrC,wBAAmG;IAGjG,4BAKQ;IASZ,+EA6CC;IAED;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/logging/aggregate/index.js"],"names":[],"mappings":"AAiBA;IACE,2BAAiC;IAGjC,mDAwBC;IArBC,+BAA+B;IAC/B,0BAAqC;IAKrC,wBAAmG;IAGjG,4BAKQ;IASZ,+EA6CC;IAED;;;;;;gBAeQ,0FAA0F;;;;;;;;;;;;;;;YAa5F,0DAA0D;;;kBAY/D;IAED,qCAGC;;CACF;8BAnI6B,4BAA4B;4BAM9B,0BAA0B;iCAVrB,2CAA2C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_trace/aggregate/index.js"],"names":[],"mappings":"AAkBA;IACE,2BAAiC;IAEjC,mDAmBC;IAjBC,kBAA+C;IAC/C,eAAyC;IAEzC,0FAA0F;IAC1F,wBAAqB;IACrB,wBAA0G;IAC1G,0GAA0G;IAC1G,cAAyB;IACzB,mIAAmI;IACnI,uBAA0B;IAC1B,0CAA0C;IAC1C,oBAAuB;IACvB,wIAAwI;IACxI,2BAA0C;IAM5C,gLAAgL;IAChL,mEAoEC;IA/DG,iCAAuB;IACvB,yJAAyJ;IACzJ,UAAkC;IAClC,eAAuD;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_trace/aggregate/index.js"],"names":[],"mappings":"AAkBA;IACE,2BAAiC;IAEjC,mDAmBC;IAjBC,kBAA+C;IAC/C,eAAyC;IAEzC,0FAA0F;IAC1F,wBAAqB;IACrB,wBAA0G;IAC1G,0GAA0G;IAC1G,cAAyB;IACzB,mIAAmI;IACnI,uBAA0B;IAC1B,0CAA0C;IAC1C,oBAAuB;IACvB,wIAAwI;IACxI,2BAA0C;IAM5C,gLAAgL;IAChL,mEAoEC;IA/DG,iCAAuB;IACvB,yJAAyJ;IACzJ,UAAkC;IAClC,eAAuD;IAyBD,UAA4D;IASpH,wCAKQ;IAuBV,kJAAkJ;IAClJ,wBAIC;IAED,iJAAiJ;IACjJ;;;;;;;;;;MA6DC;IAED;;OAEG;IACH,qCAKC;IAED,8DAA8D;IAC9D,qBAUC;IAED,2DAA2D;IAC3D,yBAKC;CACF;8BAhN6B,4BAA4B;6BAC7B,iBAAiB;iCANb,2CAA2C"}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @deprecated This feature has been deprecated, in favor of `soft_navigations`, which is in limited preview. Consider using/importing `SoftNavigations` instead. To gain access to the limited preview, please see https://docs.newrelic.com/docs/browser/single-page-app-monitoring/get-started/browser-spa-v2/ for more information. This feature will be removed in a future release.
|
|
3
|
+
*/
|
|
1
4
|
export class Instrument extends InstrumentBase {
|
|
2
5
|
static featureName: string;
|
|
3
6
|
constructor(agentIdentifier: any, aggregator: any, auto?: boolean);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/spa/instrument/index.js"],"names":[],"mappings":"AAsBA;IACE,2BAAiC;IACjC,mEAsFC;IAjFG,2CAA0C;;CAwF/C;AAED,oCAA6B;+
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/spa/instrument/index.js"],"names":[],"mappings":"AAsBA;;GAEG;AACH;IACE,2BAAiC;IACjC,mEAsFC;IAjFG,2CAA0C;;CAwF/C;AAED,oCAA6B;+BArHE,6BAA6B"}
|
|
@@ -118,6 +118,7 @@ export class AgentBase {
|
|
|
118
118
|
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/interaction/}
|
|
119
119
|
* @returns {InteractionInstance} An API object that is bound to a specific BrowserInteraction event. Each time this method is called for the same BrowserInteraction, a new object is created, but it still references the same interaction.
|
|
120
120
|
* - Note: Does not apply to MicroAgent
|
|
121
|
+
* - Deprecation Notice: interaction.createTracer is deprecated. See https://docs.newrelic.com/eol/2024/04/eol-04-24-24-createtracer/ for more information.
|
|
121
122
|
*/
|
|
122
123
|
interaction(): InteractionInstance;
|
|
123
124
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-base.d.ts","sourceRoot":"","sources":["../../../src/loaders/agent-base.js"],"names":[],"mappings":"AAMA;;GAEG;AAEH;IAGE,sCAEC;IAJD,wBAAe;IAgBf;;;;;OAKG;IACH,oBAHW,MAAM,wCAKhB;IAED;;;;;OAKG;IACH,sBAHW,MAAM,kCAKhB;IAED;;;;;;OAMG;IACH,yBAJW,MAAM,SACN,MAAM,GAAC,MAAM,GAAC,OAAO,GAAC,IAAI,sCAKpC;IAED;;;;;OAKG;IACH,mBAHW,KAAK,GAAC,MAAM,8CAKtB;IAED;;;;OAIG;IACH,iBAFW,MAAM,GAAC,IAAI,OAIrB;IAED;;;;;;;OAOG;IACH,6BAJW,MAAM,GAAC,IAAI,OAMrB;IAED;;;;OAIG;IACH,0BAFW,CAAC,KAAK,EAAE,KAAK,GAAC,MAAM,KAAK,OAAO,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,OAI9D;IAED;;;;OAIG;IACH,8CAEC;IAED;;;;;OAKG;IACH,iBAHW,MAAM,MACN,MAAM,OAIhB;IAED;;;;OAIG;IACH,yDAEC;IAED;;;;OAIG;IACH,oBAEC;IAED;;;;;OAKG;IACH,mBAEC;IAED;;;;;;;;;;OAUG;IACH,6BARW;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAC,OAUrF;IAED;;;;;OAKG;IACH,0BAHW,MAAM,OAKhB;IAED
|
|
1
|
+
{"version":3,"file":"agent-base.d.ts","sourceRoot":"","sources":["../../../src/loaders/agent-base.js"],"names":[],"mappings":"AAMA;;GAEG;AAEH;IAGE,sCAEC;IAJD,wBAAe;IAgBf;;;;;OAKG;IACH,oBAHW,MAAM,wCAKhB;IAED;;;;;OAKG;IACH,sBAHW,MAAM,kCAKhB;IAED;;;;;;OAMG;IACH,yBAJW,MAAM,SACN,MAAM,GAAC,MAAM,GAAC,OAAO,GAAC,IAAI,sCAKpC;IAED;;;;;OAKG;IACH,mBAHW,KAAK,GAAC,MAAM,8CAKtB;IAED;;;;OAIG;IACH,iBAFW,MAAM,GAAC,IAAI,OAIrB;IAED;;;;;;;OAOG;IACH,6BAJW,MAAM,GAAC,IAAI,OAMrB;IAED;;;;OAIG;IACH,0BAFW,CAAC,KAAK,EAAE,KAAK,GAAC,MAAM,KAAK,OAAO,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,OAI9D;IAED;;;;OAIG;IACH,8CAEC;IAED;;;;;OAKG;IACH,iBAHW,MAAM,MACN,MAAM,OAIhB;IAED;;;;OAIG;IACH,yDAEC;IAED;;;;OAIG;IACH,oBAEC;IAED;;;;;OAKG;IACH,mBAEC;IAED;;;;;;;;;;OAUG;IACH,6BARW;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAC,OAUrF;IAED;;;;;OAKG;IACH,0BAHW,MAAM,OAKhB;IAED;;;;;;MAME;IACF,eAJa,mBAAmB,CAM/B;IAED;;;;;MAKE;IACF,aAHW,MAAM;2BACc,MAAM;gBAAU,OAAO,GAAC,OAAO,GAAC,OAAO,GAAC,MAAM,GAAC,MAAM;wBAInF;IAED;;;;;;MAME;IACF,mBAJW,MAAM,gBACN,MAAM;2BACc,MAAM;gBAAU,OAAO,GAAC,OAAO,GAAC,OAAO,GAAC,MAAM,GAAC,MAAM;wBAInF;;CACF;kCAlMY,OAAO,yBAAyB,EAAE,mBAAmB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"micro-agent.d.ts","sourceRoot":"","sources":["../../../src/loaders/micro-agent.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"micro-agent.d.ts","sourceRoot":"","sources":["../../../src/loaders/micro-agent.js"],"names":[],"mappings":"AAuBA;;;;GAIG;AACH;IACE;;;OAGG;IACH,qBAHW,MAAM,oBACN,MAAM,YAAC,EAmBjB;IAdC,6BAAiF;IACjF,aAAkB;IAMlB;;;;OAIG;IACH,yCAA2C;IAI7C;;;;;MAOC;IAED,mCAyCC;CACF;0BAzFyB,cAAc;2BATb,gCAAgC"}
|
package/package.json
CHANGED
|
@@ -24,6 +24,8 @@ import { getNREUMInitializedAgent } from '../../../common/window/nreum'
|
|
|
24
24
|
import { deregisterDrain } from '../../../common/drain/drain'
|
|
25
25
|
import { now } from '../../../common/timing/now'
|
|
26
26
|
import { applyFnToProps } from '../../../common/util/traverse'
|
|
27
|
+
import { evaluateInternalError } from './internal-errors'
|
|
28
|
+
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants'
|
|
27
29
|
|
|
28
30
|
/**
|
|
29
31
|
* @typedef {import('./compute-stack-trace.js').StackInfo} StackInfo
|
|
@@ -142,6 +144,15 @@ export class Aggregate extends AggregateBase {
|
|
|
142
144
|
return canonicalStackString
|
|
143
145
|
}
|
|
144
146
|
|
|
147
|
+
/**
|
|
148
|
+
*
|
|
149
|
+
* @param {Error|UncaughtError} err The error instance to be processed
|
|
150
|
+
* @param {number} time the relative ms (to origin) timestamp of occurence
|
|
151
|
+
* @param {boolean=} internal if the error was "caught" and deemed "internal" before reporting to the jserrors feature
|
|
152
|
+
* @param {object=} customAttributes any custom attributes to be included in the error payload
|
|
153
|
+
* @param {boolean=} hasReplay a flag indicating if the error occurred during a replay session
|
|
154
|
+
* @returns
|
|
155
|
+
*/
|
|
145
156
|
storeError (err, time, internal, customAttributes, hasReplay) {
|
|
146
157
|
if (!err) return
|
|
147
158
|
// are we in an interaction
|
|
@@ -160,6 +171,13 @@ export class Aggregate extends AggregateBase {
|
|
|
160
171
|
}
|
|
161
172
|
|
|
162
173
|
var stackInfo = computeStackTrace(err)
|
|
174
|
+
|
|
175
|
+
const { shouldSwallow, reason } = evaluateInternalError(stackInfo, internal)
|
|
176
|
+
if (shouldSwallow) {
|
|
177
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Internal/Error/' + reason], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
178
|
+
return
|
|
179
|
+
}
|
|
180
|
+
|
|
163
181
|
var canonicalStackString = this.buildCanonicalStackString(stackInfo)
|
|
164
182
|
|
|
165
183
|
const params = {
|
|
@@ -203,7 +221,7 @@ export class Aggregate extends AggregateBase {
|
|
|
203
221
|
params.firstOccurrenceTimestamp = this.observedAt[bucketHash]
|
|
204
222
|
params.timestamp = Math.floor(agentRuntime.timeKeeper.correctRelativeTimestamp(time))
|
|
205
223
|
|
|
206
|
-
var type =
|
|
224
|
+
var type = 'err'
|
|
207
225
|
var newMetrics = { time }
|
|
208
226
|
|
|
209
227
|
// Trace sends the error in its payload, and both trace & replay simply listens for any error to occur.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const REASON_RRWEB = 'Rrweb'
|
|
2
|
+
const REASON_SECURITY_POLICY = 'Security-Policy'
|
|
3
|
+
/**
|
|
4
|
+
* This function is responsible for determining if an error should be swallowed or not.
|
|
5
|
+
* @param {Object} stackInfo - The error stack information.
|
|
6
|
+
* @returns {boolean} - Whether the error should be swallowed or not.
|
|
7
|
+
*/
|
|
8
|
+
export function evaluateInternalError (stackInfo, internal) {
|
|
9
|
+
const output = { shouldSwallow: internal || false, reason: 'Other' }
|
|
10
|
+
const leadingFrame = stackInfo.frames?.[0]
|
|
11
|
+
/** If we cant otherwise determine from the frames and message, the default of internal + reason will be the fallback */
|
|
12
|
+
if (!leadingFrame || typeof stackInfo?.message !== 'string') return output
|
|
13
|
+
|
|
14
|
+
// check if the error happened in expected modules or if messages match known patterns
|
|
15
|
+
const isNrRecorder = leadingFrame?.url?.match(/nr-(.*)-recorder.min.js/)
|
|
16
|
+
const isRrweb = leadingFrame?.url?.match(/rrweb/)
|
|
17
|
+
const isMaybeNrRecorder = leadingFrame?.url?.match(/recorder/)
|
|
18
|
+
const isSecurityPolicyAPIError = stackInfo.message.toLowerCase().match(/an attempt was made to break through the security policy of the user agent/)
|
|
19
|
+
|
|
20
|
+
// check if modules and patterns above fit known swallow cases
|
|
21
|
+
if (!!isNrRecorder || !!isRrweb) {
|
|
22
|
+
/** We know -for sure- that the error came from our recorder module or rrweb directly if these are true, so swallow it */
|
|
23
|
+
output.shouldSwallow = true
|
|
24
|
+
output.reason = REASON_RRWEB
|
|
25
|
+
if (isSecurityPolicyAPIError) output.reason += '-' + REASON_SECURITY_POLICY
|
|
26
|
+
} else if (!!isMaybeNrRecorder && isSecurityPolicyAPIError) {
|
|
27
|
+
/** We -suspect- that the error came from NR, so if it matches the exact case we know about, swallow it */
|
|
28
|
+
output.shouldSwallow = true
|
|
29
|
+
output.reason = REASON_RRWEB + '-' + REASON_SECURITY_POLICY
|
|
30
|
+
}
|
|
31
|
+
// other swallow conditions could also be added here
|
|
32
|
+
return output
|
|
33
|
+
}
|
|
@@ -94,6 +94,12 @@ export class Aggregate extends AggregateBase {
|
|
|
94
94
|
|
|
95
95
|
prepareHarvest (options = {}) {
|
|
96
96
|
if (this.blocked || !this.bufferedLogs.hasData) return
|
|
97
|
+
/** These attributes are evaluated and dropped at ingest processing time and do not get stored on NRDB */
|
|
98
|
+
const unbilledAttributes = {
|
|
99
|
+
'instrumentation.provider': 'browser',
|
|
100
|
+
'instrumentation.version': this.#agentRuntime.version,
|
|
101
|
+
'instrumentation.name': this.#agentRuntime.loaderType
|
|
102
|
+
}
|
|
97
103
|
/** see https://source.datanerd.us/agents/rum-specs/blob/main/browser/Log for logging spec */
|
|
98
104
|
const payload = {
|
|
99
105
|
qs: {
|
|
@@ -110,7 +116,8 @@ export class Aggregate extends AggregateBase {
|
|
|
110
116
|
ptid: this.#agentRuntime.ptid, // page trace id
|
|
111
117
|
appId: this.#agentInfo.applicationID, // Application ID from info object,
|
|
112
118
|
standalone: Boolean(this.#agentInfo.sa), // copy paste (true) vs APM (false)
|
|
113
|
-
agentVersion: this.#agentRuntime.version // browser agent version
|
|
119
|
+
agentVersion: this.#agentRuntime.version, // browser agent version,
|
|
120
|
+
...unbilledAttributes
|
|
114
121
|
}
|
|
115
122
|
},
|
|
116
123
|
/** logs section contains individual unique log entries */
|
|
@@ -64,6 +64,12 @@ export class Aggregate extends AggregateBase {
|
|
|
64
64
|
// 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
|
|
65
65
|
if (this.sessionId !== sessionState.value || (eventType === 'cross-tab' && this.scheduler?.started && sessionState.sessionTraceMode === MODE.OFF)) this.abort(2)
|
|
66
66
|
})
|
|
67
|
+
|
|
68
|
+
if (typeof PerformanceNavigationTiming !== 'undefined') {
|
|
69
|
+
this.traceStorage.storeTiming(globalScope.performance?.getEntriesByType?.('navigation')[0])
|
|
70
|
+
} else {
|
|
71
|
+
this.traceStorage.storeTiming(globalScope.performance?.timing, true)
|
|
72
|
+
}
|
|
67
73
|
}
|
|
68
74
|
|
|
69
75
|
/** ST/SR sampling flow in BCS - https://drive.google.com/file/d/19hwt2oft-8Hh4RrjpLqEXfpP_9wYBLcq/view?usp=sharing */
|
|
@@ -93,12 +99,6 @@ export class Aggregate extends AggregateBase {
|
|
|
93
99
|
registerHandler('trace-jserror', (...args) => this.traceStorage.storeErrorAgg(...args), this.featureName, this.ee)
|
|
94
100
|
registerHandler('pvtAdded', (...args) => this.traceStorage.processPVT(...args), this.featureName, this.ee)
|
|
95
101
|
|
|
96
|
-
if (typeof PerformanceNavigationTiming !== 'undefined') {
|
|
97
|
-
this.traceStorage.storeTiming(globalScope.performance?.getEntriesByType?.('navigation')[0])
|
|
98
|
-
} else {
|
|
99
|
-
this.traceStorage.storeTiming(globalScope.performance?.timing, true)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
102
|
/** Only start actually harvesting if running in full mode at init time */
|
|
103
103
|
if (this.mode === MODE.FULL) this.startHarvesting()
|
|
104
104
|
else {
|
|
@@ -20,6 +20,9 @@ const {
|
|
|
20
20
|
FEATURE_NAME, START, END, BODY, CB_END, JS_TIME, FETCH, FN_START, CB_START, FN_END
|
|
21
21
|
} = CONSTANTS
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @deprecated This feature has been deprecated, in favor of `soft_navigations`, which is in limited preview. Consider using/importing `SoftNavigations` instead. To gain access to the limited preview, please see https://docs.newrelic.com/docs/browser/single-page-app-monitoring/get-started/browser-spa-v2/ for more information. This feature will be removed in a future release.
|
|
25
|
+
*/
|
|
23
26
|
export class Instrument extends InstrumentBase {
|
|
24
27
|
static featureName = FEATURE_NAME
|
|
25
28
|
constructor (agentIdentifier, aggregator, auto = true) {
|
|
@@ -173,6 +173,7 @@ export class AgentBase {
|
|
|
173
173
|
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/interaction/}
|
|
174
174
|
* @returns {InteractionInstance} An API object that is bound to a specific BrowserInteraction event. Each time this method is called for the same BrowserInteraction, a new object is created, but it still references the same interaction.
|
|
175
175
|
* - Note: Does not apply to MicroAgent
|
|
176
|
+
* - Deprecation Notice: interaction.createTracer is deprecated. See https://docs.newrelic.com/eol/2024/04/eol-04-24-24-createtracer/ for more information.
|
|
176
177
|
*/
|
|
177
178
|
interaction () {
|
|
178
179
|
return this.#callMethod('interaction')
|