@newrelic/browser-agent 1.256.1 → 1.258.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 +32 -0
- package/dist/cjs/common/config/state/configurable.js +8 -5
- package/dist/cjs/common/config/state/init.js +0 -2
- package/dist/cjs/common/config/state/runtime.js +10 -8
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/constants/runtime.js +8 -2
- package/dist/cjs/common/harvest/harvest.js +7 -5
- package/dist/cjs/common/session/constants.js +1 -0
- package/dist/cjs/common/session/session-entity.js +3 -0
- package/dist/cjs/common/timing/time-keeper.js +45 -9
- package/dist/cjs/common/vitals/time-to-first-byte.js +1 -1
- package/dist/cjs/common/vitals/vital-metric.js +1 -1
- package/dist/cjs/features/ajax/aggregate/chunk.js +50 -0
- package/dist/cjs/features/ajax/aggregate/index.js +131 -191
- package/dist/cjs/features/ajax/instrument/index.js +0 -3
- package/dist/cjs/features/jserrors/aggregate/index.js +26 -13
- package/dist/cjs/features/page_view_event/aggregate/index.js +3 -3
- package/dist/cjs/features/session_replay/aggregate/index.js +12 -5
- package/dist/cjs/features/session_replay/constants.js +2 -1
- package/dist/cjs/features/session_replay/instrument/index.js +15 -5
- package/dist/cjs/features/session_replay/shared/recorder.js +6 -3
- package/dist/cjs/features/session_replay/shared/utils.js +9 -8
- package/dist/cjs/features/session_trace/aggregate/index.js +3 -5
- package/dist/cjs/features/soft_navigations/aggregate/index.js +2 -2
- package/dist/cjs/features/spa/instrument/index.js +0 -2
- package/dist/cjs/features/utils/agent-session.js +1 -5
- package/dist/cjs/features/utils/instrument-base.js +11 -14
- package/dist/cjs/features/utils/nr1-debugger.js +27 -0
- package/dist/cjs/loaders/agent.js +4 -0
- package/dist/cjs/loaders/api/apiAsync.js +5 -4
- package/dist/esm/common/config/state/configurable.js +8 -5
- package/dist/esm/common/config/state/init.js +0 -2
- package/dist/esm/common/config/state/runtime.js +11 -9
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/constants/runtime.js +7 -1
- package/dist/esm/common/harvest/harvest.js +7 -5
- package/dist/esm/common/session/constants.js +1 -0
- package/dist/esm/common/session/session-entity.js +3 -0
- package/dist/esm/common/timing/time-keeper.js +46 -9
- package/dist/esm/common/vitals/time-to-first-byte.js +2 -2
- package/dist/esm/common/vitals/vital-metric.js +1 -1
- package/dist/esm/features/ajax/aggregate/chunk.js +43 -0
- package/dist/esm/features/ajax/aggregate/index.js +130 -191
- package/dist/esm/features/ajax/instrument/index.js +1 -4
- package/dist/esm/features/jserrors/aggregate/index.js +26 -13
- package/dist/esm/features/page_view_event/aggregate/index.js +4 -4
- package/dist/esm/features/session_replay/aggregate/index.js +12 -5
- package/dist/esm/features/session_replay/constants.js +2 -1
- package/dist/esm/features/session_replay/instrument/index.js +16 -6
- package/dist/esm/features/session_replay/shared/recorder.js +6 -3
- package/dist/esm/features/session_replay/shared/utils.js +9 -7
- package/dist/esm/features/session_trace/aggregate/index.js +3 -5
- package/dist/esm/features/soft_navigations/aggregate/index.js +2 -2
- package/dist/esm/features/spa/instrument/index.js +0 -2
- package/dist/esm/features/utils/agent-session.js +1 -5
- package/dist/esm/features/utils/instrument-base.js +11 -14
- package/dist/esm/features/utils/nr1-debugger.js +21 -0
- package/dist/esm/loaders/agent.js +4 -0
- package/dist/esm/loaders/api/apiAsync.js +5 -4
- package/dist/types/common/config/state/configurable.d.ts.map +1 -1
- package/dist/types/common/config/state/init.d.ts.map +1 -1
- package/dist/types/common/config/state/runtime.d.ts.map +1 -1
- package/dist/types/common/constants/runtime.d.ts +6 -1
- package/dist/types/common/constants/runtime.d.ts.map +1 -1
- package/dist/types/common/harvest/harvest.d.ts +1 -1
- package/dist/types/common/harvest/harvest.d.ts.map +1 -1
- package/dist/types/common/session/constants.d.ts +1 -0
- package/dist/types/common/session/session-entity.d.ts.map +1 -1
- package/dist/types/common/timing/time-keeper.d.ts +1 -1
- package/dist/types/common/timing/time-keeper.d.ts.map +1 -1
- package/dist/types/features/ajax/aggregate/chunk.d.ts +8 -0
- package/dist/types/features/ajax/aggregate/chunk.d.ts.map +1 -0
- package/dist/types/features/ajax/aggregate/index.d.ts +8 -6
- package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/ajax/instrument/index.d.ts +2 -2
- package/dist/types/features/ajax/instrument/index.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts +0 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts +0 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/constants.d.ts +1 -0
- package/dist/types/features/session_replay/constants.d.ts.map +1 -1
- package/dist/types/features/session_replay/instrument/index.d.ts +1 -0
- package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/recorder.d.ts +1 -0
- package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/utils.d.ts +5 -5
- package/dist/types/features/session_replay/shared/utils.d.ts.map +1 -1
- package/dist/types/features/session_trace/aggregate/index.d.ts +8 -8
- package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/spa/instrument/index.d.ts.map +1 -1
- package/dist/types/features/utils/agent-session.d.ts.map +1 -1
- package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
- package/dist/types/features/utils/nr1-debugger.d.ts +2 -0
- package/dist/types/features/utils/nr1-debugger.d.ts.map +1 -0
- package/dist/types/loaders/agent.d.ts +5 -1
- package/dist/types/loaders/agent.d.ts.map +1 -1
- package/dist/types/loaders/api/apiAsync.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/common/config/state/configurable.js +9 -8
- package/src/common/config/state/init.js +0 -1
- package/src/common/config/state/runtime.js +12 -9
- package/src/common/constants/__mocks__/runtime.js +2 -0
- package/src/common/constants/runtime.js +6 -1
- package/src/common/drain/__mocks__/drain.js +2 -0
- package/src/common/harvest/harvest.js +8 -6
- package/src/common/session/constants.js +1 -0
- package/src/common/session/session-entity.js +2 -0
- package/src/common/timing/time-keeper.js +44 -10
- package/src/common/vitals/time-to-first-byte.js +2 -2
- package/src/common/vitals/vital-metric.js +1 -1
- package/src/common/window/__mocks__/load.js +3 -0
- package/src/features/ajax/aggregate/chunk.js +51 -0
- package/src/features/ajax/aggregate/index.js +128 -200
- package/src/features/ajax/instrument/index.js +1 -4
- package/src/features/jserrors/aggregate/index.js +28 -11
- package/src/features/page_view_event/aggregate/index.js +4 -4
- package/src/features/session_replay/aggregate/index.js +19 -7
- package/src/features/session_replay/constants.js +2 -1
- package/src/features/session_replay/instrument/index.js +16 -6
- package/src/features/session_replay/shared/__mocks__/utils.js +2 -0
- package/src/features/session_replay/shared/recorder.js +7 -4
- package/src/features/session_replay/shared/utils.js +9 -7
- package/src/features/session_trace/aggregate/index.js +3 -6
- package/src/features/soft_navigations/aggregate/index.js +2 -2
- package/src/features/spa/instrument/index.js +0 -3
- package/src/features/utils/__mocks__/agent-session.js +1 -0
- package/src/features/utils/__mocks__/feature-base.js +11 -0
- package/src/features/utils/agent-session.js +1 -7
- package/src/features/utils/instrument-base.js +11 -14
- package/src/features/utils/nr1-debugger.js +22 -0
- package/src/loaders/agent.js +4 -0
- package/src/loaders/api/apiAsync.js +5 -4
- package/dist/cjs/common/storage/first-party-cookies.js +0 -36
- package/dist/esm/common/storage/first-party-cookies.js +0 -29
- package/dist/types/common/storage/first-party-cookies.d.ts +0 -8
- package/dist/types/common/storage/first-party-cookies.d.ts.map +0 -1
- package/src/common/storage/first-party-cookies.js +0 -32
|
@@ -5,16 +5,17 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.buildNRMetaNode = buildNRMetaNode;
|
|
7
7
|
exports.canImportReplayAgg = canImportReplayAgg;
|
|
8
|
-
exports.enableSessionTracking =
|
|
8
|
+
exports.enableSessionTracking = enableSessionTracking;
|
|
9
9
|
exports.isPreloadAllowed = isPreloadAllowed;
|
|
10
10
|
var _config = require("../../../common/config/config");
|
|
11
11
|
var _runtime = require("../../../common/constants/runtime");
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
function enableSessionTracking(agentId) {
|
|
13
|
+
return _runtime.isBrowserScope && (0, _config.getConfigurationValue)(agentId, 'privacy.cookies_enabled') === true;
|
|
14
|
+
}
|
|
14
15
|
function hasReplayPrerequisite(agentId) {
|
|
15
|
-
return _config.originals.MO &&
|
|
16
|
+
return !!_config.originals.MO &&
|
|
16
17
|
// Session Replay cannot work without Mutation Observer
|
|
17
|
-
enableSessionTracking &&
|
|
18
|
+
enableSessionTracking(agentId) &&
|
|
18
19
|
// requires session tracking to be running (hence "session" replay...)
|
|
19
20
|
(0, _config.getConfigurationValue)(agentId, 'session_trace.enabled') === true; // Session Replay as of now is tightly coupled with Session Trace in the UI
|
|
20
21
|
}
|
|
@@ -31,8 +32,8 @@ function buildNRMetaNode(timestamp, timeKeeper) {
|
|
|
31
32
|
originalTimestamp: timestamp,
|
|
32
33
|
correctedTimestamp,
|
|
33
34
|
timestampDiff: timestamp - correctedTimestamp,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
originTime: _runtime.originTime,
|
|
36
|
+
correctedOriginTime: timeKeeper.correctedOriginTime,
|
|
37
|
+
originTimeDiff: Math.floor(_runtime.originTime - timeKeeper.correctedOriginTime)
|
|
37
38
|
};
|
|
38
39
|
}
|
|
@@ -14,6 +14,7 @@ var _replayMode = require("../../session_replay/shared/replay-mode");
|
|
|
14
14
|
var _aggregateBase = require("../../utils/aggregate-base");
|
|
15
15
|
var _constants2 = require("../../../common/session/constants");
|
|
16
16
|
var _now = require("../../../common/timing/now");
|
|
17
|
+
var _runtime = require("../../../common/constants/runtime");
|
|
17
18
|
/*
|
|
18
19
|
* Copyright 2020 New Relic Corporation. All rights reserved.
|
|
19
20
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -53,9 +54,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
53
54
|
super(agentIdentifier, aggregator, _constants.FEATURE_NAME);
|
|
54
55
|
_this = this;
|
|
55
56
|
this.agentRuntime = (0, _config.getRuntime)(agentIdentifier);
|
|
56
|
-
|
|
57
|
-
// Very unlikely, but in case the existing XMLHttpRequest.prototype object on the page couldn't be wrapped.
|
|
58
|
-
if (!this.agentRuntime.xhrWrappable) return;
|
|
59
57
|
this.resourceObserver = argsObj?.resourceObserver; // undefined if observer couldn't be created
|
|
60
58
|
this.ptid = '';
|
|
61
59
|
this.trace = {};
|
|
@@ -538,13 +536,13 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
538
536
|
}
|
|
539
537
|
return {
|
|
540
538
|
qs: {
|
|
541
|
-
st:
|
|
539
|
+
st: _runtime.originTime,
|
|
542
540
|
/** hr === "hasReplay" in NR1, standalone is always checked and processed before harvesting
|
|
543
541
|
* so a race condition between ST and SR states should not be a concern if implemented here */
|
|
544
542
|
hr: Number(!this.isStandalone),
|
|
545
543
|
/** fts === "firstTimestamp" in NR1, indicates what the earliest NODE timestamp was
|
|
546
544
|
* so that blob parsing doesn't need to happen to support UI/API functions */
|
|
547
|
-
fts:
|
|
545
|
+
fts: _runtime.originTime + earliestTimeStamp,
|
|
548
546
|
/** n === "nodeCount" in NR1, a count of nodes in the ST payload, so that blob parsing doesn't need to happen to support UI/API functions */
|
|
549
547
|
n: stns.length,
|
|
550
548
|
// node count
|
|
@@ -88,7 +88,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
88
88
|
if (!firstIxnStartTime) firstIxnStartTime = Math.floor(interaction.start);
|
|
89
89
|
}
|
|
90
90
|
const payload = "bel.7;".concat(serializedIxnList.join(';'));
|
|
91
|
-
if (options.retry) this.interactionsAwaitingRetry
|
|
91
|
+
if (options.retry) this.interactionsAwaitingRetry = this.interactionsToHarvest;
|
|
92
92
|
this.interactionsToHarvest = [];
|
|
93
93
|
return {
|
|
94
94
|
body: {
|
|
@@ -99,8 +99,8 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
99
99
|
onHarvestFinished(result) {
|
|
100
100
|
if (result.sent && result.retry && this.interactionsAwaitingRetry.length > 0) {
|
|
101
101
|
this.interactionsToHarvest = [...this.interactionsAwaitingRetry, ...this.interactionsToHarvest];
|
|
102
|
-
this.interactionsAwaitingRetry = [];
|
|
103
102
|
}
|
|
103
|
+
this.interactionsAwaitingRetry = [];
|
|
104
104
|
}
|
|
105
105
|
startUIInteraction(eventName, startedAt, sourceElem) {
|
|
106
106
|
// this is throttled by instrumentation so that it isn't excessively called
|
|
@@ -7,7 +7,6 @@ exports.Instrument = void 0;
|
|
|
7
7
|
var _wrap = require("../../../common/wrap");
|
|
8
8
|
var _eventListenerOpts = require("../../../common/event-listener/event-listener-opts");
|
|
9
9
|
var _instrumentBase = require("../../utils/instrument-base");
|
|
10
|
-
var _config = require("../../../common/config/config");
|
|
11
10
|
var CONSTANTS = _interopRequireWildcard(require("../constants"));
|
|
12
11
|
var _runtime = require("../../../common/constants/runtime");
|
|
13
12
|
var _now = require("../../../common/timing/now");
|
|
@@ -37,7 +36,6 @@ class Instrument extends _instrumentBase.InstrumentBase {
|
|
|
37
36
|
super(agentIdentifier, aggregator, FEATURE_NAME, auto);
|
|
38
37
|
if (!_runtime.isBrowserScope) return; // SPA not supported outside web env
|
|
39
38
|
|
|
40
|
-
if (!(0, _config.getRuntime)(agentIdentifier).xhrWrappable) return;
|
|
41
39
|
try {
|
|
42
40
|
this.removeOnAbort = new AbortController();
|
|
43
41
|
} catch (e) {}
|
|
@@ -10,20 +10,16 @@ var _contextualEe = require("../../common/event-emitter/contextual-ee");
|
|
|
10
10
|
var _registerHandler = require("../../common/event-emitter/register-handler");
|
|
11
11
|
var _sessionEntity = require("../../common/session/session-entity");
|
|
12
12
|
var _localStorage = require("../../common/storage/local-storage.js");
|
|
13
|
-
var _firstPartyCookies = require("../../common/storage/first-party-cookies");
|
|
14
13
|
var _constants = require("../../common/session/constants");
|
|
15
14
|
let ranOnce = 0;
|
|
16
15
|
function setupAgentSession(agentIdentifier) {
|
|
17
16
|
const agentRuntime = (0, _config.getRuntime)(agentIdentifier);
|
|
18
17
|
if (ranOnce++) return agentRuntime.session;
|
|
19
18
|
const sessionInit = (0, _config.getConfiguration)(agentIdentifier).session;
|
|
20
|
-
/* Domain is a string that can be specified by customer. The only way to keep the session object across subdomains is using first party cookies.
|
|
21
|
-
This determines which storage wrapper the session manager will use to keep state. */
|
|
22
|
-
const storageTypeInst = sessionInit?.domain ? new _firstPartyCookies.FirstPartyCookies(sessionInit.domain) : new _localStorage.LocalStorage();
|
|
23
19
|
agentRuntime.session = new _sessionEntity.SessionEntity({
|
|
24
20
|
agentIdentifier,
|
|
25
21
|
key: _constants.DEFAULT_KEY,
|
|
26
|
-
storage:
|
|
22
|
+
storage: new _localStorage.LocalStorage(),
|
|
27
23
|
expiresMs: sessionInit?.expiresMs,
|
|
28
24
|
inactiveMs: sessionInit?.inactiveMs
|
|
29
25
|
});
|
|
@@ -12,6 +12,7 @@ var _console = require("../../common/util/console");
|
|
|
12
12
|
var _features = require("../../loaders/features/features");
|
|
13
13
|
var _config = require("../../common/config/config");
|
|
14
14
|
var _utils = require("../session_replay/shared/utils");
|
|
15
|
+
var _invoke = require("../../common/util/invoke");
|
|
15
16
|
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); }
|
|
16
17
|
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 && Object.prototype.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; } /**
|
|
17
18
|
* @file Defines `InstrumentBase` to be used as the super of the Instrument classes implemented by each feature.
|
|
@@ -55,7 +56,15 @@ class InstrumentBase extends _featureBase.FeatureBase {
|
|
|
55
56
|
/** used in conjunction with newrelic.start() to defer harvesting in features */
|
|
56
57
|
if ((0, _config.getConfigurationValue)(this.agentIdentifier, "".concat(this.featureName, ".autoStart")) === false) this.auto = false;
|
|
57
58
|
/** if the feature requires opt-in (!auto-start), it will get registered once the api has been called */
|
|
58
|
-
if (this.auto) (0, _drain.registerDrain)(agentIdentifier, featureName);
|
|
59
|
+
if (this.auto) (0, _drain.registerDrain)(agentIdentifier, featureName);else {
|
|
60
|
+
this.ee.on("".concat(this.featureName, "-opt-in"), (0, _invoke.single)(() => {
|
|
61
|
+
// register the feature to drain only once the API has been called, it will drain when importAggregator finishes for all the features
|
|
62
|
+
// called by the api in that cycle
|
|
63
|
+
(0, _drain.registerDrain)(this.agentIdentifier, this.featureName);
|
|
64
|
+
this.auto = true;
|
|
65
|
+
this.importAggregator();
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
59
68
|
}
|
|
60
69
|
|
|
61
70
|
/**
|
|
@@ -66,19 +75,7 @@ class InstrumentBase extends _featureBase.FeatureBase {
|
|
|
66
75
|
*/
|
|
67
76
|
importAggregator() {
|
|
68
77
|
let argsObjFromInstrument = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
69
|
-
if (this.featAggregate) return;
|
|
70
|
-
if (!this.auto) {
|
|
71
|
-
// this feature requires an opt in...
|
|
72
|
-
// wait for API to be called
|
|
73
|
-
this.ee.on("".concat(this.featureName, "-opt-in"), () => {
|
|
74
|
-
// register the feature to drain only once the API has been called, it will drain when importAggregator finishes for all the features
|
|
75
|
-
// called by the api in that cycle
|
|
76
|
-
(0, _drain.registerDrain)(this.agentIdentifier, this.featureName);
|
|
77
|
-
this.auto = true;
|
|
78
|
-
this.importAggregator();
|
|
79
|
-
});
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
78
|
+
if (this.featAggregate || !this.auto) return;
|
|
82
79
|
let loadedSuccessfully;
|
|
83
80
|
this.onAggregateImported = new Promise(resolve => {
|
|
84
81
|
loadedSuccessfully = resolve;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.debugNR1 = debugNR1;
|
|
7
|
+
var _nreum = require("../../common/window/nreum");
|
|
8
|
+
const debugId = 1;
|
|
9
|
+
const newrelic = (0, _nreum.gosCDN)();
|
|
10
|
+
function debugNR1(agentIdentifier, location, event) {
|
|
11
|
+
let otherprops = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
12
|
+
let debugName = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 'SR';
|
|
13
|
+
const api = agentIdentifier ? newrelic.initializedAgents[agentIdentifier].api.addPageAction : newrelic.addPageAction;
|
|
14
|
+
let url;
|
|
15
|
+
try {
|
|
16
|
+
const locURL = new URL(window.location);
|
|
17
|
+
url = locURL.pathname;
|
|
18
|
+
} catch (err) {}
|
|
19
|
+
api(debugName, {
|
|
20
|
+
debugId,
|
|
21
|
+
url,
|
|
22
|
+
location,
|
|
23
|
+
event,
|
|
24
|
+
now: performance.now(),
|
|
25
|
+
...otherprops
|
|
26
|
+
});
|
|
27
|
+
}
|
|
@@ -30,6 +30,10 @@ var _runtime = require("../common/constants/runtime");
|
|
|
30
30
|
* sensitive to network load, this may result in smaller builds with slightly lower performance impact.
|
|
31
31
|
*/
|
|
32
32
|
class Agent extends _agentBase.AgentBase {
|
|
33
|
+
/**
|
|
34
|
+
* @param {Object} options Options to initialize agent with
|
|
35
|
+
* @param {string} [agentIdentifier] Optional identifier of agent
|
|
36
|
+
*/
|
|
33
37
|
constructor(options, agentIdentifier) {
|
|
34
38
|
super(agentIdentifier);
|
|
35
39
|
if (!_runtime.globalScope) {
|
|
@@ -11,6 +11,7 @@ var _handle = require("../../common/event-emitter/handle");
|
|
|
11
11
|
var _registerHandler = require("../../common/event-emitter/register-handler");
|
|
12
12
|
var _invoke = require("../../common/util/invoke");
|
|
13
13
|
var _constants = require("../../features/metrics/constants");
|
|
14
|
+
var _runtime = require("../../common/constants/runtime");
|
|
14
15
|
function setAPI(agentIdentifier) {
|
|
15
16
|
var instanceEE = _contextualEe.ee.get(agentIdentifier);
|
|
16
17
|
var api = {
|
|
@@ -30,13 +31,13 @@ function setAPI(agentIdentifier) {
|
|
|
30
31
|
// first parameter. These functions can be called asynchronously.
|
|
31
32
|
|
|
32
33
|
function finished(t, providedTime) {
|
|
33
|
-
var time = providedTime ? providedTime -
|
|
34
|
+
var time = providedTime ? providedTime - _runtime.originTime : t;
|
|
34
35
|
(0, _handle.handle)(_constants.CUSTOM_METRIC_CHANNEL, ['finished', {
|
|
35
36
|
time
|
|
36
37
|
}], undefined, _features.FEATURE_NAMES.metrics, instanceEE);
|
|
37
38
|
addToTrace(t, {
|
|
38
39
|
name: 'finished',
|
|
39
|
-
start: time +
|
|
40
|
+
start: time + _runtime.originTime,
|
|
40
41
|
origin: 'nr'
|
|
41
42
|
});
|
|
42
43
|
(0, _handle.handle)('api-addPageAction', [time, 'finished'], undefined, _features.FEATURE_NAMES.pageAction, instanceEE);
|
|
@@ -45,8 +46,8 @@ function setAPI(agentIdentifier) {
|
|
|
45
46
|
if (!(evt && typeof evt === 'object' && evt.name && evt.start)) return;
|
|
46
47
|
var report = {
|
|
47
48
|
n: evt.name,
|
|
48
|
-
s: evt.start -
|
|
49
|
-
e: (evt.end || evt.start) -
|
|
49
|
+
s: evt.start - _runtime.originTime,
|
|
50
|
+
e: (evt.end || evt.start) - _runtime.originTime,
|
|
50
51
|
o: evt.origin || '',
|
|
51
52
|
t: 'api'
|
|
52
53
|
};
|
|
@@ -7,12 +7,15 @@ export function getModeledObject(obj, model) {
|
|
|
7
7
|
const output = Object.create(Object.getPrototypeOf(model), Object.getOwnPropertyDescriptors(model));
|
|
8
8
|
const target = Object.keys(output).length === 0 ? obj : output;
|
|
9
9
|
for (let key in target) {
|
|
10
|
-
if (obj[key]
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
if (obj[key] === undefined) continue;
|
|
11
|
+
try {
|
|
12
|
+
if (obj[key] === null) {
|
|
13
|
+
output[key] = null;
|
|
14
|
+
continue;
|
|
15
15
|
}
|
|
16
|
+
if (Array.isArray(obj[key]) && Array.isArray(model[key])) output[key] = Array.from(new Set([...obj[key], ...model[key]]));else if (typeof obj[key] === 'object' && typeof model[key] === 'object') output[key] = getModeledObject(obj[key], model[key]);else output[key] = obj[key];
|
|
17
|
+
} catch (e) {
|
|
18
|
+
warn('An error occurred while setting a property of a Configurable', e);
|
|
16
19
|
}
|
|
17
20
|
}
|
|
18
21
|
return output;
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { getModeledObject } from './configurable';
|
|
2
2
|
import { getNREUMInitializedAgent } from '../../window/nreum';
|
|
3
|
-
import { globalScope } from '../../constants/runtime';
|
|
3
|
+
import { globalScope, originTime } from '../../constants/runtime';
|
|
4
4
|
import { BUILD_ENV, DIST_METHOD, VERSION } from "../../constants/env.npm";
|
|
5
|
-
const
|
|
5
|
+
const readonly = {
|
|
6
6
|
buildEnv: BUILD_ENV,
|
|
7
|
+
distMethod: DIST_METHOD,
|
|
8
|
+
version: VERSION,
|
|
9
|
+
originTime
|
|
10
|
+
};
|
|
11
|
+
const model = {
|
|
7
12
|
customTransaction: undefined,
|
|
8
13
|
disabled: false,
|
|
9
|
-
distMethod: DIST_METHOD,
|
|
10
14
|
isolatedBacklog: false,
|
|
11
15
|
loaderType: undefined,
|
|
12
16
|
maxBytes: 30000,
|
|
13
|
-
// The "timeOrigin" property is the new standard timestamp property shared across main frame and workers, but is not supported in some early Safari browsers (safari<15) + IE
|
|
14
|
-
// ingest expects an integer value, and timeOrigin can return a float.
|
|
15
|
-
offset: Math.floor(globalScope?.performance?.timeOrigin || globalScope?.performance?.timing?.navigationStart || Date.now()),
|
|
16
17
|
onerror: undefined,
|
|
17
18
|
origin: '' + globalScope.location,
|
|
18
19
|
ptid: undefined,
|
|
@@ -20,8 +21,6 @@ const model = {
|
|
|
20
21
|
/** Agent-specific metadata found in the RUM call response. ex. entityGuid */
|
|
21
22
|
appMetadata: {},
|
|
22
23
|
session: undefined,
|
|
23
|
-
xhrWrappable: typeof globalScope.XMLHttpRequest?.prototype?.addEventListener === 'function',
|
|
24
|
-
version: VERSION,
|
|
25
24
|
denyList: undefined,
|
|
26
25
|
harvestCount: 0,
|
|
27
26
|
timeKeeper: undefined
|
|
@@ -34,7 +33,10 @@ export function getRuntime(id) {
|
|
|
34
33
|
}
|
|
35
34
|
export function setRuntime(id, obj) {
|
|
36
35
|
if (!id) throw new Error('All runtime objects require an agent identifier!');
|
|
37
|
-
_cache[id] =
|
|
36
|
+
_cache[id] = {
|
|
37
|
+
...getModeledObject(obj, model),
|
|
38
|
+
...readonly
|
|
39
|
+
};
|
|
38
40
|
const agentInst = getNREUMInitializedAgent(id);
|
|
39
41
|
if (agentInst) agentInst.runtime = _cache[id];
|
|
40
42
|
}
|
|
@@ -38,4 +38,10 @@ export const ffVersion = (() => {
|
|
|
38
38
|
export const isIE = Boolean(isBrowserScope && window.document.documentMode); // deprecated property that only works in IE
|
|
39
39
|
|
|
40
40
|
export const supportsSendBeacon = !!globalScope.navigator?.sendBeacon;
|
|
41
|
-
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Represents the absolute timestamp in milliseconds that the page was loaded
|
|
44
|
+
* according to the browser's local clock.
|
|
45
|
+
* @type {number}
|
|
46
|
+
*/
|
|
47
|
+
export const originTime = Math.floor(Date.now() - performance.now());
|
|
@@ -129,7 +129,7 @@ export class Harvest extends SharedContext {
|
|
|
129
129
|
let url = "".concat(protocol, "://").concat(perceviedBeacon).concat(endpointURLPart, "/1/").concat(info.licenseKey);
|
|
130
130
|
if (customUrl) url = customUrl;
|
|
131
131
|
if (raw) url = "".concat(protocol, "://").concat(perceviedBeacon, "/").concat(endpoint);
|
|
132
|
-
const baseParams = !raw && includeBaseParams ? this.baseQueryString(qs) : '';
|
|
132
|
+
const baseParams = !raw && includeBaseParams ? this.baseQueryString(qs, endpoint) : '';
|
|
133
133
|
let payloadParams = encodeObj(qs, agentRuntime.maxBytes);
|
|
134
134
|
if (!submitMethod) {
|
|
135
135
|
submitMethod = submitData.getSubmitMethod({
|
|
@@ -199,17 +199,19 @@ export class Harvest extends SharedContext {
|
|
|
199
199
|
}
|
|
200
200
|
|
|
201
201
|
// The stuff that gets sent every time.
|
|
202
|
-
baseQueryString(qs) {
|
|
202
|
+
baseQueryString(qs, endpoint) {
|
|
203
203
|
const runtime = getRuntime(this.sharedContext.agentIdentifier);
|
|
204
204
|
const info = getInfo(this.sharedContext.agentIdentifier);
|
|
205
205
|
const location = cleanURL(getLocation());
|
|
206
206
|
const ref = this.obfuscator.shouldObfuscate() ? this.obfuscator.obfuscateString(location) : location;
|
|
207
|
-
|
|
207
|
+
const hr = runtime?.session?.state.sessionReplayMode === 1 && endpoint !== 'jserrors';
|
|
208
|
+
const qps = ['a=' + info.applicationID, encodeParam('sa', info.sa ? '' + info.sa : ''), encodeParam('v', VERSION), transactionNameParam(info), encodeParam('ct', runtime.customTransaction), '&rst=' + now(), '&ck=0',
|
|
208
209
|
// ck param DEPRECATED - still expected by backend
|
|
209
210
|
'&s=' + (runtime.session?.state.value || '0'),
|
|
210
211
|
// the 0 id encaps all untrackable and default traffic
|
|
211
|
-
encodeParam('ref', ref), encodeParam('ptid', runtime.ptid ? '' + runtime.ptid : '')
|
|
212
|
-
|
|
212
|
+
encodeParam('ref', ref), encodeParam('ptid', runtime.ptid ? '' + runtime.ptid : '')];
|
|
213
|
+
if (hr) qps.push(encodeParam('hr', '1', qs));
|
|
214
|
+
return qps.join('');
|
|
213
215
|
}
|
|
214
216
|
|
|
215
217
|
/**
|
|
@@ -3,6 +3,7 @@ export const DEFAULT_KEY = 'SESSION';
|
|
|
3
3
|
export const DEFAULT_EXPIRES_MS = 14400000;
|
|
4
4
|
export const DEFAULT_INACTIVE_MS = 1800000;
|
|
5
5
|
export const SESSION_EVENTS = {
|
|
6
|
+
STARTED: 'session-started',
|
|
6
7
|
PAUSE: 'session-pause',
|
|
7
8
|
RESET: 'session-reset',
|
|
8
9
|
RESUME: 'session-resume',
|
|
@@ -24,6 +24,8 @@ const model = {
|
|
|
24
24
|
sessionReplaySentFirstChunk: false,
|
|
25
25
|
sessionTraceMode: MODE.OFF,
|
|
26
26
|
traceHarvestStarted: false,
|
|
27
|
+
serverTimeDiff: null,
|
|
28
|
+
// set by TimeKeeper; "undefined" value will not be stringified and stored but "null" will
|
|
27
29
|
custom: {}
|
|
28
30
|
};
|
|
29
31
|
export class SessionEntity {
|
|
@@ -138,6 +140,7 @@ export class SessionEntity {
|
|
|
138
140
|
// we can use a modeled object here to help us know and manage what values are being used. -- see "model" above
|
|
139
141
|
if (this.isNew) this.write(getModeledObject(this.state, model), true);else this.sync(initialRead);
|
|
140
142
|
this.initialized = true;
|
|
143
|
+
this.ee.emit(SESSION_EVENTS.STARTED, [this.isNew]);
|
|
141
144
|
}
|
|
142
145
|
|
|
143
146
|
// This is the actual key appended to the storage API
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import { originTime } from '../constants/runtime';
|
|
2
|
+
import { ee as baseEE } from '../event-emitter/contextual-ee';
|
|
3
|
+
import { getRuntime } from '../config/config';
|
|
4
|
+
import { SESSION_EVENT_TYPES, SESSION_EVENTS } from '../session/constants';
|
|
5
|
+
|
|
1
6
|
/**
|
|
2
7
|
* Class used to adjust the timestamp of harvested data to New Relic server time. This
|
|
3
8
|
* is done by tracking the performance timings of the RUM call and applying a calculation
|
|
@@ -5,10 +10,10 @@
|
|
|
5
10
|
*/
|
|
6
11
|
export class TimeKeeper {
|
|
7
12
|
/**
|
|
8
|
-
*
|
|
9
|
-
* @type {
|
|
13
|
+
* Pointer to the current agent session if it exists.
|
|
14
|
+
* @type {import('../session/session-entity').SessionEntity}
|
|
10
15
|
*/
|
|
11
|
-
#
|
|
16
|
+
#session;
|
|
12
17
|
|
|
13
18
|
/**
|
|
14
19
|
* Represents the browser origin time corrected to NR server time.
|
|
@@ -29,15 +34,24 @@ export class TimeKeeper {
|
|
|
29
34
|
* @type {number}
|
|
30
35
|
*/
|
|
31
36
|
#ready = false;
|
|
32
|
-
constructor() {
|
|
33
|
-
this.#
|
|
37
|
+
constructor(agentIdentifier) {
|
|
38
|
+
this.#session = getRuntime(agentIdentifier)?.session;
|
|
39
|
+
if (this.#session) {
|
|
40
|
+
const ee = baseEE.get(agentIdentifier);
|
|
41
|
+
ee.on(SESSION_EVENTS.UPDATE, this.#processSessionUpdate.bind(this));
|
|
42
|
+
ee.on(SESSION_EVENTS.STARTED, () => {
|
|
43
|
+
if (this.#ready) {
|
|
44
|
+
this.#session.write({
|
|
45
|
+
serverTimeDiff: this.#localTimeDiff
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
this.#processSessionUpdate(null, this.#session.read());
|
|
50
|
+
}
|
|
34
51
|
}
|
|
35
52
|
get ready() {
|
|
36
53
|
return this.#ready;
|
|
37
54
|
}
|
|
38
|
-
get originTime() {
|
|
39
|
-
return this.#originTime;
|
|
40
|
-
}
|
|
41
55
|
get correctedOriginTime() {
|
|
42
56
|
return this.#correctedOriginTime;
|
|
43
57
|
}
|
|
@@ -49,6 +63,8 @@ export class TimeKeeper {
|
|
|
49
63
|
* @param endTime {number} The end time of the RUM request
|
|
50
64
|
*/
|
|
51
65
|
processRumRequest(rumRequest, startTime, endTime) {
|
|
66
|
+
if (this.#ready) return; // Server time calculated from session entity
|
|
67
|
+
|
|
52
68
|
const responseDateHeader = rumRequest.getResponseHeader('Date');
|
|
53
69
|
if (!responseDateHeader) {
|
|
54
70
|
throw new Error('Missing date header on rum response.');
|
|
@@ -58,10 +74,13 @@ export class TimeKeeper {
|
|
|
58
74
|
|
|
59
75
|
// Corrected page origin time
|
|
60
76
|
this.#correctedOriginTime = Math.floor(Date.parse(responseDateHeader) - serverOffset);
|
|
61
|
-
this.#localTimeDiff =
|
|
77
|
+
this.#localTimeDiff = originTime - this.#correctedOriginTime;
|
|
62
78
|
if (Number.isNaN(this.#correctedOriginTime)) {
|
|
63
79
|
throw new Error('Date header invalid format.');
|
|
64
80
|
}
|
|
81
|
+
if (this.#session) this.#session.write({
|
|
82
|
+
serverTimeDiff: this.#localTimeDiff
|
|
83
|
+
});
|
|
65
84
|
this.#ready = true;
|
|
66
85
|
}
|
|
67
86
|
|
|
@@ -83,4 +102,22 @@ export class TimeKeeper {
|
|
|
83
102
|
correctAbsoluteTimestamp(timestamp) {
|
|
84
103
|
return Math.floor(timestamp - this.#localTimeDiff);
|
|
85
104
|
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Processes a session entity update payload to extract the server time calculated.
|
|
108
|
+
* @param {import('../session/constants').SESSION_EVENT_TYPES | null} type
|
|
109
|
+
* @param {Object} data
|
|
110
|
+
*/
|
|
111
|
+
#processSessionUpdate(type, data) {
|
|
112
|
+
if (typeof data?.serverTimeDiff !== 'number') return;
|
|
113
|
+
if (!type && !this.#ready ||
|
|
114
|
+
// This captures the initial read from the session entity when the timekeeper first initializes
|
|
115
|
+
type === SESSION_EVENT_TYPES.CROSS_TAB // This captures any cross-tab write of the session entity
|
|
116
|
+
) {
|
|
117
|
+
// This captures the initial read from the session entity when the timekeeper first initializes
|
|
118
|
+
this.#localTimeDiff = data.serverTimeDiff;
|
|
119
|
+
this.#correctedOriginTime = originTime - this.#localTimeDiff;
|
|
120
|
+
this.#ready = true;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
86
123
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { globalScope, isBrowserScope, isiOS,
|
|
1
|
+
import { globalScope, isBrowserScope, isiOS, originTime } from '../constants/runtime';
|
|
2
2
|
import { VITAL_NAMES } from './constants';
|
|
3
3
|
import { VitalMetric } from './vital-metric';
|
|
4
4
|
import { onTTFB } from 'web-vitals/attribution';
|
|
@@ -21,7 +21,7 @@ if (isBrowserScope && typeof PerformanceNavigationTiming !== 'undefined' && !isi
|
|
|
21
21
|
if (!timeToFirstByte.isValid) {
|
|
22
22
|
const entry = {};
|
|
23
23
|
// convert real timestamps to relative timestamps to match web-vitals behavior
|
|
24
|
-
for (let key in globalScope?.performance?.timing || {}) entry[key] = Math.max(globalScope?.performance?.timing[key] -
|
|
24
|
+
for (let key in globalScope?.performance?.timing || {}) entry[key] = Math.max(globalScope?.performance?.timing[key] - originTime, 0);
|
|
25
25
|
|
|
26
26
|
// ttfb is equiv to document's responseStart property in timing API --> https://developer.mozilla.org/en-US/docs/Web/API/PerformanceTiming/responseStart
|
|
27
27
|
timeToFirstByte.update({
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { nullable, numeric, getAddStringContext, addCustomAttributes } from '../../../common/serialize/bel-serializer';
|
|
2
|
+
import { getInfo } from '../../../common/config/config';
|
|
3
|
+
export default class Chunk {
|
|
4
|
+
constructor(events, aggregateInstance) {
|
|
5
|
+
this.addString = getAddStringContext(aggregateInstance.agentIdentifier); // pass agentIdentifier here
|
|
6
|
+
this.events = events;
|
|
7
|
+
this.payload = 'bel.7;';
|
|
8
|
+
for (let i = 0; i < events.length; i++) {
|
|
9
|
+
const event = events[i];
|
|
10
|
+
const fields = [numeric(event.startTime), numeric(event.endTime - event.startTime), numeric(0),
|
|
11
|
+
// callbackEnd
|
|
12
|
+
numeric(0),
|
|
13
|
+
// no callbackDuration for non-SPA events
|
|
14
|
+
this.addString(event.method), numeric(event.status), this.addString(event.domain), this.addString(event.path), numeric(event.requestSize), numeric(event.responseSize), event.type === 'fetch' ? 1 : '', this.addString(0),
|
|
15
|
+
// nodeId
|
|
16
|
+
nullable(event.spanId, this.addString, true) +
|
|
17
|
+
// guid
|
|
18
|
+
nullable(event.traceId, this.addString, true) +
|
|
19
|
+
// traceId
|
|
20
|
+
nullable(event.spanTimestamp, numeric, false) // timestamp
|
|
21
|
+
];
|
|
22
|
+
let insert = '2,';
|
|
23
|
+
|
|
24
|
+
// Since configuration objects (like info) are created new each time they are set, we have to grab the current pointer to the attr object here.
|
|
25
|
+
const jsAttributes = getInfo(aggregateInstance.agentIdentifier).jsAttributes;
|
|
26
|
+
|
|
27
|
+
// add custom attributes
|
|
28
|
+
// gql decorators are added as custom attributes to alleviate need for new BEL schema
|
|
29
|
+
const attrParts = addCustomAttributes({
|
|
30
|
+
...(jsAttributes || {}),
|
|
31
|
+
...(event.gql || {})
|
|
32
|
+
}, this.addString);
|
|
33
|
+
fields.unshift(numeric(attrParts.length));
|
|
34
|
+
insert += fields.join(',');
|
|
35
|
+
if (attrParts && attrParts.length > 0) {
|
|
36
|
+
insert += ';' + attrParts.join(';');
|
|
37
|
+
}
|
|
38
|
+
if (i + 1 < events.length) insert += ';';
|
|
39
|
+
this.payload += insert;
|
|
40
|
+
}
|
|
41
|
+
this.tooBig = this.payload.length * 2 > aggregateInstance.MAX_PAYLOAD_SIZE;
|
|
42
|
+
}
|
|
43
|
+
}
|