@newrelic/browser-agent 1.301.0 → 1.302.0-alpha.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 +13 -0
- package/dist/cjs/common/config/init-types.js +1 -1
- package/dist/cjs/common/config/init.js +7 -1
- package/dist/cjs/common/config/runtime.js +1 -1
- package/dist/cjs/common/constants/agent-constants.js +11 -2
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/drain/drain.js +1 -1
- package/dist/cjs/common/harvest/harvester.js +30 -39
- package/dist/cjs/common/util/mfe.js +45 -0
- package/dist/cjs/features/ajax/aggregate/index.js +5 -1
- package/dist/cjs/features/generic_events/aggregate/index.js +9 -8
- package/dist/cjs/features/generic_events/constants.js +3 -1
- package/dist/cjs/features/generic_events/instrument/index.js +38 -32
- package/dist/cjs/features/jserrors/aggregate/index.js +18 -17
- package/dist/cjs/features/logging/aggregate/index.js +19 -15
- package/dist/cjs/features/logging/shared/utils.js +3 -3
- package/dist/cjs/features/page_view_event/aggregate/index.js +3 -33
- package/dist/cjs/features/session_replay/aggregate/index.js +13 -13
- package/dist/cjs/features/session_replay/shared/recorder.js +3 -2
- package/dist/cjs/features/session_trace/aggregate/index.js +0 -2
- package/dist/cjs/features/soft_navigations/aggregate/index.js +1 -2
- package/dist/cjs/features/utils/aggregate-base.js +45 -47
- package/dist/cjs/loaders/api/addPageAction.js +2 -2
- package/dist/cjs/loaders/api/log.js +2 -2
- package/dist/cjs/loaders/api/noticeError.js +2 -2
- package/dist/cjs/loaders/api/register-api-types.js +5 -5
- package/dist/cjs/loaders/api/register.js +80 -97
- package/dist/esm/common/config/init-types.js +1 -1
- package/dist/esm/common/config/init.js +7 -1
- package/dist/esm/common/config/runtime.js +1 -1
- package/dist/esm/common/constants/agent-constants.js +9 -1
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/drain/drain.js +1 -1
- package/dist/esm/common/harvest/harvester.js +30 -39
- package/dist/esm/common/util/mfe.js +38 -0
- package/dist/esm/features/ajax/aggregate/index.js +5 -1
- package/dist/esm/features/generic_events/aggregate/index.js +9 -8
- package/dist/esm/features/generic_events/constants.js +3 -1
- package/dist/esm/features/generic_events/instrument/index.js +38 -32
- package/dist/esm/features/jserrors/aggregate/index.js +18 -17
- package/dist/esm/features/logging/aggregate/index.js +19 -15
- package/dist/esm/features/logging/shared/utils.js +3 -3
- package/dist/esm/features/page_view_event/aggregate/index.js +3 -33
- package/dist/esm/features/session_replay/aggregate/index.js +13 -13
- package/dist/esm/features/session_replay/shared/recorder.js +3 -2
- package/dist/esm/features/session_trace/aggregate/index.js +0 -2
- package/dist/esm/features/soft_navigations/aggregate/index.js +1 -2
- package/dist/esm/features/utils/aggregate-base.js +46 -48
- package/dist/esm/loaders/api/addPageAction.js +2 -2
- package/dist/esm/loaders/api/log.js +2 -2
- package/dist/esm/loaders/api/noticeError.js +2 -2
- package/dist/esm/loaders/api/register-api-types.js +5 -5
- package/dist/esm/loaders/api/register.js +80 -97
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/common/config/init-types.d.ts +4 -1
- package/dist/types/common/config/init-types.d.ts.map +1 -1
- package/dist/types/common/config/init.d.ts.map +1 -1
- package/dist/types/common/constants/agent-constants.d.ts +7 -4
- package/dist/types/common/constants/agent-constants.d.ts.map +1 -1
- package/dist/types/common/harvest/harvester.d.ts +2 -2
- package/dist/types/common/harvest/harvester.d.ts.map +1 -1
- package/dist/types/common/util/mfe.d.ts +20 -0
- package/dist/types/common/util/mfe.d.ts.map +1 -0
- package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/generic_events/aggregate/index.d.ts +2 -2
- package/dist/types/features/generic_events/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/generic_events/constants.d.ts +1 -0
- package/dist/types/features/generic_events/instrument/index.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts +3 -3
- 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 -2
- package/dist/types/features/logging/shared/utils.d.ts.map +1 -1
- package/dist/types/features/page_view_event/aggregate/index.d.ts +2 -4
- package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts +13 -4
- package/dist/types/features/session_replay/aggregate/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_trace/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/soft_navigations/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/utils/aggregate-base.d.ts +13 -5
- package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
- package/dist/types/loaders/api/addPageAction.d.ts +1 -1
- package/dist/types/loaders/api/addPageAction.d.ts.map +1 -1
- package/dist/types/loaders/api/log.d.ts +1 -1
- package/dist/types/loaders/api/log.d.ts.map +1 -1
- package/dist/types/loaders/api/noticeError.d.ts +1 -1
- package/dist/types/loaders/api/noticeError.d.ts.map +1 -1
- package/dist/types/loaders/api/register-api-types.d.ts +4 -4
- package/dist/types/loaders/api/register-api-types.d.ts.map +1 -1
- package/dist/types/loaders/api/register.d.ts +8 -1
- package/dist/types/loaders/api/register.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/common/config/init-types.js +1 -1
- package/src/common/config/init.js +3 -1
- package/src/common/config/runtime.js +1 -1
- package/src/common/constants/agent-constants.js +10 -0
- package/src/common/drain/drain.js +1 -1
- package/src/common/harvest/harvester.js +27 -32
- package/src/common/util/mfe.js +35 -0
- package/src/features/ajax/aggregate/index.js +7 -1
- package/src/features/generic_events/aggregate/index.js +9 -8
- package/src/features/generic_events/constants.js +3 -1
- package/src/features/generic_events/instrument/index.js +44 -35
- package/src/features/jserrors/aggregate/index.js +17 -17
- package/src/features/logging/aggregate/index.js +20 -13
- package/src/features/logging/shared/utils.js +3 -3
- package/src/features/page_view_event/aggregate/index.js +3 -28
- package/src/features/session_replay/aggregate/index.js +12 -10
- package/src/features/session_replay/shared/recorder.js +3 -2
- package/src/features/session_trace/aggregate/index.js +0 -2
- package/src/features/soft_navigations/aggregate/index.js +1 -2
- package/src/features/utils/aggregate-base.js +47 -42
- package/src/loaders/api/addPageAction.js +2 -2
- package/src/loaders/api/log.js +2 -2
- package/src/loaders/api/noticeError.js +2 -2
- package/src/loaders/api/register-api-types.js +5 -5
- package/src/loaders/api/register.js +62 -89
- package/dist/cjs/common/util/target.js +0 -34
- package/dist/cjs/features/utils/entity-manager.js +0 -46
- package/dist/cjs/features/utils/event-store-manager.js +0 -174
- package/dist/cjs/loaders/api/register-api.js +0 -165
- package/dist/esm/common/util/target.js +0 -27
- package/dist/esm/features/utils/entity-manager.js +0 -39
- package/dist/esm/features/utils/event-store-manager.js +0 -166
- package/dist/esm/loaders/api/register-api.js +0 -159
- package/dist/types/common/util/target.d.ts +0 -18
- package/dist/types/common/util/target.d.ts.map +0 -1
- package/dist/types/features/utils/entity-manager.d.ts +0 -11
- package/dist/types/features/utils/entity-manager.d.ts.map +0 -1
- package/dist/types/features/utils/event-store-manager.d.ts +0 -85
- package/dist/types/features/utils/event-store-manager.d.ts.map +0 -1
- package/dist/types/loaders/api/register-api.d.ts +0 -14
- package/dist/types/loaders/api/register-api.d.ts.map +0 -1
- package/src/common/util/target.js +0 -27
- package/src/features/utils/entity-manager.js +0 -45
- package/src/features/utils/event-store-manager.js +0 -165
- package/src/loaders/api/register-api.js +0 -152
|
@@ -10,15 +10,12 @@ import { drain } from '../../common/drain/drain'
|
|
|
10
10
|
import { activatedFeatures } from '../../common/util/feature-flags'
|
|
11
11
|
import { Obfuscator } from '../../common/util/obfuscate'
|
|
12
12
|
import { FEATURE_NAMES } from '../../loaders/features/features'
|
|
13
|
-
import { EventStoreManager } from './event-store-manager'
|
|
14
13
|
import { Harvester } from '../../common/harvest/harvester'
|
|
15
|
-
import { warn } from '../../common/util/console'
|
|
16
|
-
import { EntityManager } from './entity-manager'
|
|
17
14
|
import { EventBuffer } from './event-buffer'
|
|
18
15
|
import { handle } from '../../common/event-emitter/handle'
|
|
19
16
|
import { SUPPORTABILITY_METRIC_CHANNEL } from '../metrics/constants'
|
|
20
17
|
import { EventAggregator } from '../../common/aggregate/event-aggregator'
|
|
21
|
-
import { IDEAL_PAYLOAD_SIZE } from '../../common/constants/agent-constants'
|
|
18
|
+
import { MAX_PAYLOAD_SIZE, IDEAL_PAYLOAD_SIZE, SUPPORTS_REGISTERED_ENTITIES } from '../../common/constants/agent-constants'
|
|
22
19
|
|
|
23
20
|
export class AggregateBase extends FeatureBase {
|
|
24
21
|
/**
|
|
@@ -41,16 +38,9 @@ export class AggregateBase extends FeatureBase {
|
|
|
41
38
|
|
|
42
39
|
this.harvestOpts = {} // features aggregate classes can define custom opts for when their harvest is called
|
|
43
40
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
/** wait for the entity guid from the rum response and use to it to further configure things to set the default entity to share an indexed entity with entityGuid */
|
|
48
|
-
this.ee.on('entity-added', entity => {
|
|
49
|
-
// not all event managers have this fn, like ST and SR
|
|
50
|
-
// this allows the lookup to work for the default and an entityGuid without creating two separate buffers
|
|
51
|
-
this.events?.setEventStore?.(entity.entityGuid)
|
|
52
|
-
})
|
|
53
|
-
}
|
|
41
|
+
this.#setupEventStore()
|
|
42
|
+
|
|
43
|
+
this.waitForDrain()
|
|
54
44
|
}
|
|
55
45
|
|
|
56
46
|
/**
|
|
@@ -58,7 +48,7 @@ export class AggregateBase extends FeatureBase {
|
|
|
58
48
|
* @param {string} entityGuid
|
|
59
49
|
* @returns {void}
|
|
60
50
|
*/
|
|
61
|
-
#setupEventStore (
|
|
51
|
+
#setupEventStore () {
|
|
62
52
|
if (this.events) return
|
|
63
53
|
switch (this.featureName) {
|
|
64
54
|
// SessionReplay has its own storage mechanisms.
|
|
@@ -67,17 +57,40 @@ export class AggregateBase extends FeatureBase {
|
|
|
67
57
|
// Jserror and Metric features uses a singleton EventAggregator instead of a regular EventBuffer.
|
|
68
58
|
case FEATURE_NAMES.jserrors:
|
|
69
59
|
case FEATURE_NAMES.metrics:
|
|
70
|
-
this.events = this.agentRef.sharedAggregator ??= new
|
|
60
|
+
this.events = this.agentRef.sharedAggregator ??= new EventAggregator()
|
|
71
61
|
break
|
|
72
|
-
/** All other features get EventBuffer
|
|
62
|
+
/** All other features get EventBuffer 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.
|
|
73
63
|
This was necessary to prevent race cond. issues where the event buffer was checked before the feature could "block" itself.
|
|
74
64
|
Its easier to just keep an empty event buffer in place. */
|
|
75
65
|
default:
|
|
76
|
-
this.events = new
|
|
66
|
+
this.events = new EventBuffer(MAX_PAYLOAD_SIZE, this)
|
|
77
67
|
break
|
|
78
68
|
}
|
|
79
69
|
}
|
|
80
70
|
|
|
71
|
+
/** @type {Boolean} indicates if the feature supports registered entities and the harvest requirements therein. Also read by getter "harvestEndpointVersion". Controlled by feature flag in pre-release phase. */
|
|
72
|
+
get supportsRegisteredEntities () {
|
|
73
|
+
return this.featureName in SUPPORTS_REGISTERED_ENTITIES && (SUPPORTS_REGISTERED_ENTITIES[this.featureName] || this.agentRef.init.feature_flags.includes('register.' + this.featureName))
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* the endpoint version the feature uses during harvests
|
|
78
|
+
* @type {number}
|
|
79
|
+
* @returns {boolean}
|
|
80
|
+
*/
|
|
81
|
+
get harvestEndpointVersion () {
|
|
82
|
+
return (this.supportsRegisteredEntities && !!this.agentRef.runtime.registeredEntities.length) ? 2 : 1
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
waitForDrain () {
|
|
86
|
+
/** emitted when the feature successfully drains */
|
|
87
|
+
this.ee.on('drain-' + this.featureName, () => {
|
|
88
|
+
/** make an immediate harvest for all the features to help with harvestability for pre-load dervied data on short lived pages */
|
|
89
|
+
if (!this.drained) setTimeout(() => this.agentRef.runtime.harvester.triggerHarvestFor(this), 1)
|
|
90
|
+
this.drained = true
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
81
94
|
/**
|
|
82
95
|
* Evaluates whether a harvest should be made early by estimating the size of the current payload. Currently, this only happens if the event storage is EventBuffer, since that triggers this method directly.
|
|
83
96
|
* If conditions are met, a new harvest will be triggered immediately.
|
|
@@ -125,7 +138,6 @@ export class AggregateBase extends FeatureBase {
|
|
|
125
138
|
*/
|
|
126
139
|
drain () {
|
|
127
140
|
drain(this.agentIdentifier, this.featureName)
|
|
128
|
-
this.drained = true
|
|
129
141
|
}
|
|
130
142
|
|
|
131
143
|
preHarvestChecks (opts) {
|
|
@@ -136,44 +148,39 @@ export class AggregateBase extends FeatureBase {
|
|
|
136
148
|
* Return harvest payload. A "serializer" function can be defined on a derived class to format the payload.
|
|
137
149
|
* @param {Boolean} shouldRetryOnFail - harvester flag to backup payload for retry later if harvest request fails; this should be moved to harvester logic
|
|
138
150
|
* @param {object|undefined} opts - opts passed from the harvester to help form the payload
|
|
139
|
-
* @param {string} opts.
|
|
151
|
+
* @param {string} opts.target - the target app metadata
|
|
140
152
|
* @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.
|
|
141
153
|
*/
|
|
142
154
|
makeHarvestPayload (shouldRetryOnFail = false, opts = {}) {
|
|
143
|
-
if (!this.events || this.events.isEmpty(this.harvestOpts
|
|
155
|
+
if (!this.events || this.events.isEmpty(this.harvestOpts)) return
|
|
144
156
|
// Other conditions and things to do when preparing harvest that is required.
|
|
145
157
|
if (this.preHarvestChecks && !this.preHarvestChecks(opts)) return
|
|
146
158
|
|
|
147
|
-
if (shouldRetryOnFail) this.events.save(this.harvestOpts
|
|
148
|
-
const
|
|
149
|
-
if (!
|
|
150
|
-
this.events.clear(this.harvestOpts
|
|
151
|
-
|
|
152
|
-
return returnedDataArr.map(({ targetApp, data }) => {
|
|
153
|
-
// A serializer or formatter assists in creating the payload `body` from stored events on harvest when defined by derived feature class.
|
|
154
|
-
const body = this.serializer ? this.serializer(data, targetApp?.entityGuid) : data
|
|
155
|
-
const payload = {
|
|
156
|
-
body
|
|
157
|
-
}
|
|
158
|
-
// Constructs the payload `qs` for relevant features on harvest.
|
|
159
|
-
if (this.queryStringsBuilder) payload.qs = this.queryStringsBuilder(data, targetApp?.entityGuid)
|
|
159
|
+
if (shouldRetryOnFail) this.events.save(this.harvestOpts)
|
|
160
|
+
const data = this.events.get(this.harvestOpts)
|
|
161
|
+
if (!data) return
|
|
162
|
+
this.events.clear(this.harvestOpts)
|
|
160
163
|
|
|
161
|
-
|
|
162
|
-
|
|
164
|
+
// A serializer or formatter assists in creating the payload `body` from stored events on harvest when defined by derived feature class.
|
|
165
|
+
const body = this.serializer ? this.serializer(data) : data
|
|
166
|
+
const payload = {
|
|
167
|
+
body
|
|
168
|
+
}
|
|
169
|
+
// Constructs the payload `qs` for relevant features on harvest.
|
|
170
|
+
if (this.queryStringsBuilder) payload.qs = this.queryStringsBuilder(data)
|
|
171
|
+
return payload
|
|
163
172
|
}
|
|
164
173
|
|
|
165
174
|
/**
|
|
166
175
|
* Cleanup task after a harvest.
|
|
167
176
|
* @param {object} result - the cbResult object from the harvester's send method
|
|
168
|
-
* @param {object=} result.targetApp - the target app object that was used to point the harvest to the correct app
|
|
169
|
-
* @param {string=} result.targetApp.entityGuid - the entity guid of the target app
|
|
170
177
|
* @param {boolean=} result.sent - whether the harvest was sent successfully
|
|
171
178
|
* @param {boolean=} result.retry - whether the harvest should be retried
|
|
172
179
|
*/
|
|
173
180
|
postHarvestCleanup (result = {}) {
|
|
174
181
|
this.isRetrying = result.sent && result.retry
|
|
175
|
-
if (this.isRetrying) this.events.reloadSave(this.harvestOpts
|
|
176
|
-
this.events.clearSave(this.harvestOpts
|
|
182
|
+
if (this.isRetrying) this.events.reloadSave(this.harvestOpts)
|
|
183
|
+
this.events.clearSave(this.harvestOpts)
|
|
177
184
|
}
|
|
178
185
|
|
|
179
186
|
/**
|
|
@@ -212,8 +219,6 @@ export class AggregateBase extends FeatureBase {
|
|
|
212
219
|
if (!agentRef.runtime.obfuscator) agentRef.runtime.obfuscator = new Obfuscator(agentRef)
|
|
213
220
|
this.obfuscator = agentRef.runtime.obfuscator
|
|
214
221
|
|
|
215
|
-
if (!agentRef.runtime.entityManager) agentRef.runtime.entityManager = new EntityManager(this.agentRef)
|
|
216
|
-
|
|
217
222
|
if (!agentRef.runtime.harvester) agentRef.runtime.harvester = new Harvester(agentRef)
|
|
218
223
|
}
|
|
219
224
|
|
|
@@ -12,6 +12,6 @@ export function setupAddPageActionAPI (agent) {
|
|
|
12
12
|
setupAPI(ADD_PAGE_ACTION, (name, attributes) => addPageAction(name, attributes, agent), agent)
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
export function addPageAction (name, attributes, agentRef,
|
|
16
|
-
handle(prefix + ADD_PAGE_ACTION, [timestamp, name, attributes,
|
|
15
|
+
export function addPageAction (name, attributes, agentRef, target, timestamp = now()) {
|
|
16
|
+
handle(prefix + ADD_PAGE_ACTION, [timestamp, name, attributes, target], undefined, FEATURE_NAMES.genericEvents, agentRef.ee)
|
|
17
17
|
}
|
package/src/loaders/api/log.js
CHANGED
|
@@ -13,6 +13,6 @@ export function setupLogAPI (agent) {
|
|
|
13
13
|
setupAPI(LOG, (message, options) => log(message, options, agent), agent)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export function log (message, { customAttributes = {}, level = LOG_LEVELS.INFO } = {}, agentRef,
|
|
17
|
-
bufferLog(agentRef.ee, message, customAttributes, level,
|
|
16
|
+
export function log (message, { customAttributes = {}, level = LOG_LEVELS.INFO } = {}, agentRef, target, timestamp = now()) {
|
|
17
|
+
bufferLog(agentRef.ee, message, customAttributes, level, target, timestamp)
|
|
18
18
|
}
|
|
@@ -12,8 +12,8 @@ export function setupNoticeErrorAPI (agent) {
|
|
|
12
12
|
setupAPI(NOTICE_ERROR, (err, customAttributes) => noticeError(err, customAttributes, agent), agent)
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
export function noticeError (err, customAttributes, agentRef,
|
|
15
|
+
export function noticeError (err, customAttributes, agentRef, target, timestamp = now()) {
|
|
16
16
|
if (typeof err === 'string') err = new Error(err)
|
|
17
|
-
handle('err', [err, timestamp, false, customAttributes, agentRef.runtime.isRecording, undefined,
|
|
17
|
+
handle('err', [err, timestamp, false, customAttributes, agentRef.runtime.isRecording, undefined, target], undefined, FEATURE_NAMES.jserrors, agentRef.ee)
|
|
18
18
|
handle('uaErr', [], undefined, FEATURE_NAMES.genericEvents, agentRef.ee)
|
|
19
19
|
}
|
|
@@ -17,17 +17,17 @@
|
|
|
17
17
|
/**
|
|
18
18
|
* @typedef {Object} RegisterAPIConstructor
|
|
19
19
|
* @property {Object} opts - The options for the registered entity.
|
|
20
|
-
* @property {string} opts.
|
|
21
|
-
* @property {string} opts.
|
|
20
|
+
* @property {string} opts.id - The unique id for the registered entity. This will be assigned to any synthesized entities.
|
|
21
|
+
* @property {string} opts.name - The readable name for the registered entity. This will be assigned to any synthesized entities.
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* @typedef {Object} RegisterAPIMetadata
|
|
26
26
|
* @property {Object} customAttributes - The custom attributes for the registered entity.
|
|
27
27
|
* @property {Object} target - The options for the registered entity.
|
|
28
|
-
* @property {string} target.licenseKey - The license key for the registered entity.
|
|
29
|
-
* @property {string} target.
|
|
30
|
-
* @property {string} target.
|
|
28
|
+
* @property {string} target.licenseKey - The license key for the registered entity. If none was supplied, it will assume the license key from the main agent.
|
|
29
|
+
* @property {string} target.id - The ID for the registered entity.
|
|
30
|
+
* @property {string} target.name - The name returned for the registered entity.
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
33
|
export default {}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { handle } from '../../common/event-emitter/handle'
|
|
6
6
|
import { warn } from '../../common/util/console'
|
|
7
|
-
import {
|
|
7
|
+
import { isValidMFETarget } from '../../common/util/mfe'
|
|
8
8
|
import { FEATURE_NAMES } from '../features/features'
|
|
9
9
|
import { now } from '../../common/timing/now'
|
|
10
10
|
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../features/metrics/constants'
|
|
@@ -13,6 +13,7 @@ import { REGISTER } from './constants'
|
|
|
13
13
|
import { log } from './log'
|
|
14
14
|
import { addPageAction } from './addPageAction'
|
|
15
15
|
import { noticeError } from './noticeError'
|
|
16
|
+
import { single } from '../../common/util/invoke'
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* @typedef {import('./register-api-types').RegisterAPI} RegisterAPI
|
|
@@ -35,106 +36,80 @@ export function setupRegisterAPI (agent) {
|
|
|
35
36
|
* @param {Object} agentRef the reference to the base agent instance
|
|
36
37
|
* @param {Object} handlers the shared handlers to be used by both the base agent's API and the external target's API
|
|
37
38
|
* @param {Object} target the target information to be used by the external target's API to send data to the correct location
|
|
39
|
+
* @param {string} [target.licenseKey] the license key of the target to report data to
|
|
40
|
+
* @param {string} target.id the entity ID of the target to report data to
|
|
41
|
+
* @param {string} target.name the entity name of the target to report data to
|
|
38
42
|
* @returns {RegisterAPI} the api object to be returned from the register api method
|
|
39
43
|
*/
|
|
40
44
|
export function buildRegisterApi (agentRef, target) {
|
|
41
45
|
const attrs = {}
|
|
42
46
|
warn(54, 'newrelic.register')
|
|
43
47
|
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
target ||= {}
|
|
49
|
+
target.licenseKey ||= agentRef.info.licenseKey // will inherit the license key from the container agent if not provided for brevity. A future state may dictate that we need different license keys to do different things.
|
|
50
|
+
target.blocked = false
|
|
51
|
+
|
|
52
|
+
/** @type {Function} a function that is set and reports when APIs are triggered -- warns the customer of the invalid state */
|
|
53
|
+
let invalidApiResponse = () => {}
|
|
54
|
+
/** @type {Array} the array of registered target APIs */
|
|
55
|
+
const registeredEntities = agentRef.runtime.registeredEntities
|
|
56
|
+
|
|
57
|
+
/** if we have already registered this target, go ahead and re-use it */
|
|
58
|
+
const preregisteredEntity = registeredEntities.find(({ metadata: { target: { id, name } } }) => id === target.id)
|
|
59
|
+
if (preregisteredEntity) {
|
|
60
|
+
if (preregisteredEntity.metadata.target.name !== target.name) preregisteredEntity.metadata.target.name = target.name
|
|
61
|
+
return preregisteredEntity
|
|
62
|
+
}
|
|
46
63
|
|
|
47
64
|
/**
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
65
|
+
* Block the API, and supply a warning function to display a message to end users
|
|
66
|
+
* @param {Function} warning
|
|
67
|
+
*/
|
|
68
|
+
const block = (warning) => {
|
|
69
|
+
target.blocked = true
|
|
70
|
+
invalidApiResponse = warning
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** primary cases that can block the register API from working at init time */
|
|
74
|
+
if (!agentRef.init.api.allow_registered_children) block(single(() => warn(55)))
|
|
75
|
+
if (!isValidMFETarget(target)) block(single(() => warn(48, target)))
|
|
56
76
|
|
|
57
77
|
/** @type {RegisterAPI} */
|
|
58
78
|
const api = {
|
|
59
|
-
addPageAction: (name, attributes = {}) => {
|
|
60
|
-
|
|
61
|
-
},
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
noticeError: (error, attributes = {}) => {
|
|
66
|
-
report(noticeError, [error, { ...attrs, ...attributes }, agentRef], target)
|
|
67
|
-
},
|
|
68
|
-
setApplicationVersion: (value) => {
|
|
69
|
-
attrs['application.version'] = value
|
|
70
|
-
},
|
|
71
|
-
setCustomAttribute: (key, value) => {
|
|
72
|
-
attrs[key] = value
|
|
73
|
-
},
|
|
74
|
-
setUserId: (value) => {
|
|
75
|
-
attrs['enduser.id'] = value
|
|
76
|
-
},
|
|
79
|
+
addPageAction: (name, attributes = {}) => report(addPageAction, [name, { ...attrs, ...attributes }, agentRef], target),
|
|
80
|
+
log: (message, options = {}) => report(log, [message, { ...options, customAttributes: { ...attrs, ...(options.customAttributes || {}) } }, agentRef], target),
|
|
81
|
+
noticeError: (error, attributes = {}) => report(noticeError, [error, { ...attrs, ...attributes }, agentRef], target),
|
|
82
|
+
setApplicationVersion: (value) => setLocalValue('application.version', value),
|
|
83
|
+
setCustomAttribute: (key, value) => setLocalValue(key, value),
|
|
84
|
+
setUserId: (value) => setLocalValue('enduser.id', value),
|
|
77
85
|
/** metadata */
|
|
78
86
|
metadata: {
|
|
79
87
|
customAttributes: attrs,
|
|
80
|
-
target
|
|
81
|
-
/** set in a getter so that later access of the Promise is not polluted before customer is allowed to set a catch block */
|
|
82
|
-
get connected () {
|
|
83
|
-
return _connected || Promise.reject(new Error('Failed to connect'))
|
|
84
|
-
}
|
|
88
|
+
target
|
|
85
89
|
}
|
|
86
90
|
}
|
|
87
91
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
/** check if registered target already has entity guid */
|
|
97
|
-
let registeredEntityGuid = entityManager?.getEntityGuidFor(target.licenseKey, target.applicationID)
|
|
98
|
-
let registrationReady = !!registeredEntityGuid
|
|
99
|
-
|
|
100
|
-
/** check if we can just resolve immediately without making another connect call */
|
|
101
|
-
if (mainAgentReady && registrationReady) {
|
|
102
|
-
target.entityGuid = registeredEntityGuid
|
|
103
|
-
resolve(api)
|
|
104
|
-
} else {
|
|
105
|
-
/** we need to make a new connection call since we dont already have a registered entity for this call */
|
|
106
|
-
|
|
107
|
-
/** if the connect callback doesnt resolve in 15 seconds... reject */
|
|
108
|
-
const timeout = setTimeout(() => reject(new Error('Failed to connect - Timeout')), 15000)
|
|
109
|
-
|
|
110
|
-
// tell the main agent to send a rum call for this target
|
|
111
|
-
// when the rum call resolves, it will emit an "entity-added" event, see below
|
|
112
|
-
agentRef.ee.emit('api-send-rum', [attrs, target])
|
|
113
|
-
|
|
114
|
-
// wait for entity events to emit to see when main agent and/or API registration is ready
|
|
115
|
-
agentRef.ee.on('entity-added', entityEventHandler)
|
|
92
|
+
/**
|
|
93
|
+
* Check if the API is blocked and emit a warning message describing the blockage
|
|
94
|
+
* @returns {boolean}
|
|
95
|
+
*/
|
|
96
|
+
const isBlocked = () => {
|
|
97
|
+
if (target.blocked) invalidApiResponse()
|
|
98
|
+
return target.blocked
|
|
99
|
+
}
|
|
116
100
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
else {
|
|
120
|
-
if (target.licenseKey === entity.licenseKey && target.applicationID === entity.applicationID) {
|
|
121
|
-
registrationReady = true
|
|
122
|
-
target.entityGuid = entity.entityGuid
|
|
123
|
-
}
|
|
124
|
-
}
|
|
101
|
+
/** only allow registered APIs to be tracked in the agent runtime */
|
|
102
|
+
if (!isBlocked()) registeredEntities.push(api)
|
|
125
103
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
reject(err)
|
|
136
|
-
}
|
|
137
|
-
})
|
|
104
|
+
/**
|
|
105
|
+
* Sets a value local to the registered API attrs. Will do nothing if APIs are deregistered.
|
|
106
|
+
* @param {string} key The attribute key
|
|
107
|
+
* @param {*} value the attribute value
|
|
108
|
+
* @returns {void}
|
|
109
|
+
*/
|
|
110
|
+
const setLocalValue = (key, value) => {
|
|
111
|
+
if (isBlocked()) return
|
|
112
|
+
attrs[key] = value
|
|
138
113
|
}
|
|
139
114
|
|
|
140
115
|
/**
|
|
@@ -142,23 +117,21 @@ export function buildRegisterApi (agentRef, target) {
|
|
|
142
117
|
* If the api.duplicate_registered_data configuration value is set to true, the data will be reported to BOTH the container and the external target
|
|
143
118
|
* @param {*} methodToCall the container agent's API method to call
|
|
144
119
|
* @param {*} args the arguments to supply to the container agent's API method
|
|
145
|
-
* @param {string}
|
|
120
|
+
* @param {string} target the target to report the data to. If undefined, will report to the container agent's target.
|
|
146
121
|
* @returns
|
|
147
122
|
*/
|
|
148
|
-
const report =
|
|
149
|
-
if (
|
|
123
|
+
const report = (methodToCall, args, target) => {
|
|
124
|
+
if (isBlocked()) return
|
|
150
125
|
/** set the timestamp before the async part of waiting for the rum response for better accuracy */
|
|
151
126
|
const timestamp = now()
|
|
152
127
|
handle(SUPPORTABILITY_METRIC_CHANNEL, [`API/register/${methodToCall.name}/called`], undefined, FEATURE_NAMES.metrics, agentRef.ee)
|
|
153
128
|
try {
|
|
154
|
-
await _connected
|
|
155
|
-
// target should be decorated with entityGuid by the rum resp at this point
|
|
156
129
|
const shouldDuplicate = agentRef.init.api.duplicate_registered_data
|
|
157
|
-
if (shouldDuplicate === true ||
|
|
130
|
+
if (shouldDuplicate === true || Array.isArray(shouldDuplicate)) {
|
|
158
131
|
// also report to container by providing undefined target
|
|
159
132
|
methodToCall(...args, undefined, timestamp)
|
|
160
133
|
}
|
|
161
|
-
methodToCall(...args, target
|
|
134
|
+
return methodToCall(...args, target, timestamp) // always report to target
|
|
162
135
|
} catch (err) {
|
|
163
136
|
warn(50, err)
|
|
164
137
|
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.isContainerAgentTarget = isContainerAgentTarget;
|
|
7
|
-
exports.isValidTarget = isValidTarget;
|
|
8
|
-
/**
|
|
9
|
-
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
10
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* @param {Object} [target] - the target to be validated
|
|
15
|
-
* @param {boolean} [allowUndefined=true]
|
|
16
|
-
* @returns {boolean}
|
|
17
|
-
*/
|
|
18
|
-
function isValidTarget(target) {
|
|
19
|
-
/** target can be undefined to support legacy/default behaviors - main agent does not supply a target */
|
|
20
|
-
if (!target) return true;
|
|
21
|
-
/** if not undefined, we require specific values */
|
|
22
|
-
return !!(target.licenseKey && target.applicationID);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Checks if the target matches the container agent target
|
|
27
|
-
* @param {*} target the target to be validated
|
|
28
|
-
* @param {*} agentRef the agent reference to be validated
|
|
29
|
-
* @returns {boolean}
|
|
30
|
-
*/
|
|
31
|
-
function isContainerAgentTarget(target, agentRef) {
|
|
32
|
-
if (!target) return true;
|
|
33
|
-
return target.licenseKey === agentRef.info.licenseKey && target.applicationID === agentRef.info.applicationID;
|
|
34
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.EntityManager = void 0;
|
|
7
|
-
var _agentConstants = require("../../common/constants/agent-constants");
|
|
8
|
-
/**
|
|
9
|
-
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
10
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
class EntityManager {
|
|
14
|
-
#entities = new Map();
|
|
15
|
-
#entityGuidLookup = {};
|
|
16
|
-
constructor(agentRef) {
|
|
17
|
-
this.agentRef = agentRef;
|
|
18
|
-
this.#entities.set(_agentConstants.DEFAULT_KEY, {
|
|
19
|
-
licenseKey: agentRef.info.licenseKey,
|
|
20
|
-
applicationID: agentRef.info.applicationID
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
get(entityGuid = _agentConstants.DEFAULT_KEY) {
|
|
24
|
-
return this.#entities.get(entityGuid);
|
|
25
|
-
}
|
|
26
|
-
getEntityGuidFor(licenseKey, applicationID) {
|
|
27
|
-
if (!this.#entityGuidLookup[licenseKey] || !this.#entityGuidLookup[applicationID]) return;
|
|
28
|
-
return this.#entityGuidLookup[licenseKey].filter(x => this.#entityGuidLookup[applicationID].includes(x))[0];
|
|
29
|
-
}
|
|
30
|
-
set(entityGuid, entity) {
|
|
31
|
-
if (this.#entities.has(entityGuid)) return;
|
|
32
|
-
this.#entities.set(entityGuid, entity);
|
|
33
|
-
this.#entityGuidLookup[entity.licenseKey] ??= [];
|
|
34
|
-
this.#entityGuidLookup[entity.licenseKey].push(entityGuid);
|
|
35
|
-
this.#entityGuidLookup[entity.applicationID] ??= [];
|
|
36
|
-
this.#entityGuidLookup[entity.applicationID].push(entityGuid);
|
|
37
|
-
this.agentRef.ee.emit('entity-added', [entity]);
|
|
38
|
-
}
|
|
39
|
-
clear() {
|
|
40
|
-
this.#entities.clear();
|
|
41
|
-
}
|
|
42
|
-
setDefaultEntity(entity) {
|
|
43
|
-
this.#entities.set(_agentConstants.DEFAULT_KEY, entity);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
exports.EntityManager = EntityManager;
|