newrelic 8.5.2 → 8.6.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/NEWS.md CHANGED
@@ -1,3 +1,15 @@
1
+ ### v8.6.0 (2021-11-17)
2
+
3
+ * Added `onResolved` instrumentation hook to apply instrumentation prior to module load.
4
+
5
+ This hook fires after the module filepath has been resolved just prior to the module being loaded by the CommonJS module loader.
6
+
7
+ * Fixed issue where `recordConsume` was not binding consumer if it was a promise
8
+
9
+ * Pinned mongo versioned tests to `<4.2.0` until we can address https://github.com/newrelic/node-newrelic/issues/982
10
+
11
+ * Introduced a context management API to be used in place of manually calling tracer.segment get/set.
12
+
1
13
  ### v8.5.2 (2021-11-09)
2
14
 
3
15
  * Fixed issue where unhandled promise rejections were not getting logged as errors in a lambda execution
package/api.js CHANGED
@@ -55,7 +55,8 @@ const CUSTOM_EVENT_TYPE_REGEX = /^[a-zA-Z0-9:_ ]+$/
55
55
  * You do not need to directly instantiate this class, as an instance of this is
56
56
  * the return from `require('newrelic')`.
57
57
  *
58
- * @constructor
58
+ * @param agent
59
+ * @class
59
60
  */
