newrelic 8.5.0 → 8.7.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.
@@ -229,6 +229,7 @@ Config.prototype.mergeServerConfig = mergeServerConfig
229
229
  * recognized, unsupported, and unknown parameters.
230
230
  *
231
231
  * @param {object} json The config blob sent by New Relic.
232
+ * @param recursion
232
233
  */
233
234
  Config.prototype.onConnect = function onConnect(json, recursion) {
234
235
  json = json || Object.create(null)
@@ -865,7 +866,7 @@ Config.prototype.checkAsyncHookStatus = function checkAsyncHookStatus() {
865
866
  * I wanted to cache the DisplayHost, but if I attached the variable to the config object,
866
867
  * it sends the extra variable to New Relic, which is not desired.
867
868
  *
868
- * @return {string} display host name
869
+ * @returns {string} display host name
869
870
  */
870
871
  Config.prototype.getDisplayHost = getDisplayHost
871
872
 
@@ -903,7 +904,7 @@ function getDisplayHost() {
903
904
  * I wanted to cache the Hostname, but if I attached the variable to the config object,
904
905
  * it sends the extra variable to New Relic, which is not desired.
905
906
  *
906
- * @return {string} host name
907
+ * @returns {string} host name
907
908
  */
908
909
  Config.prototype.getHostnameSafe = getHostnameSafe
909
910
 
@@ -980,6 +981,7 @@ Config.prototype.applications = function applications() {
980
981
  *
981
982
  * @param {object} external The configuration being loaded.
982
983
  * @param {object} internal Whichever chunk of the config being overridden.
984
+ * @param arbitrary
983
985
  */
984
986
  Config.prototype._fromPassed = function _fromPassed(external, internal, arbitrary) {
985
987
  if (!external) {
@@ -1065,6 +1067,8 @@ Config.prototype._featureFlagsFromEnv = function _featureFlagsFromEnv() {
1065
1067
  * need to set this yourself.
1066
1068
  * @param object data The current level of the configuration object. Should
1067
1069
  * never need to set this yourself.
1070
+ * @param metadata
1071
+ * @param data
1068
1072
  */
1069
1073
  Config.prototype._fromEnvironment = function _fromEnvironment(metadata, data) {
1070
1074
  if (!metadata) {
@@ -1122,7 +1126,6 @@ Config.prototype._fromEnvironment = function _fromEnvironment(metadata, data) {
1122
1126
  * environment variable.
1123
1127
  *
1124
1128
  * @param {*} inputConfig configuration passed to the Config constructor
1125
- *
1126
1129
  * @returns {boolean}
1127
1130
  */
1128
1131
  Config.prototype._loggingManuallySet = function _loggingManuallySet(inputConfig) {
@@ -1137,7 +1140,6 @@ Config.prototype._loggingManuallySet = function _loggingManuallySet(inputConfig)
1137
1140
  * file or enveironment variable
1138
1141
  *
1139
1142
  * @param {*} inputConfig configuration pass to the Config constructor
1140
- *
1141
1143
  * @returns {boolean}
1142
1144
  */
1143
1145
  Config.prototype._nativeMetricsManuallySet = function _nativeMetricsManuallySet(inputConfig) {
@@ -1156,7 +1158,6 @@ Config.prototype._nativeMetricsManuallySet = function _nativeMetricsManuallySet(
1156
1158
  * environment variable.
1157
1159
  *
1158
1160
  * @param {*} inputConfig configuration passed to the Config constructor
1159
- *
1160
1161
  * @returns {boolean}
1161
1162
  */
1162
1163
  Config.prototype._DTManuallySet = function _DTManuallySet(inputConfig) {
@@ -1173,6 +1174,7 @@ Config.prototype._DTManuallySet = function _DTManuallySet(inputConfig) {
1173
1174
  * - disables cross_application_tracer.enabled if set
1174
1175
  * - defaults logging to disabled
1175
1176
  * - verifies data specific to running DT is defined either in config file of env vars
1177
+ *
1176
1178
  * @param {*} inputConfig configuration passed to the Config constructor
1177
1179
  */
1178
1180
  Config.prototype._enforceServerless = function _enforceServerless(inputConfig) {
@@ -1282,7 +1284,7 @@ Config.prototype._canonicalize = function _canonicalize() {
1282
1284
  }
1283
1285
 
1284
1286
  const expectedCodes = this.error_collector && this.error_collector.expected_status_codes
1285
- if (statusCodes) {
1287
+ if (expectedCodes) {
1286
1288
  this.error_collector.expected_status_codes = _parseCodes(expectedCodes)
1287
1289
  }
1288
1290
 
@@ -1410,7 +1412,6 @@ Config.prototype._applyHighSecurity = function _applyHighSecurity() {
1410
1412
  *
1411
1413
  * @param {Agent} agent
1412
1414
  * @param {object} policies
1413
- *
1414
1415
  * @returns {CollectorResponse} The result of the processing, with the known
1415
1416
  * policies as the response payload.
1416
1417
  */
@@ -1540,7 +1541,7 @@ function redactValue(value) {
1540
1541
  * Get a JSONifiable object containing all settings we want to report to the
1541
1542
  * collector and store in the environment_values table.
1542
1543
  *
1543
- * @return Object containing simple key-value pairs of settings
1544
+ * @returns Object containing simple key-value pairs of settings
1544
1545
  */
1545
1546
  Config.prototype.publicSettings = function publicSettings() {
1546
1547
  let settings = Object.create(null)
@@ -1683,6 +1684,8 @@ function initialize(config) {
1683
1684
 
1684
1685
  /**
1685
1686
  * This helper function creates an empty configuration object
1687
+ *
1688
+ * @param config
1686
1689
  */
1687
1690
  function createNewConfigObject(config) {
1688
1691
  config = new Config(Object.create(null))
@@ -0,0 +1,32 @@
1
+ /*
2
+ * Copyright 2021 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ 'use strict'
7
+
8
+ const logger = require('../logger')
9
+
10
+ /**
11
+ * Factory function to create context manager implementations used by the
12
+ * ContextManager class.
13
+ *
14
+ * @param {object} config New Relic config instance.
15
+ * @returns {*} The appropriate underlying context manager implementation based on
16
+ * the current configuration.
17
+ */
18
+ function createContextManager(config) {
19
+ if (config.logging.diagnostics) {
20
+ logger.info('Using LegacyDiagnosticContextManager')
21
+
22
+ const LegacyDiagnosticContextManager = require('./diagnostics/legacy-diagnostic-context-manager')
23
+ return new LegacyDiagnosticContextManager(config)
24
+ }
25
+
26
+ logger.info('Using LegacyContextManager')
27
+
28
+ const LegacyContextManager = require('./legacy-context-manager')
29
+ return new LegacyContextManager(config)
30
+ }
31
+
32
+ module.exports = createContextManager
@@ -0,0 +1,36 @@
1
+ /*
2
+ * Copyright 2021 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ 'use strict'
7
+
8
+ const LegacyContextManager = require('../legacy-context-manager')
9
+
10
+ /**
11
+ * Overrides setContext to add diagnostic logging around setting and removing
12
+ * from context. Currently just supports the segment.probe().
13
+ *
14
+ * Exists in own class to keep default context management as minimal/efficient as possible
15
+ * given we wrap pretty much every functions execution.
16
+ */
17
+ class LegacyDiagnosticContextManager extends LegacyContextManager {
18
+ setContext(newContext) {
19
+ this._logDiagnostic(this._context, 'Removed from context')
20
+
21
+ this._context = newContext
22
+
23
+ this._logDiagnostic(newContext, 'Set in context')
24
+ }
25
+
26
+ _logDiagnostic(context, message) {
27
+ // This is to currently support diagnostic logging of segments which gets attached to
28
+ // transactions with a stack trace. All of this is output at once at the end of a transaction
29
+ // when enabled for clear tracing.
30
+ if (context && context.probe) {
31
+ context.probe(message)
32
+ }
33
+ }
34
+ }
35
+
36
+ module.exports = LegacyDiagnosticContextManager
@@ -0,0 +1,66 @@
1
+ /*
2
+ * Copyright 2021 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ 'use strict'
7
+
8
+ /**
9
+ * Class for managing state in the agent.
10
+ * Keeps track of a single context instance.
11
+ *
12
+ * Given current usage with every instrumented function, the functions in this
13
+ * class should do as little work as possible to avoid unnecessary overhead.
14
+ *
15
+ * @class
16
+ */
17
+ class LegacyContextManager {
18
+ /**
19
+ * @param {object} config New Relic config instance
20
+ */
21
+ constructor(config) {
22
+ this._config = config
23
+ this._context = null
24
+ }
25
+
26
+ /**
27
+ * Get the currently active context.
28
+ *
29
+ * @returns {object} The current active context.
30
+ */
31
+ getContext() {
32
+ return this._context
33
+ }
34
+
35
+ /**
36
+ * Set a new active context. Not bound to function execution.
37
+ *
38
+ * @param {object} newContext The context to set as active.
39
+ */
40
+ setContext(newContext) {
41
+ this._context = newContext
42
+ }
43
+
44
+ /**
45
+ * Run a function with the passed in context as the active context.
46
+ * Restores the previously active context upon completion.
47
+ *
48
+ * @param {object} context The context to set as active during callback execution.
49
+ * @param {Function} callback The function to execute in context.
50
+ * @param {Function} [cbThis] Optional `this` to apply to the callback.
51
+ * @param {Array<*>} [args] Optional arguments object or args array to invoke the callback with.
52
+ * @returns {*} Returns the value returned by the callback function.
53
+ */
54
+ runInContext(context, callback, cbThis, args) {
55
+ const oldContext = this.getContext()
56
+ this.setContext(context)
57
+
58
+ try {
59
+ return callback.apply(cbThis, args)
60
+ } finally {
61
+ this.setContext(oldContext)
62
+ }
63
+ }
64
+ }
65
+
66
+ module.exports = LegacyContextManager
@@ -47,9 +47,11 @@ common.instrumentCollection = function instrumentCollection(shim, Collection) {
47
47
  * Instruments all methods from constants.DB_OPS on
48
48
  * the Db class.
49
49
  *
50
- * @param {Object} params
50
+ * @param {object} params
51
51
  * @param {Shim} params.shim
52
52
  * @param {Db} params.Db
53
+ * @param shim
54
+ * @param Db
53
55
  */
54
56
  common.instrumentDb = function instrumentDb(shim, Db) {
55
57
  if (Db && Db.prototype) {
@@ -62,6 +64,7 @@ common.instrumentDb = function instrumentDb(shim, Db) {
62
64
 
63
65
  /**
64
66
  * Sets up the desc for all instrumented query methods
67
+ *
65
68
  * @param {Shim} shim
66
69
  * @param {string} methodName
67
70
  */
@@ -123,7 +126,7 @@ common.captureAttributesOnStarted = function captureAttributesOnStarted(shim, in
123
126
  * @param {Shim} shim
124
127
  * @param {string} connStr
125
128
  * @param {string} db database name
126
- * @param {Object} client mongo client instance
129
+ * @param {object} client mongo client instance
127
130
  */
128
131
  function setHostPort(shim, connStr, db, client) {
129
132
  const parts = connStr.split(':')
@@ -153,6 +156,9 @@ function setHostPort(shim, connStr, db, client) {
153
156
  * for the query segment. v4 refactored where the toplogy is stored.
154
157
  * You can now get the details via the client obj that's deeply nested
155
158
  * See: https://github.com/mongodb/node-mongodb-native/pull/2594/files#diff-1d214e57ddda9095d296e5700ebce701333bfefcf417e234c584d14091b2f50dR168
159
+ *
160
+ * @param shim
161
+ * @param obj
156
162
  */
157
163
  function getInstanceAttributeParameters(shim, obj) {
158
164
  if (obj.s && obj.s.db && obj.s.topology) {
@@ -197,8 +203,10 @@ function getInstanceAttributeParameters(shim, obj) {
197
203
  }
198
204
 
199
205
  function doCapture(conf, database) {
200
- let host = null
201
- let port = null
206
+ // in older versions of 3.x the host/port
207
+ // lived directly on the topology.s.options
208
+ let host = conf.host
209
+ let port = conf.port
202
210
 
203
211
  // servers is an array but we will always pull the first for consistency
204
212
  if (conf.servers && conf.servers.length) {
@@ -11,28 +11,22 @@ const shimmer = require('../shimmer')
11
11
 
12
12
  /**
13
13
  * @namespace Library.Spec
14
- *
15
14
  * @property {string} name
16
15
  * The name of this promise library.
17
- *
18
16
  * @property {?string} constructor
19
17
  * Optional. The name of the property that is the Promise constructor. Default
20
18
  * is to use the library itself as the Promise constructor.
21
- *
22
19
  * @property {?bool} executor
23
20
  * Optional. If true, the Promise constructor itself will be wrapped for the
24
21
  * executor. If false then `_proto`, `_static`, or `_library` must have an
25
22
  * `executor` field whose value is the name of the executor function. Default
26
23
  * is false.
27
- *
28
24
  * @property {Library.Spec.Mapping} $proto
29
25
  * The mapping for Promise instance method concepts (i.e. `then`). These are
30
26
  * mapped on the Promise class' prototype.
31
- *
32
27
  * @property {Library.Spec.Mapping} $static
33
28
  * The mapping for Promise static method concepts (i.e. `all`, `race`). These
34
29
  * are mapped on the Promise class itself.
35
- *
36
30
  * @property {?Library.Spec.Mapping} $library
37
31
  * The mapping for library-level static method concepts (i.e. `fcall`, `when`).
38
32
  * These are mapped on the library containing the Promise class. NOTE: in most
@@ -42,35 +36,23 @@ const shimmer = require('../shimmer')
42
36
 
43
37
  /**
44
38
  * @namespace Library.Spec.Mapping
45
- *
46
- * @desc
39
+ * @description
47
40
  * A mapping of promise concepts (i.e. `then`) to this library's implementation
48
41
  * name(s) (i.e. `["then", "chain"]`). Each value can by either a single string
49
42
  * or an array of strings if the concept exists under multiple keys. If any
50
43
  * given concept doesn't exist in this library, it is simply skipped.
51
- *
52
- * @property {array} $copy
44
+ * @property {Array} $copy
53
45
  * An array of properties or methods to just directly copy without wrapping.
54
46
  * This field only matters when `Library.Spec.executor` is `true`.
55
- *
56
- * @property {string|array} executor
57
- *
58
- *
59
- * @property {string|array} then
60
- *
61
- *
62
- * @property {string|array} all
63
- *
64
- *
65
- * @property {string|array} race
66
- *
67
- *
68
- * @property {string|array} resolve
47
+ * @property {string | Array} executor
48
+ * @property {string | Array} then
49
+ * @property {string | Array} all
50
+ * @property {string | Array} race
51
+ * @property {string | Array} resolve
69
52
  * Indicates methods to wrap which are resolve factories. This method only
70
53
  * requires wrapping if the library doesn't use an executor internally to
71
54
  * implement it.
72
- *
73
- * @property {string|array} reject
55
+ * @property {string | Array} reject
74
56
  * Indicates methods to wrap which are reject factories. Like `resolve`, this
75
57
  * method only requires wrapping if the library doesn't use an executor
76
58
  * internally to implement it.
@@ -80,11 +62,13 @@ const shimmer = require('../shimmer')
80
62
  * Instruments a promise library.
81
63
  *
82
64
  * @param {Agent} agent - The New Relic APM agent.
83
- * @param {function} library - The promise library.
65
+ * @param {Function} library - The promise library.
84
66
  * @param {?Library.Spec} spec - Spec for this promise library mapping.
85
67
  */
86
68
  /* eslint-disable camelcase */
87
69
  module.exports = function initialize(agent, library, spec) {
70
+ const contextManager = agent._contextManager
71
+
88
72
  if (spec.useFinally == null) {
89
73
  spec.useFinally = true
90
74
  }
@@ -144,7 +128,7 @@ module.exports = function initialize(agent, library, spec) {
144
128
  return Promise(executor) // eslint-disable-line new-cap
145
129
  }
146
130
 
147
- const parent = agent.tracer.segment
131
+ const parent = contextManager.getContext()
148
132
  let promise = null
149
133
  if (
150
134
  !parent ||
@@ -170,15 +154,13 @@ module.exports = function initialize(agent, library, spec) {
170
154
  const segment = _createSegment(segmentName)
171
155
  Contextualizer.link(null, promise, segment, spec.useFinally)
172
156
 
173
- agent.tracer.segment = segment
174
157
  segment.start()
175
158
  try {
176
159
  // Must run after promise is defined so that `__NR_wrapper` can be set.
177
- executor.apply(context.self, context.args)
160
+ contextManager.runInContext(segment, executor, context.self, context.args)
178
161
  } catch (e) {
179
162
  context.args[1](e)
180
163
  } finally {
181
- agent.tracer.segment = parent
182
164
  segment.touch()
183
165
  }
184
166
  }
@@ -259,8 +241,7 @@ module.exports = function initialize(agent, library, spec) {
259
241
  * execution.
260
242
  *
261
243
  * @param {object} context - The object to export the execution context with.
262
- *
263
- * @return {function} A function which, when executed, will add its context
244
+ * @returns {Function} A function which, when executed, will add its context
264
245
  * and arguments to the `context` parameter.
265
246
  */
266
247
  function wrapExecutorContext(context) {
@@ -285,7 +266,9 @@ module.exports = function initialize(agent, library, spec) {
285
266
  /**
286
267
  * Creates a wrapper for `Promise#then` that extends the transaction context.
287
268
  *
288
- * @return {function} A wrapped version of `Promise#then`.
269
+ * @param then
270
+ * @param name
271
+ * @returns {Function} A wrapped version of `Promise#then`.
289
272
  */
290
273
  function wrapThen(then, name) {
291
274
  return _wrapThen(then, name, true)
@@ -294,7 +277,9 @@ module.exports = function initialize(agent, library, spec) {
294
277
  /**
295
278
  * Creates a wrapper for `Promise#catch` that extends the transaction context.
296
279
  *
297
- * @return {function} A wrapped version of `Promise#catch`.
280
+ * @param cach
281
+ * @param name
282
+ * @returns {Function} A wrapped version of `Promise#catch`.
298
283
  */
299
284
  function wrapCatch(cach, name) {
300
285
  return _wrapThen(cach, name, false)
@@ -303,14 +288,13 @@ module.exports = function initialize(agent, library, spec) {
303
288
  /**
304
289
  * Creates a wrapper for promise chain extending methods.
305
290
  *
306
- * @param {function} then
291
+ * @param {Function} then
307
292
  * The function we are to wrap as a chain extender.
308
- *
293
+ * @param name
309
294
  * @param {bool} useAllParams
310
295
  * When true, all parameters which are functions will be wrapped. Otherwise,
311
296
  * only the last parameter will be wrapped.
312
- *
313
- * @return {function} A wrapped version of the function.
297
+ * @returns {Function} A wrapped version of the function.
314
298
  */
315
299
  function _wrapThen(then, name, useAllParams) {
316
300
  // Don't wrap non-functions.
@@ -377,6 +361,9 @@ module.exports = function initialize(agent, library, spec) {
377
361
 
378
362
  /**
379
363
  * Creates a wrapper around the static `Promise` factory method.
364
+ *
365
+ * @param cast
366
+ * @param name
380
367
  */
381
368
  function wrapCast(cast, name) {
382
369
  if (typeof cast !== 'function' || cast.name === '__NR_wrappedCast') {
@@ -437,8 +424,8 @@ module.exports = function initialize(agent, library, spec) {
437
424
  *
438
425
  * @param {object} obj - The source of the methods to wrap.
439
426
  * @param {string} name - The name of this source.
440
- * @param {string|array} methods - The names of the methods to wrap.
441
- * @param {function} wrapper - The function which wraps the methods.
427
+ * @param {string | Array} methods - The names of the methods to wrap.
428
+ * @param {Function} wrapper - The function which wraps the methods.
442
429
  */
443
430
  function _safeWrap(obj, name, methods, wrapper) {
444
431
  if (methods && methods.length) {
@@ -252,7 +252,11 @@ const INFINITE_TRACING = {
252
252
  }
253
253
 
254
254
  const FEATURES = {
255
- CERTIFICATES: SUPPORTABILITY.FEATURES + '/Certificates'
255
+ CERTIFICATES: SUPPORTABILITY.FEATURES + '/Certificates',
256
+ INSTRUMENTATION: {
257
+ ON_RESOLVED: SUPPORTABILITY.FEATURES + '/Instrumentation/OnResolved',
258
+ ON_REQUIRE: SUPPORTABILITY.FEATURES + '/Instrumentation/OnRequire'
259
+ }
256
260
  }
257
261
 
258
262
  module.exports = {
@@ -17,6 +17,12 @@ function parseProcCPUInfo(data) {
17
17
  packages: null
18
18
  }
19
19
 
20
+ // In some rare cases the OS may be locked down so that you cannot retrieve this info.
21
+ if (!data) {
22
+ logger.debug('No CPU data to parse, returning empty stats.')
23
+ return processorStats
24
+ }
25
+
20
26
  // separate the processors
21
27
  let splitData = data.split('\n').map(function formatAttribute(attr) {
22
28
  return attr.split(':').map(function eliminateExtraWhitespace(s) {
@@ -34,7 +40,7 @@ function parseProcCPUInfo(data) {
34
40
 
35
41
  splitData = collapseMultilineValues(splitData)
36
42
 
37
- const processors = seperateProcessors(splitData)
43
+ const processors = separateProcessors(splitData)
38
44
 
39
45
  processorStats = countProcessorStats(processors)
40
46
  if (!processorStats.cores) {
@@ -73,7 +79,7 @@ function collapseMultilineValues(li) {
73
79
 
74
80
  // walk through the processed list of key, value pairs and populate
75
81
  // objects till you find a collision
76
- function seperateProcessors(processorData) {
82
+ function separateProcessors(processorData) {
77
83
  const processors = []
78
84
  let processor = Object.create(null)
79
85
  for (let i = 0; i < processorData.length; ++i) {
@@ -10,6 +10,12 @@ const logger = require('./logger.js').child({ component: 'proc-meminfo' })
10
10
  module.exports = parseProcMeminfo
11
11
 
12
12
  function parseProcMeminfo(data) {
13
+ // In some rare cases the OS may be locked down so that you cannot retrieve this info.
14
+ if (!data) {
15
+ logger.debug('No memory data to parse.')
16
+ return null
17
+ }
18
+
13
19
  const memTotal = parseInt(data.replace(/MemTotal:\s*(\d*)\skB/, '$1'), 10)
14
20
 
15
21
  if (memTotal) {
@@ -82,8 +82,14 @@ class AwsLambda {
82
82
  // NOTE: This may be converted to holding onto a single ender function if only
83
83
  // one invocation is executing at a time.
84
84
  shim.wrap(process, 'emit', function wrapEmit(shim, emit) {
85
- return function wrappedEmit(ev) {
86
- if (ev === 'beforeExit') {
85
+ return function wrappedEmit(ev, error) {
86
+ // need to add error as uncaughtException to be used
87
+ // later to add to transaction errors
88
+ if (ev === 'unhandledRejection') {
89
+ uncaughtException = error
90
+ }
91
+
92
+ if (['beforeExit', 'unhandledRejection'].includes(ev)) {
87
93
  transactionEnders.forEach((ender) => {
88
94
  ender()
89
95
  })