@newrelic/browser-agent 1.273.0 → 1.273.1

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.
@@ -1,6 +1,3 @@
1
- import { getInfo } from '../../common/config/info'
2
- import { getConfiguration } from '../../common/config/init'
3
- import { getRuntime } from '../../common/config/runtime'
4
1
  import { drain } from '../../common/drain/drain'
5
2
  import { ee } from '../../common/event-emitter/contextual-ee'
6
3
  import { registerHandler } from '../../common/event-emitter/register-handler'
@@ -8,15 +5,13 @@ import { SessionEntity } from '../../common/session/session-entity'
8
5
  import { LocalStorage } from '../../common/storage/local-storage.js'
9
6
  import { DEFAULT_KEY } from '../../common/session/constants'
10
7
 
11
- let ranOnce = 0
12
- export function setupAgentSession (agentIdentifier) {
13
- const agentRuntime = getRuntime(agentIdentifier)
14
- if (ranOnce++) return agentRuntime.session
8
+ export function setupAgentSession (agentRef) {
9
+ if (agentRef.runtime.session) return agentRef.runtime.session // already setup
15
10
 
16
- const sessionInit = getConfiguration(agentIdentifier).session
11
+ const sessionInit = agentRef.init.session
17
12
 
18
- agentRuntime.session = new SessionEntity({
19
- agentIdentifier,
13
+ agentRef.runtime.session = new SessionEntity({
14
+ agentIdentifier: agentRef.agentIdentifier,
20
15
  key: DEFAULT_KEY,
21
16
  storage: new LocalStorage(),
22
17
  expiresMs: sessionInit?.expiresMs,
@@ -24,29 +19,28 @@ export function setupAgentSession (agentIdentifier) {
24
19
  })
25
20
 
26
21
  // Retrieve & re-add all of the persisted setCustomAttribute|setUserId k-v from previous page load(s), if any was stored.
27
- const customSessionData = agentRuntime.session.state.custom
28
- const agentInfo = getInfo(agentIdentifier)
22
+ const customSessionData = agentRef.runtime.session.state.custom
29
23
  if (customSessionData) {
30
- agentInfo.jsAttributes = { ...agentInfo.jsAttributes, ...customSessionData }
24
+ agentRef.info.jsAttributes = { ...agentRef.info.jsAttributes, ...customSessionData }
31
25
  }
32
26
 
33
- const sharedEE = ee.get(agentIdentifier)
27
+ const sharedEE = ee.get(agentRef.agentIdentifier)
34
28
 
35
29
  // any calls to newrelic.setCustomAttribute(<persisted>) will need to be added to:
36
30
  // local info.jsAttributes {}
37
31
  // the session's storage API
38
32
  registerHandler('api-setCustomAttribute', (time, key, value) => {
39
- agentRuntime.session.syncCustomAttribute(key, value)
33
+ agentRef.runtime.session.syncCustomAttribute(key, value)
40
34
  }, 'session', sharedEE)
41
35
 
42
36
  // any calls to newrelic.setUserId(...) will need to be added to:
43
37
  // local info.jsAttributes {}
44
38
  // the session's storage API
45
39
  registerHandler('api-setUserId', (time, key, value) => {
46
- agentRuntime.session.syncCustomAttribute(key, value)
40
+ agentRef.runtime.session.syncCustomAttribute(key, value)
47
41
  }, 'session', sharedEE)
48
42
 
49
- drain(agentIdentifier, 'session')
43
+ drain(agentRef.agentIdentifier, 'session')
50
44
 
51
- return agentRuntime.session
45
+ return agentRef.runtime.session
52
46
  }
@@ -82,7 +82,7 @@ export class InstrumentBase extends FeatureBase {
82
82
  try {
83
83
  if (canEnableSessionTracking(this.agentIdentifier)) { // would require some setup before certain features start
84
84
  const { setupAgentSession } = await import(/* webpackChunkName: "session-manager" */ './agent-session')
85
- session = setupAgentSession(this.agentIdentifier)
85
+ session = setupAgentSession(agentRef)
86
86
  }
87
87
  } catch (e) {
88
88
  warn(20, e)
@@ -2,19 +2,13 @@
2
2
 
3
3
  import { warn } from '../common/util/console'
4
4
  import { SR_EVENT_EMITTER_TYPES } from '../features/session_replay/constants'
5
- import { generateRandomHexString } from '../common/ids/unique-id'
5
+ import { MicroAgentBase } from './micro-agent-base'
6
6
 
7
7
  /**
8
8
  * @typedef {import('./api/interaction-types').InteractionInstance} InteractionInstance
9
9
  */
10
10
 
11
- export class AgentBase {
12
- agentIdentifier
13
-
14
- constructor (agentIdentifier = generateRandomHexString(16)) {
15
- this.agentIdentifier = agentIdentifier
16
- }
17
-
11
+ export class AgentBase extends MicroAgentBase {
18
12
  /**
19
13
  * Tries to execute the api and generates a generic warning message with the api name injected if unsuccessful
20
14
  * @param {string} methodName
@@ -26,74 +20,11 @@ export class AgentBase {
26
20
  }
27
21
 
28
22
  /**
29
- * Reports a browser PageAction event along with a name and optional attributes.
30
- * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/addpageaction/}
31
- * @param {string} name Name or category of the action. Reported as the actionName attribute.
32
- * @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.
33
- */
34
- addPageAction (name, attributes) {
35
- return this.#callMethod('addPageAction', name, attributes)
36
- }
37
-
38
- /**
39
- * Groups page views to help URL structure or to capture the URL's routing information.
40
- * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/setpageviewname/}
41
- * @param {string} name The page name you want to use. Use alphanumeric characters.
42
- * @param {string} [host] Default is http://custom.transaction. Typically set host to your site's domain URI.
43
- */
44
- setPageViewName (name, host) {
45
- return this.#callMethod('setPageViewName', name, host)
46
- }
47
-
48
- /**
49
- * Adds a user-defined attribute name and value to subsequent events on the page.
50
- * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/setcustomattribute/}
51
- * @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.
52
- * @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.
53
- * @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.
54
- */
55
- setCustomAttribute (name, value, persist) {
56
- return this.#callMethod('setCustomAttribute', name, value, persist)
57
- }
58
-
59
- /**
60
- * Identifies a browser error without disrupting your app's operations.
61
- * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/noticeerror/}
62
- * @param {Error|string} error Provide a meaningful error message that you can use when analyzing data on browser's JavaScript errors page.
63
- * @param {object} [customAttributes] An object containing name/value pairs representing custom attributes.
64
- */
65
- noticeError (error, customAttributes) {
66
- return this.#callMethod('noticeError', error, customAttributes)
67
- }
68
-
69
- /**
70
- * Adds a user-defined identifier string to subsequent events on the page.
71
- * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/setuserid/}
72
- * @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.
73
- */
74
- setUserId (value) {
75
- return this.#callMethod('setUserId', value)
76
- }
77
-
78
- /**
79
- * Adds a user-defined application version string to subsequent events on the page.
80
- * This decorates all payloads with an attribute of `application.version` which is queryable in NR1.
81
- * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/setapplicationversion/}
82
- * @param {string|null} value A string identifier for the application version, useful for
83
- * tying all browser events to a specific release tag. The value parameter does not
84
- * have to be unique. Passing a null value unsets any existing value.
85
- */
86
- setApplicationVersion (value) {
87
- return this.#callMethod('setApplicationVersion', value)
88
- }
89
-
90
- /**
91
- * Allows selective ignoring and grouping of known errors that the browser agent captures.
92
- * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/seterrorhandler/}
93
- * @param {(error: Error|string) => boolean | { group: string }} callback When an error occurs, the callback is called with the error object as a parameter. The callback will be called with each error, so it is not specific to one error.
23
+ * Starts any and all features that are not running yet in "autoStart" mode
24
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/start/}
94
25
  */
95
- setErrorHandler (callback) {
96
- return this.#callMethod('setErrorHandler', callback)
26
+ start () {
27
+ return this.#callMethod('start')
97
28
  }
98
29
 
99
30
  /**
@@ -105,25 +36,6 @@ export class AgentBase {
105
36
  return this.#callMethod('finished', timeStamp)
106
37
  }
107
38
 
108
- /**
109
- * Adds a unique name and ID to identify releases with multiple JavaScript bundles on the same page.
110
- * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/addrelease/}
111
- * @param {string} name A short description of the component; for example, the name of a project, application, file, or library.
112
- * @param {string} id The ID or version of this release; for example, a version number, build number from your CI environment, GitHub SHA, GUID, or a hash of the contents.
113
- */
114
- addRelease (name, id) {
115
- return this.#callMethod('addRelease', name, id)
116
- }
117
-
118
- /**
119
- * Starts a set of agent features if not running in "autoStart" mode
120
- * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/start/}
121
- * @param {string|string[]} [featureNames] The name(s) of the features to start. If no name(s) are passed, all features will be started
122
- */
123
- start (featureNames) {
124
- return this.#callMethod('start', featureNames)
125
- }
126
-
127
39
  /**
128
40
  * Forces a replay to record. If a replay is already actively recording, this call will be ignored.
129
41
  * If a recording has not been started, a new one will be created. If a recording has been started, but is currently not recording, it will resume recording.
@@ -179,16 +91,6 @@ export class AgentBase {
179
91
  return this.#callMethod('interaction')
180
92
  }
181
93
 
182
- /**
183
- * Capture a single log.
184
- * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/log/}
185
- * @param {string} message String to be captured as log message
186
- * @param {{customAttributes?: object, level?: 'ERROR'|'TRACE'|'DEBUG'|'INFO'|'WARN'}} [options] customAttributes defaults to `{}` if not assigned, level defaults to `info` if not assigned.
187
- */
188
- log (message, options) {
189
- return this.#callMethod('log', message, options)
190
- }
191
-
192
94
  /**
193
95
  * Wrap a logger function to capture a log each time the function is invoked with the message and arguments passed
194
96
  * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/wraplogger/}
@@ -0,0 +1,113 @@
1
+ import { warn } from '../common/util/console'
2
+ import { generateRandomHexString } from '../common/ids/unique-id'
3
+
4
+ export class MicroAgentBase {
5
+ agentIdentifier
6
+
7
+ constructor (agentIdentifier = generateRandomHexString(16)) {
8
+ this.agentIdentifier = agentIdentifier
9
+ }
10
+
11
+ /**
12
+ * Tries to execute the api and generates a generic warning message with the api name injected if unsuccessful
13
+ * @param {string} methodName
14
+ * @param {...any} args
15
+ */
16
+ #callMethod (methodName, ...args) {
17
+ if (typeof this.api?.[methodName] !== 'function') warn(35, methodName)
18
+ else return this.api[methodName](...args)
19
+ }
20
+
21
+ // MicroAgent class custom defines its own start
22
+
23
+ /**
24
+ * Reports a browser PageAction event along with a name and optional attributes.
25
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/addpageaction/}
26
+ * @param {string} name Name or category of the action. Reported as the actionName attribute.
27
+ * @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.
28
+ */
29
+ addPageAction (name, attributes) {
30
+ return this.#callMethod('addPageAction', name, attributes)
31
+ }
32
+
33
+ /**
34
+ * Groups page views to help URL structure or to capture the URL's routing information.
35
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/setpageviewname/}
36
+ * @param {string} name The page name you want to use. Use alphanumeric characters.
37
+ * @param {string} [host] Default is http://custom.transaction. Typically set host to your site's domain URI.
38
+ */
39
+ setPageViewName (name, host) {
40
+ return this.#callMethod('setPageViewName', name, host)
41
+ }
42
+
43
+ /**
44
+ * Adds a user-defined attribute name and value to subsequent events on the page.
45
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/setcustomattribute/}
46
+ * @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.
47
+ * @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.
48
+ * @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.
49
+ */
50
+ setCustomAttribute (name, value, persist) {
51
+ return this.#callMethod('setCustomAttribute', name, value, persist)
52
+ }
53
+
54
+ /**
55
+ * Identifies a browser error without disrupting your app's operations.
56
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/noticeerror/}
57
+ * @param {Error|string} error Provide a meaningful error message that you can use when analyzing data on browser's JavaScript errors page.
58
+ * @param {object} [customAttributes] An object containing name/value pairs representing custom attributes.
59
+ */
60
+ noticeError (error, customAttributes) {
61
+ return this.#callMethod('noticeError', error, customAttributes)
62
+ }
63
+
64
+ /**
65
+ * Adds a user-defined identifier string to subsequent events on the page.
66
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/setuserid/}
67
+ * @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.
68
+ */
69
+ setUserId (value) {
70
+ return this.#callMethod('setUserId', value)
71
+ }
72
+
73
+ /**
74
+ * Adds a user-defined application version string to subsequent events on the page.
75
+ * This decorates all payloads with an attribute of `application.version` which is queryable in NR1.
76
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/setapplicationversion/}
77
+ * @param {string|null} value A string identifier for the application version, useful for
78
+ * tying all browser events to a specific release tag. The value parameter does not
79
+ * have to be unique. Passing a null value unsets any existing value.
80
+ */
81
+ setApplicationVersion (value) {
82
+ return this.#callMethod('setApplicationVersion', value)
83
+ }
84
+
85
+ /**
86
+ * Allows selective ignoring and grouping of known errors that the browser agent captures.
87
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/seterrorhandler/}
88
+ * @param {(error: Error|string) => boolean | { group: string }} callback When an error occurs, the callback is called with the error object as a parameter. The callback will be called with each error, so it is not specific to one error.
89
+ */
90
+ setErrorHandler (callback) {
91
+ return this.#callMethod('setErrorHandler', callback)
92
+ }
93
+
94
+ /**
95
+ * Adds a unique name and ID to identify releases with multiple JavaScript bundles on the same page.
96
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/addrelease/}
97
+ * @param {string} name A short description of the component; for example, the name of a project, application, file, or library.
98
+ * @param {string} id The ID or version of this release; for example, a version number, build number from your CI environment, GitHub SHA, GUID, or a hash of the contents.
99
+ */
100
+ addRelease (name, id) {
101
+ return this.#callMethod('addRelease', name, id)
102
+ }
103
+
104
+ /**
105
+ * Capture a single log.
106
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/log/}
107
+ * @param {string} message String to be captured as log message
108
+ * @param {{customAttributes?: object, level?: 'ERROR'|'TRACE'|'DEBUG'|'INFO'|'WARN'}} [options] customAttributes defaults to `{}` if not assigned, level defaults to `info` if not assigned.
109
+ */
110
+ log (message, options) {
111
+ return this.#callMethod('log', message, options)
112
+ }
113
+ }
@@ -4,13 +4,9 @@ import { getEnabledFeatures } from './features/enabled-features'
4
4
  import { configure } from './configure/configure'
5
5
  // core files
6
6
  import { setNREUMInitializedAgent } from '../common/window/nreum'
7
- import { getInfo } from '../common/config/info'
8
- import { getConfiguration, getConfigurationValue } from '../common/config/init'
9
- import { getLoaderConfig } from '../common/config/loader-config'
10
- import { getRuntime } from '../common/config/runtime'
11
7
  import { FEATURE_NAMES } from './features/features'
12
8
  import { warn } from '../common/util/console'
13
- import { AgentBase } from './agent-base'
9
+ import { MicroAgentBase } from './micro-agent-base'
14
10
 
15
11
  const nonAutoFeatures = [
16
12
  FEATURE_NAMES.jserrors,
@@ -24,7 +20,7 @@ const nonAutoFeatures = [
24
20
  * automatically instrument. Instead, each MicroAgent instance will lazy load the required features and can support loading multiple instances on one page.
25
21
  * Out of the box, it can manually handle and report Page View, Page Action, and Error events.
26
22
  */
27
- export class MicroAgent extends AgentBase {
23
+ export class MicroAgent extends MicroAgentBase {
28
24
  /**
29
25
  * @param {Object} options - Specifies features and runtime configuration,
30
26
  * @param {string=} agentIdentifier - The optional unique ID of the agent.
@@ -41,62 +37,53 @@ export class MicroAgent extends AgentBase {
41
37
  /**
42
38
  * Starts a set of agent features if not running in "autoStart" mode
43
39
  * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/start/}
44
- * @param {string|string[]|undefined} name The feature name(s) to start. If no name(s) are passed, all features will be started
40
+ * @param {string|string[]} [featureNames] The feature name(s) to start. If no name(s) are passed, all features will be started
45
41
  */
46
- this.start = features => this.run(features)
47
- this.run(nonAutoFeatures.filter(featureName => getConfigurationValue(this.agentIdentifier, `${featureName}.autoStart`)))
48
- }
49
-
50
- get config () {
51
- return {
52
- info: getInfo(this.agentIdentifier),
53
- init: getConfiguration(this.agentIdentifier),
54
- loader_config: getLoaderConfig(this.agentIdentifier),
55
- runtime: getRuntime(this.agentIdentifier)
56
- }
57
- }
42
+ this.start = (featureNames) => {
43
+ try {
44
+ if (featureNames === undefined || (Array.isArray(featureNames) && featureNames.length === 0)) featureNames = nonAutoFeatures
45
+ else if (typeof featureNames === 'string') featureNames = [featureNames]
58
46
 
59
- run (features) {
60
- try {
61
- const featNames = nonAutoFeatures
62
- if (features === undefined) features = featNames
63
- else {
64
- features = Array.isArray(features) && features.length ? features : [features]
65
- if (features.some(f => !featNames.includes(f))) return warn(37, featNames)
66
- if (!features.includes(FEATURE_NAMES.pageViewEvent)) features.push(FEATURE_NAMES.pageViewEvent)
67
- }
68
- } catch (err) {
69
- warn(23, err)
70
- }
47
+ if (featureNames.some(f => !nonAutoFeatures.includes(f))) warn(37, nonAutoFeatures)
48
+ const enabledFeatures = getEnabledFeatures(this.agentIdentifier)
71
49
 
72
- try {
73
- const enabledFeatures = getEnabledFeatures(this.agentIdentifier)
50
+ try {
51
+ // a biproduct of doing this is that the "session manager" is automatically handled through importing this feature
52
+ this.features.page_view_event = new PVE(this)
53
+ } catch (err) {
54
+ warn(24, err)
55
+ }
74
56
 
75
- try {
76
- // a biproduct of doing this is that the "session manager" is automatically handled through importing this feature
77
- this.features.page_view_event = new PVE(this)
57
+ this.features.page_view_event.onAggregateImported.then(() => {
58
+ /* The following features do not import an "instrument" file, meaning they are only hooked up to the API.
59
+ Since the missing instrument-base class handles drain-gating (racing behavior) and PVE handles some setup, these are chained until after PVE has finished initializing
60
+ so as to avoid the race condition of things like session and sharedAggregator not being ready by features that uses them right away. */
61
+ nonAutoFeatures.forEach(f => {
62
+ if (enabledFeatures[f] && featureNames.includes(f)) {
63
+ import(/* webpackChunkName: "lazy-feature-loader" */ '../features/utils/lazy-feature-loader').then(({ lazyFeatureLoader }) => {
64
+ return lazyFeatureLoader(f, 'aggregate')
65
+ }).then(({ Aggregate }) => {
66
+ this.features[f] = new Aggregate(this)
67
+ }).catch(err => warn(25, err))
68
+ }
69
+ })
70
+ })
71
+ return true
78
72
  } catch (err) {
79
- warn(24, err)
73
+ warn(26, err)
74
+ return false
80
75
  }
76
+ }
81
77
 
82
- this.features.page_view_event.onAggregateImported.then(() => {
83
- /* The following features do not import an "instrument" file, meaning they are only hooked up to the API.
84
- Since the missing instrument-base class handles drain-gating (racing behavior) and PVE handles some setup, these are chained until after PVE has finished initializing
85
- so as to avoid the race condition of things like session and sharedAggregator not being ready by features that uses them right away. */
86
- nonAutoFeatures.forEach(f => {
87
- if (enabledFeatures[f] && features.includes(f)) {
88
- import(/* webpackChunkName: "lazy-feature-loader" */ '../features/utils/lazy-feature-loader').then(({ lazyFeatureLoader }) => {
89
- return lazyFeatureLoader(f, 'aggregate')
90
- }).then(({ Aggregate }) => {
91
- this.features[f] = new Aggregate(this)
92
- }).catch(err => warn(25, err))
93
- }
94
- })
95
- })
96
- return true
97
- } catch (err) {
98
- warn(26, err)
99
- return false
78
+ this.start(nonAutoFeatures.filter(featureName => !!this.init[featureName].autoStart))
79
+ }
80
+
81
+ get config () {
82
+ return {
83
+ info: this.info,
84
+ init: this.init,
85
+ loader_config: this.loader_config,
86
+ runtime: this.runtime
100
87
  }
101
88
  }
102
89
  }