@newrelic/browser-agent 1.285.0 → 1.287.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 +22 -0
- package/README.md +6 -0
- package/dist/cjs/common/config/init-types.js +96 -0
- package/dist/cjs/common/config/init.js +9 -79
- package/dist/cjs/common/config/runtime.js +7 -6
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/dom/selector-path.js +1 -1
- package/dist/cjs/common/harvest/harvester.js +3 -3
- package/dist/cjs/common/util/feature-flags.js +6 -6
- package/dist/cjs/common/util/target.js +34 -0
- package/dist/cjs/features/ajax/aggregate/index.js +2 -1
- package/dist/cjs/features/generic_events/aggregate/index.js +10 -6
- package/dist/cjs/features/jserrors/aggregate/index.js +44 -22
- package/dist/cjs/features/logging/aggregate/index.js +17 -11
- package/dist/cjs/features/logging/shared/utils.js +3 -2
- package/dist/cjs/features/metrics/aggregate/index.js +6 -4
- package/dist/cjs/features/page_view_event/aggregate/index.js +60 -11
- package/dist/cjs/features/page_view_event/instrument/index.js +4 -0
- package/dist/cjs/features/session_replay/aggregate/index.js +8 -6
- package/dist/cjs/features/session_replay/instrument/index.js +1 -1
- package/dist/cjs/features/session_replay/shared/recorder-events.js +4 -2
- package/dist/cjs/features/session_replay/shared/recorder.js +17 -11
- package/dist/cjs/features/session_trace/aggregate/trace/storage.js +4 -3
- package/dist/cjs/features/soft_navigations/aggregate/index.js +12 -2
- package/dist/cjs/features/spa/aggregate/index.js +3 -3
- package/dist/cjs/features/spa/aggregate/interaction.js +6 -9
- package/dist/cjs/features/utils/aggregate-base.js +51 -24
- package/dist/cjs/features/utils/entity-manager.js +47 -0
- package/dist/cjs/features/utils/event-store-manager.js +79 -54
- package/dist/cjs/features/utils/nr1-debugger.js +1 -1
- package/dist/cjs/interfaces/registered-entity.js +114 -0
- package/dist/cjs/loaders/agent-base.js +1 -1
- package/dist/cjs/loaders/agent.js +3 -1
- package/dist/cjs/loaders/api/api-methods.js +1 -1
- package/dist/cjs/loaders/api/api.js +97 -69
- package/dist/cjs/loaders/api/apiAsync.js +19 -22
- package/dist/cjs/loaders/api/register-api-types.js +35 -0
- package/dist/cjs/loaders/api/register-api.js +165 -0
- package/dist/cjs/loaders/configure/configure.js +12 -15
- package/dist/cjs/loaders/micro-agent-base.js +17 -1
- package/dist/cjs/loaders/micro-agent.js +4 -1
- package/dist/esm/common/config/init-types.js +92 -0
- package/dist/esm/common/config/init.js +9 -79
- package/dist/esm/common/config/runtime.js +7 -6
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/dom/selector-path.js +1 -1
- package/dist/esm/common/harvest/harvester.js +3 -3
- package/dist/esm/common/util/feature-flags.js +6 -6
- package/dist/esm/common/util/target.js +27 -0
- package/dist/esm/features/ajax/aggregate/index.js +2 -1
- package/dist/esm/features/generic_events/aggregate/index.js +10 -6
- package/dist/esm/features/jserrors/aggregate/index.js +44 -22
- package/dist/esm/features/logging/aggregate/index.js +17 -11
- package/dist/esm/features/logging/shared/utils.js +3 -2
- package/dist/esm/features/metrics/aggregate/index.js +6 -4
- package/dist/esm/features/page_view_event/aggregate/index.js +60 -11
- package/dist/esm/features/page_view_event/instrument/index.js +4 -0
- package/dist/esm/features/session_replay/aggregate/index.js +8 -6
- package/dist/esm/features/session_replay/instrument/index.js +1 -1
- package/dist/esm/features/session_replay/shared/recorder-events.js +4 -2
- package/dist/esm/features/session_replay/shared/recorder.js +17 -11
- package/dist/esm/features/session_trace/aggregate/trace/storage.js +4 -3
- package/dist/esm/features/soft_navigations/aggregate/index.js +12 -2
- package/dist/esm/features/spa/aggregate/index.js +3 -3
- package/dist/esm/features/spa/aggregate/interaction.js +6 -9
- package/dist/esm/features/utils/aggregate-base.js +51 -24
- package/dist/esm/features/utils/entity-manager.js +40 -0
- package/dist/esm/features/utils/event-store-manager.js +79 -54
- package/dist/esm/features/utils/nr1-debugger.js +1 -1
- package/dist/esm/interfaces/registered-entity.js +107 -0
- package/dist/esm/loaders/agent-base.js +1 -1
- package/dist/esm/loaders/agent.js +3 -1
- package/dist/esm/loaders/api/api-methods.js +1 -1
- package/dist/esm/loaders/api/api.js +95 -67
- package/dist/esm/loaders/api/apiAsync.js +14 -17
- package/dist/esm/loaders/api/register-api-types.js +33 -0
- package/dist/esm/loaders/api/register-api.js +159 -0
- package/dist/esm/loaders/configure/configure.js +13 -16
- package/dist/esm/loaders/micro-agent-base.js +17 -1
- package/dist/esm/loaders/micro-agent.js +4 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/common/config/init-types.d.ts +275 -0
- package/dist/types/common/config/init-types.d.ts.map +1 -0
- package/dist/types/common/config/init.d.ts +1 -262
- package/dist/types/common/config/init.d.ts.map +1 -1
- package/dist/types/common/config/runtime.d.ts.map +1 -1
- package/dist/types/common/dom/selector-path.d.ts.map +1 -1
- package/dist/types/common/util/feature-flags.d.ts +1 -1
- package/dist/types/common/util/feature-flags.d.ts.map +1 -1
- package/dist/types/common/util/target.d.ts +18 -0
- package/dist/types/common/util/target.d.ts.map +1 -0
- package/dist/types/features/ajax/aggregate/index.d.ts +1 -1
- package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/generic_events/aggregate/index.d.ts +2 -1
- package/dist/types/features/generic_events/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts +9 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/logging/aggregate/index.d.ts +3 -3
- package/dist/types/features/logging/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/logging/shared/utils.d.ts +2 -1
- package/dist/types/features/logging/shared/utils.d.ts.map +1 -1
- package/dist/types/features/metrics/aggregate/index.d.ts +1 -0
- package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_event/aggregate/index.d.ts +10 -2
- package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_event/instrument/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts +2 -11
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/recorder-events.d.ts +1 -0
- package/dist/types/features/session_replay/shared/recorder-events.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/recorder.d.ts +4 -4
- package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
- package/dist/types/features/soft_navigations/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/spa/aggregate/interaction.d.ts +3 -4
- package/dist/types/features/spa/aggregate/interaction.d.ts.map +1 -1
- package/dist/types/features/utils/aggregate-base.d.ts +22 -5
- package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
- package/dist/types/features/utils/entity-manager.d.ts +15 -0
- package/dist/types/features/utils/entity-manager.d.ts.map +1 -0
- package/dist/types/features/utils/event-store-manager.d.ts +48 -24
- package/dist/types/features/utils/event-store-manager.d.ts.map +1 -1
- package/dist/types/interfaces/registered-entity.d.ts +72 -0
- package/dist/types/interfaces/registered-entity.d.ts.map +1 -0
- package/dist/types/loaders/agent.d.ts +2 -1
- package/dist/types/loaders/agent.d.ts.map +1 -1
- package/dist/types/loaders/api/api.d.ts +1 -20
- package/dist/types/loaders/api/api.d.ts.map +1 -1
- package/dist/types/loaders/api/apiAsync.d.ts +1 -1
- package/dist/types/loaders/api/apiAsync.d.ts.map +1 -1
- package/dist/types/loaders/api/register-api-types.d.ts +56 -0
- package/dist/types/loaders/api/register-api-types.d.ts.map +1 -0
- package/dist/types/loaders/api/register-api.d.ts +14 -0
- package/dist/types/loaders/api/register-api.d.ts.map +1 -0
- package/dist/types/loaders/configure/configure.d.ts +1 -0
- package/dist/types/loaders/configure/configure.d.ts.map +1 -1
- package/dist/types/loaders/micro-agent-base.d.ts +17 -0
- package/dist/types/loaders/micro-agent-base.d.ts.map +1 -1
- package/dist/types/loaders/micro-agent.d.ts +2 -0
- package/dist/types/loaders/micro-agent.d.ts.map +1 -1
- package/package.json +10 -1
- package/src/common/config/init-types.js +92 -0
- package/src/common/config/init.js +9 -79
- package/src/common/config/runtime.js +7 -6
- package/src/common/dom/selector-path.js +1 -3
- package/src/common/harvest/harvester.js +3 -3
- package/src/common/util/feature-flags.js +6 -6
- package/src/common/util/target.js +27 -0
- package/src/features/ajax/aggregate/index.js +2 -1
- package/src/features/generic_events/aggregate/index.js +8 -6
- package/src/features/jserrors/aggregate/index.js +42 -20
- package/src/features/logging/aggregate/index.js +14 -10
- package/src/features/logging/shared/utils.js +3 -2
- package/src/features/metrics/aggregate/index.js +7 -5
- package/src/features/page_view_event/aggregate/index.js +50 -8
- package/src/features/page_view_event/instrument/index.js +4 -0
- package/src/features/session_replay/aggregate/index.js +6 -3
- package/src/features/session_replay/instrument/index.js +1 -1
- package/src/features/session_replay/shared/recorder-events.js +5 -2
- package/src/features/session_replay/shared/recorder.js +17 -11
- package/src/features/session_trace/aggregate/trace/storage.js +3 -3
- package/src/features/soft_navigations/aggregate/index.js +11 -2
- package/src/features/spa/aggregate/index.js +3 -3
- package/src/features/spa/aggregate/interaction.js +6 -9
- package/src/features/utils/aggregate-base.js +56 -24
- package/src/features/utils/entity-manager.js +45 -0
- package/src/features/utils/event-store-manager.js +72 -49
- package/src/features/utils/nr1-debugger.js +1 -1
- package/src/interfaces/registered-entity.js +107 -0
- package/src/loaders/agent-base.js +2 -2
- package/src/loaders/agent.js +4 -1
- package/src/loaders/api/api-methods.js +1 -1
- package/src/loaders/api/api.js +94 -62
- package/src/loaders/api/apiAsync.js +14 -18
- package/src/loaders/api/register-api-types.js +33 -0
- package/src/loaders/api/register-api.js +152 -0
- package/src/loaders/configure/configure.js +12 -12
- package/src/loaders/micro-agent-base.js +18 -2
- package/src/loaders/micro-agent.js +5 -1
|
@@ -12,16 +12,42 @@ import { Obfuscator } from '../../common/util/obfuscate';
|
|
|
12
12
|
import { FEATURE_NAMES } from '../../loaders/features/features';
|
|
13
13
|
import { EventStoreManager } from './event-store-manager';
|
|
14
14
|
import { Harvester } from '../../common/harvest/harvester';
|
|
15
|
+
import { warn } from '../../common/util/console';
|
|
16
|
+
import { EntityManager } from './entity-manager';
|
|
17
|
+
import { EventBuffer } from './event-buffer';
|
|
15
18
|
import { handle } from '../../common/event-emitter/handle';
|
|
16
19
|
import { SUPPORTABILITY_METRIC_CHANNEL } from '../metrics/constants';
|
|
20
|
+
import { EventAggregator } from '../../common/aggregate/event-aggregator';
|
|
17
21
|
export class AggregateBase extends FeatureBase {
|
|
22
|
+
/**
|
|
23
|
+
* Create an AggregateBase instance.
|
|
24
|
+
* @param {Object} agentRef The reference to the agent instance.
|
|
25
|
+
* @param {string} featureName The name of the feature creating the instance.
|
|
26
|
+
*/
|
|
18
27
|
constructor(agentRef, featureName) {
|
|
19
28
|
super(agentRef.agentIdentifier, featureName);
|
|
20
29
|
this.agentRef = agentRef;
|
|
21
30
|
this.checkConfiguration(agentRef);
|
|
22
31
|
this.doOnceForAllAggregate(agentRef);
|
|
32
|
+
this.harvestOpts = {}; // features aggregate classes can define custom opts for when their harvest is called
|
|
33
|
+
|
|
34
|
+
const agentEntityGuid = this.agentRef?.runtime?.appMetadata?.agents?.[0]?.entityGuid;
|
|
35
|
+
if (agentEntityGuid) {
|
|
36
|
+
this.#setupEventStore(agentEntityGuid); // if there's no entity guid, wont dont anything, and will wait for rum flags
|
|
37
|
+
} else {
|
|
38
|
+
this.ee.on('entity-added', entity => {
|
|
39
|
+
this.#setupEventStore(entity.entityGuid);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
23
43
|
|
|
24
|
-
|
|
44
|
+
/**
|
|
45
|
+
* sets up the event store for the feature. It must wait for the entity guid to be available before setting up the event store. This is called once the rum response is received with an entityGuid.
|
|
46
|
+
* @param {string} entityGuid
|
|
47
|
+
* @returns {void}
|
|
48
|
+
*/
|
|
49
|
+
#setupEventStore(entityGuid) {
|
|
50
|
+
if (this.events || !entityGuid) return;
|
|
25
51
|
switch (this.featureName) {
|
|
26
52
|
// SessionTrace + Replay have their own storage mechanisms.
|
|
27
53
|
case FEATURE_NAMES.sessionTrace:
|
|
@@ -30,16 +56,15 @@ export class AggregateBase extends FeatureBase {
|
|
|
30
56
|
// Jserror and Metric features uses a singleton EventAggregator instead of a regular EventBuffer.
|
|
31
57
|
case FEATURE_NAMES.jserrors:
|
|
32
58
|
case FEATURE_NAMES.metrics:
|
|
33
|
-
this.events = agentRef.sharedAggregator;
|
|
59
|
+
this.events = this.agentRef.sharedAggregator ??= new EventStoreManager(this.agentRef, EventAggregator, entityGuid, 'shared_aggregator');
|
|
34
60
|
break;
|
|
35
61
|
/** All other features get EventBuffer in the ESM by default. Note: PVE is included here, but event buffer will always be empty so future harvests will still not happen by interval or EOL.
|
|
36
62
|
This was necessary to prevent race cond. issues where the event buffer was checked before the feature could "block" itself.
|
|
37
63
|
Its easier to just keep an empty event buffer in place. */
|
|
38
64
|
default:
|
|
39
|
-
this.events = new EventStoreManager(agentRef
|
|
65
|
+
this.events = new EventStoreManager(this.agentRef, EventBuffer, entityGuid, this.featureName);
|
|
40
66
|
break;
|
|
41
67
|
}
|
|
42
|
-
this.harvestOpts = {}; // features aggregate classes can define custom opts for when their harvest is called
|
|
43
68
|
}
|
|
44
69
|
|
|
45
70
|
/**
|
|
@@ -69,6 +94,10 @@ export class AggregateBase extends FeatureBase {
|
|
|
69
94
|
this.deregisterDrain();
|
|
70
95
|
});
|
|
71
96
|
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Stages the feature to be drained
|
|
100
|
+
*/
|
|
72
101
|
drain() {
|
|
73
102
|
drain(this.agentIdentifier, this.featureName);
|
|
74
103
|
this.drained = true;
|
|
@@ -80,28 +109,29 @@ export class AggregateBase extends FeatureBase {
|
|
|
80
109
|
/**
|
|
81
110
|
* Return harvest payload. A "serializer" function can be defined on a derived class to format the payload.
|
|
82
111
|
* @param {Boolean} shouldRetryOnFail - harvester flag to backup payload for retry later if harvest request fails; this should be moved to harvester logic
|
|
83
|
-
* @param {object|undefined} opts
|
|
112
|
+
* @param {object|undefined} opts - opts passed from the harvester to help form the payload
|
|
113
|
+
* @param {string} opts.targetEntityGuid - the entity guid of the target app
|
|
84
114
|
* @returns {Array} Final payload tagged with their targeting browser app. The value of `payload` can be undefined if there are no pending events for an app. This should be a minimum length of 1.
|
|
85
115
|
*/
|
|
86
116
|
makeHarvestPayload(shouldRetryOnFail = false, opts = {}) {
|
|
87
|
-
if (this.events.isEmpty(this.harvestOpts, opts.
|
|
117
|
+
if (!this.events || this.events.isEmpty(this.harvestOpts, opts.targetEntityGuid)) return;
|
|
88
118
|
// Other conditions and things to do when preparing harvest that is required.
|
|
89
119
|
if (this.preHarvestChecks && !this.preHarvestChecks(opts)) return;
|
|
90
|
-
if (shouldRetryOnFail) this.events.save(this.harvestOpts, opts.
|
|
91
|
-
const returnedDataArr = this.events.get(this.harvestOpts, opts.
|
|
92
|
-
if (!returnedDataArr.length)
|
|
93
|
-
this.events.clear(this.harvestOpts, opts.
|
|
120
|
+
if (shouldRetryOnFail) this.events.save(this.harvestOpts, opts.targetEntityGuid);
|
|
121
|
+
const returnedDataArr = this.events.get(this.harvestOpts, opts.targetEntityGuid);
|
|
122
|
+
if (!returnedDataArr.length) return warn(52);
|
|
123
|
+
this.events.clear(this.harvestOpts, opts.targetEntityGuid);
|
|
94
124
|
return returnedDataArr.map(({
|
|
95
125
|
targetApp,
|
|
96
126
|
data
|
|
97
127
|
}) => {
|
|
98
128
|
// A serializer or formatter assists in creating the payload `body` from stored events on harvest when defined by derived feature class.
|
|
99
|
-
const body = this.serializer ? this.serializer(data) : data;
|
|
129
|
+
const body = this.serializer ? this.serializer(data, targetApp?.entityGuid) : data;
|
|
100
130
|
const payload = {
|
|
101
131
|
body
|
|
102
132
|
};
|
|
103
133
|
// Constructs the payload `qs` for relevant features on harvest.
|
|
104
|
-
if (this.queryStringsBuilder) payload.qs = this.queryStringsBuilder(data);
|
|
134
|
+
if (this.queryStringsBuilder) payload.qs = this.queryStringsBuilder(data, targetApp?.entityGuid);
|
|
105
135
|
return {
|
|
106
136
|
targetApp,
|
|
107
137
|
payload
|
|
@@ -112,11 +142,15 @@ export class AggregateBase extends FeatureBase {
|
|
|
112
142
|
/**
|
|
113
143
|
* Cleanup task after a harvest.
|
|
114
144
|
* @param {object} result - the cbResult object from the harvester's send method
|
|
145
|
+
* @param {object=} result.targetApp - the target app object that was used to point the harvest to the correct app
|
|
146
|
+
* @param {string=} result.targetApp.entityGuid - the entity guid of the target app
|
|
147
|
+
* @param {boolean=} result.sent - whether the harvest was sent successfully
|
|
148
|
+
* @param {boolean=} result.retry - whether the harvest should be retried
|
|
115
149
|
*/
|
|
116
150
|
postHarvestCleanup(result = {}) {
|
|
117
151
|
const harvestFailed = result.sent && result.retry;
|
|
118
|
-
if (harvestFailed) this.events.reloadSave(this.harvestOpts, result.targetApp);
|
|
119
|
-
this.events.clearSave(this.harvestOpts, result.targetApp);
|
|
152
|
+
if (harvestFailed) this.events.reloadSave(this.harvestOpts, result.targetApp?.entityGuid);
|
|
153
|
+
this.events.clearSave(this.harvestOpts, result.targetApp?.entityGuid);
|
|
120
154
|
}
|
|
121
155
|
|
|
122
156
|
/**
|
|
@@ -138,16 +172,14 @@ export class AggregateBase extends FeatureBase {
|
|
|
138
172
|
} catch (err) {
|
|
139
173
|
// do nothing
|
|
140
174
|
}
|
|
141
|
-
configure({
|
|
142
|
-
agentIdentifier: this.agentIdentifier
|
|
143
|
-
}, {
|
|
175
|
+
configure(existingAgent, {
|
|
144
176
|
...cdn,
|
|
145
177
|
info: {
|
|
146
178
|
...cdn.info,
|
|
147
179
|
jsAttributes
|
|
148
180
|
},
|
|
149
181
|
runtime: existingAgent.runtime
|
|
150
|
-
});
|
|
182
|
+
}, existingAgent.runtime.loaderType);
|
|
151
183
|
}
|
|
152
184
|
}
|
|
153
185
|
|
|
@@ -158,12 +190,7 @@ export class AggregateBase extends FeatureBase {
|
|
|
158
190
|
doOnceForAllAggregate(agentRef) {
|
|
159
191
|
if (!agentRef.runtime.obfuscator) agentRef.runtime.obfuscator = new Obfuscator(agentRef);
|
|
160
192
|
this.obfuscator = agentRef.runtime.obfuscator;
|
|
161
|
-
if (!agentRef.
|
|
162
|
-
licenseKey: agentRef.info.licenseKey,
|
|
163
|
-
appId: agentRef.info.applicationID
|
|
164
|
-
};
|
|
165
|
-
// Create a single Aggregator for this agent if DNE yet; to be used by jserror endpoint features.
|
|
166
|
-
if (!agentRef.sharedAggregator) agentRef.sharedAggregator = new EventStoreManager(agentRef.mainAppKey, 2, agentRef.agentIdentifier, 'shared_aggregator');
|
|
193
|
+
if (!agentRef.runtime.entityManager) agentRef.runtime.entityManager = new EntityManager(this.agentRef);
|
|
167
194
|
if (!agentRef.runtime.harvester) agentRef.runtime.harvester = new Harvester(agentRef);
|
|
168
195
|
}
|
|
169
196
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export class EntityManager {
|
|
7
|
+
#entities = new Map();
|
|
8
|
+
#entityGuidLookup = {};
|
|
9
|
+
#defaultEntity = null;
|
|
10
|
+
constructor(agentRef) {
|
|
11
|
+
this.agentRef = agentRef;
|
|
12
|
+
this.#defaultEntity = {
|
|
13
|
+
licenseKey: agentRef.info.licenseKey,
|
|
14
|
+
applicationID: agentRef.info.applicationID
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
get(entityGuid) {
|
|
18
|
+
if (!entityGuid) return this.#defaultEntity;
|
|
19
|
+
return this.#entities.get(entityGuid);
|
|
20
|
+
}
|
|
21
|
+
getEntityGuidFor(licenseKey, applicationID) {
|
|
22
|
+
if (!this.#entityGuidLookup[licenseKey] || !this.#entityGuidLookup[applicationID]) return;
|
|
23
|
+
return this.#entityGuidLookup[licenseKey].filter(x => this.#entityGuidLookup[applicationID].includes(x))[0];
|
|
24
|
+
}
|
|
25
|
+
set(entityGuid, entity) {
|
|
26
|
+
if (this.#entities.has(entityGuid)) return;
|
|
27
|
+
this.#entities.set(entityGuid, entity);
|
|
28
|
+
this.#entityGuidLookup[entity.licenseKey] ??= [];
|
|
29
|
+
this.#entityGuidLookup[entity.licenseKey].push(entityGuid);
|
|
30
|
+
this.#entityGuidLookup[entity.applicationID] ??= [];
|
|
31
|
+
this.#entityGuidLookup[entity.applicationID].push(entityGuid);
|
|
32
|
+
this.agentRef.ee.emit('entity-added', [entity]);
|
|
33
|
+
}
|
|
34
|
+
clear() {
|
|
35
|
+
this.#entities.clear();
|
|
36
|
+
}
|
|
37
|
+
setDefaultEntity(entity) {
|
|
38
|
+
this.#defaultEntity = entity;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
|
-
import { EventAggregator } from '../../common/aggregate/event-aggregator';
|
|
6
5
|
import { dispatchGlobalEvent } from '../../common/dispatch/global-event';
|
|
7
6
|
import { activatedFeatures } from '../../common/util/feature-flags';
|
|
8
|
-
import { EventBuffer } from './event-buffer';
|
|
9
7
|
|
|
10
8
|
/**
|
|
11
9
|
* This layer allows multiple browser entity apps, or "target", to each have their own segregated storage instance.
|
|
@@ -13,31 +11,39 @@ import { EventBuffer } from './event-buffer';
|
|
|
13
11
|
*/
|
|
14
12
|
export class EventStoreManager {
|
|
15
13
|
/**
|
|
16
|
-
* @param {object}
|
|
17
|
-
* @param {
|
|
18
|
-
* @param {string} agentIdentifier - agent identifier used in inspection events
|
|
19
|
-
* @param {string} featureName - feature name used in inspection events for non-shared aggregators
|
|
14
|
+
* @param {object} agentRef - reference to base agent class
|
|
15
|
+
* @param {EventBuffer|EventAggregator} storageClass - the type of storage to use in this manager; 'EventBuffer' (1), 'EventAggregator' (2)
|
|
20
16
|
*/
|
|
21
|
-
constructor(
|
|
22
|
-
this.
|
|
23
|
-
this.
|
|
17
|
+
constructor(agentRef, storageClass, defaultEntityGuid, featureName) {
|
|
18
|
+
this.agentRef = agentRef;
|
|
19
|
+
this.entityManager = agentRef.runtime.entityManager;
|
|
20
|
+
this.StorageClass = storageClass;
|
|
24
21
|
this.appStorageMap = new Map();
|
|
25
|
-
this.
|
|
26
|
-
this.agentIdentifier = agentIdentifier;
|
|
22
|
+
this.defaultEntity = this.#getEventStore(defaultEntityGuid);
|
|
27
23
|
this.featureName = featureName;
|
|
28
24
|
}
|
|
29
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Always returns a storage instance. Creates one if one does not exist. If a lookup is not provided, uses the DEFAULT namespace
|
|
28
|
+
* @param {string=} targetEntityGuid the lookup
|
|
29
|
+
* @returns {*} ALWAYS returns a storage instance
|
|
30
|
+
*/
|
|
31
|
+
#getEventStore(targetEntityGuid) {
|
|
32
|
+
if (!targetEntityGuid) return this.defaultEntity;
|
|
33
|
+
if (!this.appStorageMap.has(targetEntityGuid)) this.appStorageMap.set(targetEntityGuid, new this.StorageClass());
|
|
34
|
+
return this.appStorageMap.get(targetEntityGuid);
|
|
35
|
+
}
|
|
36
|
+
|
|
30
37
|
// This class must contain an union of all methods from all supported storage classes and conceptualize away the target app argument.
|
|
31
38
|
|
|
32
39
|
/**
|
|
40
|
+
* Calls the isEmpty method on the underlying storage class. If target is provided, runs just for the target, otherwise runs for all apps.
|
|
33
41
|
* @param {object} optsIfPresent - exists if called during harvest interval, @see AggregateBase.makeHarvestPayload
|
|
34
42
|
* @param {object} target - specific app's storage to check; if not provided, this method takes into account all apps recorded by this manager
|
|
35
43
|
* @returns {boolean} True if the target's storage is empty, or target does not exist in map (defaults to all storages)
|
|
36
44
|
*/
|
|
37
|
-
isEmpty(optsIfPresent,
|
|
38
|
-
if (
|
|
39
|
-
if (!this.appStorageMap.has(target)) return true;else return this.appStorageMap.get(target).isEmpty(optsIfPresent);
|
|
40
|
-
}
|
|
45
|
+
isEmpty(optsIfPresent, targetEntityGuid) {
|
|
46
|
+
if (targetEntityGuid) return this.#getEventStore(targetEntityGuid).isEmpty(optsIfPresent);
|
|
41
47
|
for (const eventStore of this.appStorageMap.values()) {
|
|
42
48
|
if (!eventStore.isEmpty(optsIfPresent)) return false;
|
|
43
49
|
}
|
|
@@ -45,77 +51,96 @@ export class EventStoreManager {
|
|
|
45
51
|
}
|
|
46
52
|
|
|
47
53
|
/**
|
|
54
|
+
* Calls the add method on the underlying storage class.
|
|
48
55
|
* @param {string} event - the event element to store
|
|
49
|
-
* @param {object}
|
|
56
|
+
* @param {object} targetEntityGuid - the entity guid lookup to store event under; if not provided, this method adds to the default
|
|
50
57
|
* @returns {boolean} True if the event was successfully added
|
|
51
58
|
*/
|
|
52
|
-
add(event,
|
|
59
|
+
add(event, targetEntityGuid) {
|
|
53
60
|
dispatchGlobalEvent({
|
|
54
|
-
agentIdentifier: this.agentIdentifier,
|
|
55
|
-
|
|
61
|
+
agentIdentifier: this.agentRef.agentIdentifier,
|
|
62
|
+
drained: !!activatedFeatures?.[this.agentRef.agentIdentifier],
|
|
56
63
|
type: 'data',
|
|
57
64
|
name: 'buffer',
|
|
58
65
|
feature: this.featureName,
|
|
59
66
|
data: event
|
|
60
67
|
});
|
|
61
|
-
|
|
62
|
-
return this.appStorageMap.get(target || this.mainApp).add(event);
|
|
68
|
+
return this.#getEventStore(targetEntityGuid).add(event);
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
/** This is only used by the Metrics feature which has no need to add metric under a different app atm. */
|
|
66
72
|
addMetric(type, name, params, value) {
|
|
67
|
-
return this
|
|
73
|
+
return this.#getEventStore().addMetric(type, name, params, value);
|
|
68
74
|
}
|
|
69
75
|
|
|
70
76
|
/**
|
|
71
|
-
*
|
|
72
|
-
* @param {object}
|
|
77
|
+
* Calls the get method on the underlying storage class. If target is provided, runs just for the target, otherwise runs for all apps.
|
|
78
|
+
* @param {object=} opts - exists if called during harvest interval, @see AggregateBase.makeHarvestPayload
|
|
79
|
+
* @param {object=} target - specific app to fetch; if not provided, this method fetches from all apps
|
|
73
80
|
* @returns {Array} Objects of `data` labeled with their respective `target` app to be sent to
|
|
74
81
|
*/
|
|
75
|
-
get(
|
|
76
|
-
if (
|
|
77
|
-
targetApp:
|
|
78
|
-
data: this
|
|
82
|
+
get(opts, targetEntityGuid) {
|
|
83
|
+
if (targetEntityGuid) return [{
|
|
84
|
+
targetApp: this.entityManager.get(targetEntityGuid),
|
|
85
|
+
data: this.#getEventStore(targetEntityGuid).get(opts)
|
|
79
86
|
}];
|
|
80
87
|
const allPayloads = [];
|
|
81
|
-
this.appStorageMap.forEach((eventStore,
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
88
|
+
this.appStorageMap.forEach((eventStore, targetEntityGuid) => {
|
|
89
|
+
const targetApp = this.entityManager.get(targetEntityGuid);
|
|
90
|
+
if (targetApp) allPayloads.push({
|
|
91
|
+
targetApp,
|
|
92
|
+
data: eventStore.get(opts)
|
|
85
93
|
});
|
|
86
94
|
});
|
|
87
95
|
return allPayloads;
|
|
88
96
|
}
|
|
89
|
-
|
|
90
|
-
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Calls the byteSize method on the underlying storage class
|
|
100
|
+
* @param {*} targetEntityGuid
|
|
101
|
+
* @returns
|
|
102
|
+
*/
|
|
103
|
+
byteSize(targetEntityGuid) {
|
|
104
|
+
return this.#getEventStore(targetEntityGuid).byteSize();
|
|
91
105
|
}
|
|
92
|
-
|
|
93
|
-
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Calls the wouldExceedMaxSize method on the underlying storage class
|
|
109
|
+
* @param {*} incomingSize
|
|
110
|
+
* @param {*} targetEntityGuid
|
|
111
|
+
* @returns
|
|
112
|
+
*/
|
|
113
|
+
wouldExceedMaxSize(incomingSize, targetEntityGuid) {
|
|
114
|
+
return this.#getEventStore(targetEntityGuid).wouldExceedMaxSize(incomingSize);
|
|
94
115
|
}
|
|
95
|
-
|
|
96
|
-
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Calls the save method on the underlying storage class. If target is provided, runs just for the target, otherwise runs for all apps.
|
|
119
|
+
* @param {*} optsIfPresent
|
|
120
|
+
* @param {*} targetEntityGuid
|
|
121
|
+
* @returns
|
|
122
|
+
*/
|
|
123
|
+
save(optsIfPresent, targetEntityGuid) {
|
|
124
|
+
if (targetEntityGuid) return this.#getEventStore(targetEntityGuid).save(optsIfPresent);
|
|
97
125
|
this.appStorageMap.forEach(eventStore => eventStore.save(optsIfPresent));
|
|
98
126
|
}
|
|
99
|
-
|
|
100
|
-
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Calls the clear method on the underlying storage class. If target is provided, runs just for the target, otherwise runs for all apps.
|
|
130
|
+
* @param {*} optsIfPresent
|
|
131
|
+
* @param {*} targetEntityGuid
|
|
132
|
+
* @returns
|
|
133
|
+
*/
|
|
134
|
+
clear(optsIfPresent, targetEntityGuid) {
|
|
135
|
+
if (targetEntityGuid) return this.#getEventStore(targetEntityGuid).clear(optsIfPresent);
|
|
101
136
|
this.appStorageMap.forEach(eventStore => eventStore.clear(optsIfPresent));
|
|
102
137
|
}
|
|
103
138
|
|
|
104
139
|
// Unlike the methods above, the following will have a target as they are called by AggregateBase.postHarvestCleanup callback on harvest finish after getting & sending the data.
|
|
105
|
-
reloadSave(optsIfPresent,
|
|
106
|
-
|
|
107
|
-
// -- remove this block once the old harvest.js & harvest-schedule.js are deleted!
|
|
108
|
-
this.appStorageMap.forEach(eventStore => eventStore.reloadSave(optsIfPresent));
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
return this.appStorageMap.get(target)?.reloadSave(optsIfPresent);
|
|
140
|
+
reloadSave(optsIfPresent, targetEntityGuid) {
|
|
141
|
+
return this.#getEventStore(targetEntityGuid).reloadSave(optsIfPresent);
|
|
112
142
|
}
|
|
113
|
-
clearSave(optsIfPresent,
|
|
114
|
-
|
|
115
|
-
// -- remove this block once the old harvest.js & harvest-schedule.js are deleted!
|
|
116
|
-
this.appStorageMap.forEach(eventStore => eventStore.clearSave(optsIfPresent));
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
return this.appStorageMap.get(target)?.clearSave(optsIfPresent);
|
|
143
|
+
clearSave(optsIfPresent, targetEntityGuid) {
|
|
144
|
+
return this.#getEventStore(targetEntityGuid).clearSave(optsIfPresent);
|
|
120
145
|
}
|
|
121
146
|
}
|
|
@@ -6,7 +6,7 @@ import { gosCDN } from '../../common/window/nreum';
|
|
|
6
6
|
const debugId = 1;
|
|
7
7
|
const newrelic = gosCDN();
|
|
8
8
|
export function debugNR1(agentIdentifier, location, event, otherprops = {}, debugName = 'SR') {
|
|
9
|
-
const api = agentIdentifier ? newrelic.initializedAgents[agentIdentifier].
|
|
9
|
+
const api = agentIdentifier ? newrelic.initializedAgents[agentIdentifier].addPageAction : newrelic.addPageAction;
|
|
10
10
|
let url;
|
|
11
11
|
try {
|
|
12
12
|
const locURL = new URL(window.location);
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import { warn } from '../common/util/console';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {import('../loaders/api/register-api-types').RegisterAPI} RegisterAPI
|
|
9
|
+
* @typedef {import('../loaders/api/register-api-types').RegisterAPIMetadata} RegisterAPIMetadata
|
|
10
|
+
* @typedef {import('../loaders/api/register-api-types').RegisterAPIConstructor} RegisterAPIConstructor
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @experimental
|
|
15
|
+
* IMPORTANT: This feature is being developed for use internally and is not in a public-facing production-ready state.
|
|
16
|
+
* It is not recommended for use in production environments and will not receive support for issues.
|
|
17
|
+
*
|
|
18
|
+
* An interface for registering an external caller to report through the base agent to a different target than the base agent.
|
|
19
|
+
*/
|
|
20
|
+
export class RegisteredEntity {
|
|
21
|
+
/** @type {RegisterAPIMetadata} */
|
|
22
|
+
metadata = {
|
|
23
|
+
target: {},
|
|
24
|
+
customAttributes: {}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
*
|
|
29
|
+
* @param {RegisterAPIConstructor} opts The options for setting up the registered entity.
|
|
30
|
+
*/
|
|
31
|
+
constructor(opts) {
|
|
32
|
+
try {
|
|
33
|
+
if (!window?.newrelic) return warn(51);
|
|
34
|
+
Object.assign(this, window?.newrelic?.register(opts) || {});
|
|
35
|
+
} catch (err) {
|
|
36
|
+
warn(50, err);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Reports a browser PageAction event along with a name and optional attributes to the registered target.
|
|
42
|
+
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/addpageaction/}
|
|
43
|
+
* @param {string} name Name or category of the action. Reported as the actionName attribute.
|
|
44
|
+
* @param {object} [attributes] JSON object with one or more key/value pairs. For example: {key:"value"}. The key is reported as its own PageAction attribute with the specified values.
|
|
45
|
+
*/
|
|
46
|
+
addPageAction(name, attributes) {
|
|
47
|
+
/** this method will be overset once register is successful */
|
|
48
|
+
warn(35, 'addPageAction');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Adds a user-defined attribute name and value to subsequent events on the page for the registered target. Note -- the persist flag does not work with the register API.
|
|
53
|
+
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/setcustomattribute/}
|
|
54
|
+
* @param {string} name Name of the attribute. Appears as column in the PageView event. It will also appear as a column in the PageAction event if you are using it.
|
|
55
|
+
* @param {string|number|boolean|null} value Value of the attribute. Appears as the value in the named attribute column in the PageView event. It will appear as a column in the PageAction event if you are using it. Custom attribute values cannot be complex objects, only simple types such as Strings, Integers and Booleans. Passing a null value unsets any existing attribute of the same name.
|
|
56
|
+
* @param {boolean} [persist] Default false. If set to true, the name-value pair will also be set into the browser's storage API. Then on the following instrumented pages that load within the same session, the pair will be re-applied as a custom attribute.
|
|
57
|
+
*/
|
|
58
|
+
setCustomAttribute(name, value, persist) {
|
|
59
|
+
/** this method will be overset once register is successful */
|
|
60
|
+
warn(35, 'setCustomAttribute');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Identifies a browser error without disrupting your app's operations for the registered target.
|
|
65
|
+
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/noticeerror/}
|
|
66
|
+
* @param {Error|string} error Provide a meaningful error message that you can use when analyzing data on browser's JavaScript errors page.
|
|
67
|
+
* @param {object} [customAttributes] An object containing name/value pairs representing custom attributes.
|
|
68
|
+
*/
|
|
69
|
+
noticeError(error, customAttributes) {
|
|
70
|
+
/** this method will be overset once register is successful */
|
|
71
|
+
warn(35, 'noticeError');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Adds a user-defined identifier string to subsequent events on the page for the registered taret.
|
|
76
|
+
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/setuserid/}
|
|
77
|
+
* @param {string|null} value A string identifier for the end-user, useful for tying all browser events to specific users. The value parameter does not have to be unique. If IDs should be unique, the caller is responsible for that validation. Passing a null value unsets any existing user ID.
|
|
78
|
+
*/
|
|
79
|
+
setUserId(value) {
|
|
80
|
+
/** this method will be overset once register is successful */
|
|
81
|
+
warn(35, 'setUserId');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Adds a user-defined application version string to subsequent events on the page for the registered target.
|
|
86
|
+
* This decorates all payloads with an attribute of `application.version` which is queryable in NR1.
|
|
87
|
+
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/setapplicationversion/}
|
|
88
|
+
* @param {string|null} value A string identifier for the application version, useful for
|
|
89
|
+
* tying all browser events to a specific release tag. The value parameter does not
|
|
90
|
+
* have to be unique. Passing a null value unsets any existing value.
|
|
91
|
+
*/
|
|
92
|
+
setApplicationVersion(value) {
|
|
93
|
+
/** this method will be overset once register is successful */
|
|
94
|
+
warn(35, 'setApplicationVersion');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Capture a single log for the registered target.
|
|
99
|
+
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/log/}
|
|
100
|
+
* @param {string} message String to be captured as log message
|
|
101
|
+
* @param {{customAttributes?: object, level?: 'ERROR'|'TRACE'|'DEBUG'|'INFO'|'WARN'}} [options] customAttributes defaults to `{}` if not assigned, level defaults to `info` if not assigned.
|
|
102
|
+
*/
|
|
103
|
+
log(message, options) {
|
|
104
|
+
/** this method will be overset once register is successful */
|
|
105
|
+
warn(35, 'setCustomAttribute');
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -20,7 +20,7 @@ export class AgentBase extends MicroAgentBase {
|
|
|
20
20
|
* @param {...any} args
|
|
21
21
|
*/
|
|
22
22
|
#callMethod(methodName, ...args) {
|
|
23
|
-
if (
|
|
23
|
+
if (this[methodName] === AgentBase.prototype[methodName] || this[methodName] === MicroAgentBase.prototype[methodName]) warn(35, methodName);else return this[methodName](...args);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/**
|
|
@@ -67,6 +67,9 @@ export class Agent extends AgentBase {
|
|
|
67
67
|
runtime: this.runtime
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
|
+
get api() {
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
70
73
|
run() {
|
|
71
74
|
// Attempt to initialize all the requested features (sequentially in prio order & synchronously), with any failure aborting the whole process.
|
|
72
75
|
try {
|
|
@@ -94,7 +97,6 @@ export class Agent extends AgentBase {
|
|
|
94
97
|
this.features[featName].abortHandler?.();
|
|
95
98
|
}
|
|
96
99
|
const newrelic = gosNREUM();
|
|
97
|
-
delete newrelic.initializedAgents[this.agentIdentifier]?.api; // prevent further calls to agent-specific APIs (see "configure.js")
|
|
98
100
|
delete newrelic.initializedAgents[this.agentIdentifier]?.features; // GC mem used internally by features
|
|
99
101
|
delete this.sharedAggregator;
|
|
100
102
|
// Keep the initialized agent object with its configs for troubleshooting purposes.
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { SR_EVENT_EMITTER_TYPES } from '../../features/session_replay/constants';
|
|
6
|
-
export const apiMethods = ['setErrorHandler', 'finished', 'addToTrace', 'addRelease', 'recordCustomEvent', 'addPageAction', 'setCurrentRouteName', 'setPageViewName', 'setCustomAttribute', 'interaction', 'noticeError', 'setUserId', 'setApplicationVersion', 'start', SR_EVENT_EMITTER_TYPES.RECORD, SR_EVENT_EMITTER_TYPES.PAUSE, 'log', 'wrapLogger'];
|
|
6
|
+
export const apiMethods = ['setErrorHandler', 'finished', 'addToTrace', 'addRelease', 'recordCustomEvent', 'addPageAction', 'setCurrentRouteName', 'setPageViewName', 'setCustomAttribute', 'interaction', 'noticeError', 'setUserId', 'setApplicationVersion', 'start', SR_EVENT_EMITTER_TYPES.RECORD, SR_EVENT_EMITTER_TYPES.PAUSE, 'log', 'wrapLogger', 'register'];
|
|
7
7
|
export const asyncApiMethods = ['setErrorHandler', 'finished', 'addToTrace', 'addRelease'];
|