60
61
  function API(agent) {
61
62
  this.agent = agent
@@ -139,6 +140,7 @@ API.prototype.getTransaction = function getTransaction() {
139
140
  * utilization.full_hostname. If utilization.full_hostname is null or empty,
140
141
  * this will be the hostname specified in the connect request as host.
141
142
  *
143
+ * @param omitSupportability
142
144
  * @returns {LinkingMetadata} The linking object with the data above
143
145
  */
144
146
  API.prototype.getLinkingMetadata = function getLinkingMetadata(omitSupportability) {
@@ -186,7 +188,6 @@ API.prototype.getLinkingMetadata = function getLinkingMetadata(omitSupportabilit
186
188
  *
187
189
  * @param {string} name The string you would like to report to New Relic
188
190
  * as the dispatcher.
189
- *
190
191
  * @param {string} [version] The dispatcher version you would like to
191
192
  * report to New Relic
192
193
  */
@@ -414,7 +415,6 @@ API.prototype.addCustomSpanAttribute = function addCustomSpanAttribute(key, valu
414
415
  *
415
416
  * @param {Error} error
416
417
  * The error to be traced.
417
- *
418
418
  * @param {object} [customAttributes]
419
419
  * Optional. Any custom attributes to be displayed in the New Relic UI.
420
420
  */
@@ -526,7 +526,7 @@ API.prototype.addIgnoringRule = function addIgnoringRule(pattern) {
526
526
  * Do *not* reuse the headers between users, or even between requests.
527
527
  *
528
528
  * @param {string} [options.nonce] - Nonce to inject into `<script>` header.
529
- *
529
+ * @param options
530
530
  * @returns {string} The `<script>` header to be injected.
531
531
  */
532
532
  API.prototype.getBrowserTimingHeader = function getBrowserTimingHeader(options) {
@@ -545,7 +545,7 @@ API.prototype.getBrowserTimingHeader = function getBrowserTimingHeader(options)
545
545
  *
546
546
  * @param {number} num - Error code from `RUM_ISSUES`.
547
547
  * @param {bool} [quite=false] - Be quiet about this failure.
548
- *
548
+ * @param quiet
549
549
  * @see RUM_ISSUES
550
550
  */
551
551
  function _gracefail(num, quiet) {
@@ -687,9 +687,9 @@ API.prototype.getBrowserTimingHeader = function getBrowserTimingHeader(options)
687
687
 
688
688
  /**
689
689
  * @callback startSegmentCallback
690
- * @param {function} cb
690
+ * @param {Function} cb
691
691
  * The function to time with the created segment.
692
- * @return {Promise=} Returns a promise if cb returns a promise.
692
+ * @returns {Promise=} Returns a promise if cb returns a promise.
693
693
  */
694
694
 
695
695
  /**
@@ -701,23 +701,18 @@ API.prototype.getBrowserTimingHeader = function getBrowserTimingHeader(options)
701
701
  * // The returned promise here will signify the end of the segment.
702
702
  * return myAsyncTask().then(myNextTask)
703
703
  * })
704
- *
705
704
  * @param {string} name
706
705
  * The name to give the new segment. This will also be the name of the metric.
707
- *
708
706
  * @param {bool} record
709
707
  * Indicates if the segment should be recorded as a metric. Metrics will show
710
708
  * up on the transaction breakdown table and server breakdown graph. Segments
711
709
  * just show up in transaction traces.
712
- *
713
710
  * @param {startSegmentCallback} handler
714
711
  * The function to track as a segment.
715
- *
716
- * @param {function} [callback]
712
+ * @param {Function} [callback]
717
713
  * An optional callback for the handler. This will indicate the end of the
718
714
  * timing if provided.
719
- *
720
- * @return {*} Returns the result of calling `handler`.
715
+ * @returns {*} Returns the result of calling `handler`.
721
716
  */
722
717
  API.prototype.startSegment = function startSegment(name, record, handler, callback) {
723
718
  this.agent.metrics
@@ -775,11 +770,9 @@ API.prototype.startSegment = function startSegment(name, record, handler, callba
775
770
  * transaction.end()
776
771
  * }, 100)
777
772
  * })
778
- *
779
773
  * @param {string} url
780
774
  * The URL of the transaction. It is used to name and group related transactions in APM,
781
775
  * so it should be a generic name and not iclude any variable parameters.
782
- *
783
776
  * @param {Function} handle
784
777
  * Function that represents the transaction work.
785
778
  */
@@ -862,20 +855,16 @@ API.prototype.startBackgroundTransaction = startBackgroundTransaction
862
855
  * transaction.end()
863
856
  * }, 100)
864
857
  * })
865
- *
866
858
  * @param {string} name
867
859
  * The name of the transaction. It is used to name and group related
868
860
  * transactions in APM, so it should be a generic name and not iclude any
869
861
  * variable parameters.
870
- *
871
862
  * @param {string} [group]
872
863
  * Optional, used for grouping background transactions in APM. For more
873
864
  * information see:
874
865
  * https://docs.newrelic.com/docs/apm/applications-menu/monitoring/transactions-page#txn-type-dropdown
875
- *
876
866
  * @param {Function} handle
877
867
  * Function that represents the background work.
878
- *
879
868
  * @memberOf API#
880
869
  */
881
870
  function startBackgroundTransaction(name, group, handle) {
@@ -972,9 +961,9 @@ API.prototype.endTransaction = function endTransaction() {
972
961
  * Record a custom metric, usually associated with a particular duration.
973
962
  * The `name` must be a string following standard metric naming rules. The `value` will
974
963
  * usually be a number, but it can also be an object.
975
- * * When `value` is a numeric value, it should represent the magnitude of a measurement
964
+ * When `value` is a numeric value, it should represent the magnitude of a measurement
976
965
  * associated with an event; for example, the duration for a particular method call.
977
- * * When `value` is an object, it must contain count, total, min, max, and sumOfSquares
966
+ * When `value` is an object, it must contain count, total, min, max, and sumOfSquares
978
967
  * keys, all with number values. This form is useful to aggregate metrics on your own
979
968
  * and report them periodically; for example, from a setInterval. These values will
980
969
  * be aggregated with any previously collected values for the same metric. The names
@@ -1151,18 +1140,15 @@ API.prototype.recordCustomEvent = function recordCustomEvent(eventType, attribut
1151
1140
  * - `newrelic.instrument(moduleName, onRequire [,onError])`
1152
1141
  * - `newrelic.instrument(options)`
1153
1142
  *
1154
- * @param {object} options
1155
- * The options for this custom instrumentation.
1156
- *
1157
- * @param {string} options.moduleName
1158
- * The module name given to require to load the module
1159
- *
1160
- * @param {function} options.onRequire
1161
- * The function to call when the module is required
1162
- *
1163
- * @param {function} [options.onError]
1164
- * If provided, should `onRequire` throw an error, the error will be passed to
1143
+ * @param {object} options The options for this custom instrumentation.
1144
+ * @param {string} options.moduleName The module name given to require to load the module
1145
+ * @param {Function} options.onResolved The function to call prior to module load after the filepath has been resolved
1146
+ * @param {Function} options.onRequire The function to call when the module has been loaded
1147
+ * @param {Function} [options.onError] If provided, should `onRequire` throw an error, the error will be passed to
1165
1148
  * this function.
1149
+ * @param moduleName
1150
+ * @param onRequire
1151
+ * @param onError
1166
1152
  */
1167
1153
  API.prototype.instrument = function instrument(moduleName, onRequire, onError) {
1168
1154
  const metric = this.agent.metrics.getOrCreateMetric(NAMES.SUPPORTABILITY.API + '/instrument')
@@ -1187,18 +1173,15 @@ API.prototype.instrument = function instrument(moduleName, onRequire, onError) {
1187
1173
  * - `newrelic.instrumentConglomerate(moduleName, onRequire [, onError])`
1188
1174
  * - `newrelic.isntrumentConglomerate(options)`
1189
1175
  *
1190
- * @param {object} options
1191
- * The options for this custom instrumentation.
1192
- *
1193
- * @param {string} options.moduleName
1194
- * The module name given to require to load the module
1195
- *
1196
- * @param {function} options.onRequire
1197
- * The function to call when the module is required
1198
- *
1199
- * @param {function} [options.onError]
1200
- * If provided, should `onRequire` throw an error, the error will be passed to
1176
+ * @param {object} options The options for this custom instrumentation.
1177
+ * @param {string} options.moduleName The module name given to require to load the module
1178
+ * @param {Function} options.onResolved The function to call prior to module load after the filepath has been resolved
1179
+ * @param {Function} options.onRequire The function to call when the module has been loaded
1180
+ * @param {Function} [options.onError] If provided, should `onRequire` throw an error, the error will be passed to
1201
1181
  * this function.
1182
+ * @param moduleName
1183
+ * @param onRequire
1184
+ * @param onError
1202
1185
  */
1203
1186
  API.prototype.instrumentConglomerate = function instrumentConglomerate(
1204
1187
  moduleName,
@@ -1224,18 +1207,15 @@ API.prototype.instrumentConglomerate = function instrumentConglomerate(
1224
1207
  * - `newrelic.instrumentDatastore(moduleName, onRequire [,onError])`
1225
1208
  * - `newrelic.instrumentDatastore(options)`
1226
1209
  *
1227
- * @param {object} options
1228
- * The options for this custom instrumentation.
1229
- *
1230
- * @param {string} options.moduleName
1231
- * The module name given to require to load the module
1232
- *
1233
- * @param {function} options.onRequire
1234
- * The function to call when the module is required
1235
- *
1236
- * @param {function} [options.onError]
1237
- * If provided, should `onRequire` throw an error, the error will be passed to
1210
+ * @param {object} options The options for this custom instrumentation.
1211
+ * @param {string} options.moduleName The module name given to require to load the module
1212
+ * @param {Function} options.onResolved The function to call prior to module load after the filepath has been resolved
1213
+ * @param {Function} options.onRequire The function to call when the module has been loaded
1214
+ * @param {Function} [options.onError] If provided, should `onRequire` throw an error, the error will be passed to
1238
1215
  * this function.
1216
+ * @param moduleName
1217
+ * @param onRequire
1218
+ * @param onError
1239
1219
  */
1240
1220
  API.prototype.instrumentDatastore = function instrumentDatastore(moduleName, onRequire, onError) {
1241
1221
  const metric = this.agent.metrics.getOrCreateMetric(
@@ -1256,77 +1236,21 @@ API.prototype.instrumentDatastore = function instrumentDatastore(moduleName, onR
1256
1236
  shimmer.registerInstrumentation(opts)
1257
1237
  }
1258
1238
 
1259
- /**
1260
- * Applies an instrumentation to an already loaded module.
1261
- *
1262
- * // oh no, express was loaded before newrelic
1263
- * const express = require('express')
1264
- * const newrelic = require('newrelic')
1265
- *
1266
- * // phew, we can use instrumentLoadedModule to make
1267
- * // sure express is still instrumented
1268
- * newrelic.instrumentLoadedModule('express', express)
1269
- *
1270
- * @param {string} moduleName
1271
- * The module's name/identifier. Will be normalized
1272
- * into an instrumentation key.
1273
- *
1274
- * @param {object} module
1275
- * The actual module object or function we're instrumenting
1276
- */
1277
- API.prototype.instrumentLoadedModule = function instrumentLoadedModule(moduleName, module) {
1278
- const metric = this.agent.metrics.getOrCreateMetric(
1279
- NAMES.SUPPORTABILITY.API + '/instrumentLoadedModule'
1280
- )
1281
- metric.incrementCallCount()
1282
- try {
1283
- const instrumentationName = shimmer.getInstrumentationNameFromModuleName(moduleName)
1284
- if (!shimmer.registeredInstrumentations[instrumentationName]) {
1285
- logger.warn("No instrumentation registered for '%s'.", instrumentationName)
1286
- return false
1287
- }
1288
-
1289
- const instrumentation = shimmer.registeredInstrumentations[instrumentationName]
1290
- if (!instrumentation.onRequire) {
1291
- logger.warn("No onRequire function registered for '%s'.", instrumentationName)
1292
- return false
1293
- }
1294
-
1295
- const resolvedName = require.resolve(moduleName)
1296
-
1297
- const shim = shims.createShimFromType(
1298
- instrumentation.type,
1299
- this.agent,
1300
- moduleName,
1301
- resolvedName
1302
- )
1303
-
1304
- instrumentation.onRequire(shim, module, moduleName)
1305
-
1306
- return true
1307
- } catch (error) {
1308
- logger.error('instrumentLoadedModule encountered an error, module not instrumentend: %s', error)
1309
- }
1310
- }
1311
-
1312
1239
  /**
1313
1240
  * Registers an instrumentation function.
1314
1241
  *
1315
1242
  * - `newrelic.instrumentWebframework(moduleName, onRequire [,onError])`
1316
1243
  * - `newrelic.instrumentWebframework(options)`
1317
1244
  *
1318
- * @param {object} options
1319
- * The options for this custom instrumentation.
1320
- *
1321
- * @param {string} options.moduleName
1322
- * The module name given to require to load the module
1323
- *
1324
- * @param {function} options.onRequire
1325
- * The function to call when the module is required
1326
- *
1327
- * @param {function} [options.onError]
1328
- * If provided, should `onRequire` throw an error, the error will be passed to
1245
+ * @param {object} options The options for this custom instrumentation.
1246
+ * @param {string} options.moduleName The module name given to require to load the module
1247
+ * @param {Function} options.onResolved The function to call prior to module load after the filepath has been resolved
1248
+ * @param {Function} options.onRequire The function to call when the module has been loaded
1249
+ * @param {Function} [options.onError] If provided, should `onRequire` throw an error, the error will be passed to
1329
1250
  * this function.
1251
+ * @param moduleName
1252
+ * @param onRequire
1253
+ * @param onError
1330
1254
  */
1331
1255
  API.prototype.instrumentWebframework = function instrumentWebframework(
1332
1256
  moduleName,
@@ -1357,18 +1281,15 @@ API.prototype.instrumentWebframework = function instrumentWebframework(
1357
1281
  * - `newrelic.instrumentMessages(moduleName, onRequire [,onError])`
1358
1282
  * - `newrelic.instrumentMessages(options)`
1359
1283
  *
1360
- * @param {object} options
1361
- * The options for this custom instrumentation.
1362
- *
1363
- * @param {string} options.moduleName
1364
- * The module name given to require to load the module
1365
- *
1366
- * @param {function} options.onRequire
1367
- * The function to call when the module is required
1368
- *
1369
- * @param {function} [options.onError]
1370
- * If provided, should `onRequire` throw an error, the error will be passed to
1284
+ * @param {object} options The options for this custom instrumentation.
1285
+ * @param {string} options.moduleName The module name given to require to load the module
1286
+ * @param {Function} options.onResolved The function to call prior to module load after the filepath has been resolved
1287
+ * @param {Function} options.onRequire The function to call when the module has been loaded
1288
+ * @param {Function} [options.onError] If provided, should `onRequire` throw an error, the error will be passed to
1371
1289
  * this function.
1290
+ * @param moduleName
1291
+ * @param onRequire
1292
+ * @param onError
1372
1293
  */
1373
1294
  API.prototype.instrumentMessages = function instrumentMessages(moduleName, onRequire, onError) {
1374
1295
  const metric = this.agent.metrics.getOrCreateMetric(
@@ -1389,6 +1310,58 @@ API.prototype.instrumentMessages = function instrumentMessages(moduleName, onReq
1389
1310
  shimmer.registerInstrumentation(opts)
1390
1311
  }
1391
1312
 
1313
+ /**
1314
+ * Applies an instrumentation to an already loaded module.
1315
+ *
1316
+ * // oh no, express was loaded before newrelic
1317
+ * const express = require('express')
1318
+ * const newrelic = require('newrelic')
1319
+ *
1320
+ * // phew, we can use instrumentLoadedModule to make
1321
+ * // sure express is still instrumented
1322
+ * newrelic.instrumentLoadedModule('express', express)
1323
+ *
1324
+ * @param {string} moduleName
1325
+ * The module's name/identifier. Will be normalized
1326
+ * into an instrumentation key.
1327
+ * @param {object} module
1328
+ * The actual module object or function we're instrumenting
1329
+ */
1330
+ API.prototype.instrumentLoadedModule = function instrumentLoadedModule(moduleName, module) {
1331
+ const metric = this.agent.metrics.getOrCreateMetric(
1332
+ NAMES.SUPPORTABILITY.API + '/instrumentLoadedModule'
1333
+ )
1334
+ metric.incrementCallCount()
1335
+ try {
1336
+ const instrumentationName = shimmer.getInstrumentationNameFromModuleName(moduleName)
1337
+ if (!shimmer.registeredInstrumentations[instrumentationName]) {
1338
+ logger.warn("No instrumentation registered for '%s'.", instrumentationName)
1339
+ return false
1340
+ }
1341
+
1342
+ const instrumentation = shimmer.registeredInstrumentations[instrumentationName]
1343
+ if (!instrumentation.onRequire) {
1344
+ logger.warn("No onRequire function registered for '%s'.", instrumentationName)
1345
+ return false
1346
+ }
1347
+
1348
+ const resolvedName = require.resolve(moduleName)
1349
+
1350
+ const shim = shims.createShimFromType(
1351
+ instrumentation.type,
1352
+ this.agent,
1353
+ moduleName,
1354
+ resolvedName
1355
+ )
1356
+
1357
+ instrumentation.onRequire(shim, module, moduleName)
1358
+
1359
+ return true
1360
+ } catch (error) {
1361
+ logger.error('instrumentLoadedModule encountered an error, module not instrumented: %s', error)
1362
+ }
1363
+ }
1364
+
1392
1365
  /**
1393
1366
  * Returns the current trace and span id.
1394
1367
  *
@@ -1424,19 +1397,16 @@ API.prototype.getTraceMetadata = function getTraceMetadata() {
1424
1397
  *
1425
1398
  * @param {object} [options]
1426
1399
  * Object with shut down options.
1427
- *
1428
1400
  * @param {boolean} [options.collectPendingData=false]
1429
1401
  * If true, the agent will send any pending data to the collector before
1430
1402
  * shutting down.
1431
- *
1432
1403
  * @param {number} [options.timeout=0]
1433
1404
  * Time in milliseconds to wait before shutting down.
1434
- *
1435
1405
  * @param {boolean} [options.waitForIdle=false]
1436
1406
  * If true, the agent will not shut down until there are no active transactions.
1437
- *
1438
- * @param {function} [callback]
1407
+ * @param {Function} [callback]
1439
1408
  * Callback function that runs when agent stops.
1409
+ * @param cb
1440
1410
  */
1441
1411
  API.prototype.shutdown = function shutdown(options, cb) {
1442
1412
  this.agent.metrics.getOrCreateMetric(`${NAMES.SUPPORTABILITY.API}/shutdown`).incrementCallCount()
@@ -1458,6 +1428,11 @@ API.prototype.shutdown = function shutdown(options, cb) {
1458
1428
  _doShutdown(this, options, callback)
1459
1429
  }
1460
1430
 
1431
+ /**
1432
+ * @param api
1433
+ * @param options
1434
+ * @param callback
1435
+ */
1461
1436
  function _doShutdown(api, options, callback) {
1462
1437
  const agent = api.agent
1463
1438
 
@@ -1473,6 +1448,9 @@ function _doShutdown(api, options, callback) {
1473
1448
  return
1474
1449
  }
1475
1450
 
1451
+ /**
1452
+ * @param error
1453
+ */
1476
1454
  function afterHarvest(error) {
1477
1455
  if (error) {
1478
1456
  logger.error(error, 'An error occurred while running last harvest before shutdown.')
@@ -1506,6 +1484,10 @@ function _doShutdown(api, options, callback) {
1506
1484
  }
1507
1485
  }
1508
1486
 
1487
+ /**
1488
+ * @param object
1489
+ * @param maxLength
1490
+ */
1509
1491
  function _checkKeyLength(object, maxLength) {
1510
1492
  const keys = Object.keys(object)
1511
1493
  let badKey = false
@@ -1534,6 +1516,10 @@ API.prototype.setLambdaHandler = function setLambdaHandler(handler) {
1534
1516
  return this.awsLambda.patchLambdaHandler(handler)
1535
1517
  }
1536
1518
 
1519
+ /**
1520
+ * @param attributes
1521
+ * @param name
1522
+ */
1537
1523
  function _filterAttributes(attributes, name) {
1538
1524
  const filteredAttributes = Object.create(null)
1539
1525
  Object.keys(attributes).forEach((attributeKey) => {
package/lib/agent.js CHANGED
@@ -29,6 +29,7 @@ const TxSegmentNormalizer = require('./metrics/normalizer/tx_segment')
29
29
  const uninstrumented = require('./uninstrumented')
30
30
  const util = require('util')
31
31
  const createSpanEventAggregator = require('./spans/create-span-event-aggregator')
32
+ const createContextManager = require('./context-manager/create-context-manager')
32
33
 
33
34
  // Map of valid states to whether or not data collection is valid
34
35
  const STATES = {
@@ -53,6 +54,8 @@ const DEFAULT_HARVEST_INTERVAL_MS = 60000
53
54
  * This constructor can throw if, for some reason, the configuration isn't
54
55
  * available. Don't try to recover here, because without configuration the
55
56
  * agent can't be brought up to a useful state.
57
+ *
58
+ * @param config
56
59
  */
57
60
  function Agent(config) {
58
61
  EventEmitter.call(this)
@@ -136,8 +139,9 @@ function Agent(config) {
136
139
 
137
140
  this.errors = new ErrorCollector(config, errorTraceAggregator, errorEventAggregator, this.metrics)
138
141
 
142
+ this._contextManager = createContextManager(this.config)
139
143
  // Transaction tracing.
140
- this.tracer = new Tracer(this)
144
+ this.tracer = new Tracer(this, this._contextManager)
141
145
  this.traces = new TransactionTraceAggregator(
142
146
  {
143
147
  periodMs: DEFAULT_HARVEST_INTERVAL_MS,
@@ -185,7 +189,6 @@ util.inherits(Agent, EventEmitter)
185
189
  * the configuration.
186
190
  *
187
191
  * @config {boolean} agent_enabled Whether to start up the agent.
188
- *
189
192
  * @param {Function} callback Continuation and error handler.
190
193
  */
191
194
  Agent.prototype.start = function start(callback) {
@@ -248,6 +251,7 @@ Agent.prototype.start = function start(callback) {
248
251
 
249
252
  /**
250
253
  * Forces all aggregators to send the data collected.
254
+ *
251
255
  * @param {Function} callback The callback to invoke when all data types have been sent.
252
256
  */
253
257
  Agent.prototype.forceHarvestAll = function forceHarvestAll(callback) {
@@ -416,6 +420,9 @@ Agent.prototype.startAggregators = function startAggregators() {
416
420
  /**
417
421
  * Completes any final setup upon full connection to New Relic
418
422
  * servers and sets the agent state to 'started'.
423
+ *
424
+ * @param shouldImmediatelyHarvest
425
+ * @param callback
419
426
  */
420
427
  Agent.prototype.onConnect = function onConnect(shouldImmediatelyHarvest, callback) {
421
428
  this._reconfigureAggregators(this.config)
@@ -485,6 +492,8 @@ Agent.prototype._serverlessModeStart = function _serverlessModeStart(callback) {
485
492
  * FIXME: make it possible to dispose of the agent, as well as do a
486
493
  * "hard" restart. This requires working with shimmer to strip the
487
494
  * current instrumentation and patch to the module loader.
495
+ *
496
+ * @param callback
488
497
  */
489
498
  Agent.prototype.stop = function stop(callback) {
490
499
  if (!callback) {
@@ -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