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.
@@ -16,15 +16,13 @@ const TRANSACTION_TYPES_SET = Transaction.TYPES_SET
16
16
  /**
17
17
  * Constructs a transaction managing shim.
18
18
  *
19
- * @constructor
20
- * @extends Shim
19
+ * @class
20
+ * @augments Shim
21
21
  * @classdesc
22
22
  * A helper class for working with transactions.
23
- *
24
23
  * @param {Agent} agent - The agent the shim will use.
25
24
  * @param {string} moduleName - The name of the module being instrumented.
26
25
  * @param {string} resolvedName - The full path to the loaded module.
27
- *
28
26
  * @see Shim
29
27
  * @see WebFrameworkShim
30
28
  */
@@ -75,22 +73,18 @@ TransactionShim.prototype.insertCATRequestHeaders = insertCATRequestHeaders
75
73
 
76
74
  /**
77
75
  * @interface TransactionSpec
78
- *
79
76
  * @description
80
77
  * Describes the type of transaction to be created by the function being
81
78
  * wrapped by {@link Shim#bindCreateTransaction}.
82
- *
83
79
  * @property {string} type
84
80
  * The type of transaction to create. Must be one of the values from
85
81
  * {@link Shim#TRANSACTION_TYPES}.
86
- *
87
82
  * @property {bool} [nest=false]
88
83
  * Indicates if the transaction being created is allowed to be nested within
89
84
  * another transaction of the same type. If `false`, the default, the transaction
90
85
  * will only be created if there is no existing transaction, or the current
91
86
  * transaction is of a different type. If `true`, the transaction will be
92
87
  * created regardless of the current transaction's type.
93
- *
94
88
  * @see Shim#bindCreateTransaction
95
89
  * @see Shim#TRANSACTION_TYPES
96
90
  */
@@ -105,18 +99,14 @@ TransactionShim.prototype.insertCATRequestHeaders = insertCATRequestHeaders
105
99
  * - `bindCreateTransaction(func, spec)`
106
100
  *
107
101
  * @memberof TransactionShim.prototype
108
- *
109
- * @param {Object|Function} nodule
102
+ * @param {object | Function} nodule
110
103
  * The source for the property to wrap, or a single function to wrap.
111
- *
112
104
  * @param {string} [property]
113
105
  * The property to wrap. If omitted, the `nodule` parameter is assumed to be
114
106
  * the function to wrap.
115
- *
116
107
  * @param {TransactionSpec} spec
117
108
  * The spec for creating the transaction.
118
- *
119
- * @return {Object|Function} The first parameter to this function, after
109
+ * @returns {object | Function} The first parameter to this function, after
120
110
  * wrapping it or its property.
121
111
  */
122
112
  function bindCreateTransaction(nodule, property, spec) {
@@ -164,7 +154,6 @@ function bindCreateTransaction(nodule, property, spec) {
164
154
  * back off when resolution exits the item.
165
155
  *
166
156
  * @memberof TransactionShim.prototype
167
- *
168
157
  * @param {string} pathSegment - The path segment to add to the naming stack.
169
158
  */
170
159
  function pushTransactionName(pathSegment) {
@@ -183,7 +172,6 @@ function pushTransactionName(pathSegment) {
183
172
  * this function, but we do not live in an ideal world.
184
173
  *
185
174
  * @memberof TransactionShim.prototype
186
- *
187
175
  * @param {string} [pathSegment]
188
176
  * Optional. Path segment to pop the stack repeatedly until a segment matching
189
177
  * `pathSegment` is removed.
@@ -203,7 +191,6 @@ function popTransactionName(pathSegment) {
203
191
  * Either this _or_ the naming stack should be used. Do not use them together.
204
192
  *
205
193
  * @memberof TransactionShim.prototype
206
- *
207
194
  * @param {string} name - The name to use for the transaction.
208
195
  */
209
196
  function setTransactionName(name) {
@@ -222,14 +209,11 @@ function setTransactionName(name) {
222
209
  *
223
210
  * This will check for either header naming style, and both request and reply
224
211
  * CAT headers.
225
- *
226
212
  * @param {object} headers
227
213
  * The request/response headers object to look in.
228
- *
229
214
  * @param {TraceSegment} [segment=null]
230
215
  * The trace segment to associate the header data with. If no segment is
231
216
  * provided then the currently active segment is used.
232
- *
233
217
  * @param {string} [transportType='Unknown']
234
218
  * The transport type that brought the headers. Usually `HTTP` or `HTTPS`.
235
219
  */
@@ -282,10 +266,8 @@ function handleCATHeaders(headers, segment, transportType) {
282
266
  * - `insertCATRequestHeaders(headers [, useAlternateHeaderNames])`
283
267
  *
284
268
  * @memberof TransactionShim.prototype
285
- *
286
269
  * @param {object} headers
287
270
  * The outbound request headers object to inject our CAT headers into.
288
- *
289
271
  * @param {bool} [useAlternateHeaderNames=false]
290
272
  * Indicates if HTTP-style headers should be used or alternate style. Some
291
273
  * transport protocols are more strict on the characters allowed in headers
@@ -327,10 +309,8 @@ function insertCATRequestHeaders(headers, useAlternateHeaderNames) {
327
309
  * - `insertCATReplyHeaders(headers [, useAlternateHeaderNames])`
328
310
  *
329
311
  * @memberof TransactionShim.prototype
330
- *
331
312
  * @param {object} headers
332
313
  * The outbound response headers object to inject our CAT headers into.
333
- *
334
314
  * @param {bool} [useAlternateHeaderNames=false]
335
315
  * Indicates if HTTP-style headers should be used or alternate style. Some
336
316
  * transport protocols are more strict on the characters allowed in headers
@@ -388,20 +368,15 @@ function insertCATReplyHeader(headers, useAlternateHeaderNames) {
388
368
  * `spec.type` is not the same as the current transaction's type.
389
369
  *
390
370
  * @private
391
- *
392
371
  * @param {Shim} shim
393
372
  * The shim used for the binding.
394
- *
395
- * @param {function} fn
373
+ * @param {Function} fn
396
374
  * The function link with the transaction.
397
- *
398
375
  * @param {string} name
399
376
  * The name of the wrapped function.
400
- *
401
377
  * @param {TransactionSpec} spec
402
378
  * The spec for the transaction to create.
403
- *
404
- * @return {function} A function which wraps `fn` and creates potentially nested
379
+ * @returns {Function} A function which wraps `fn` and creates potentially nested
405
380
  * transactions linked to its execution.
406
381
  */
407
382
  function _makeNestedTransWrapper(shim, fn, name, spec) {
@@ -412,7 +387,7 @@ function _makeNestedTransWrapper(shim, fn, name, spec) {
412
387
 
413
388
  // Reuse existing transactions only if the type matches.
414
389
  let transaction = shim.tracer.getTransaction()
415
- let segment = shim.tracer.segment
390
+ let segment = shim.getSegment()
416
391
 
417
392
  // Only create a new transaction if we either do not have a current
418
393
  // transaction _or_ the current transaction is not of the type we want.
@@ -433,20 +408,15 @@ function _makeNestedTransWrapper(shim, fn, name, spec) {
433
408
  * A transaction will only be created if there is not a currently active one.
434
409
  *
435
410
  * @private
436
- *
437
411
  * @param {Shim} shim
438
412
  * The shim used for the binding.
439
- *
440
- * @param {function} fn
413
+ * @param {Function} fn
441
414
  * The function link with the transaction.
442
- *
443
415
  * @param {string} name
444
416
  * The name of the wrapped function.
445
- *
446
417
  * @param {TransactionSpec} spec
447
418
  * The spec for the transaction to create.
448
- *
449
- * @return {function} A function which wraps `fn` and potentially creates a new
419
+ * @returns {Function} A function which wraps `fn` and potentially creates a new
450
420
  * transaction linked to the function's execution.
451
421
  */
452
422
  function _makeTransWrapper(shim, fn, name, spec) {
package/lib/shimmer.js CHANGED
@@ -6,12 +6,15 @@
6
6
  'use strict'
7
7
 
8
8
  const path = require('path')
9
+ const semver = require('semver')
9
10
  const fs = require('./util/unwrapped-core').fs
10
11
  const logger = require('./logger').child({ component: 'shimmer' })
11
12
  const INSTRUMENTATIONS = require('./instrumentations')()
12
13
  const properties = require('./util/properties')
13
14
  const shims = require('./shim')
14
15
 
16
+ const NAMES = require('./metrics/names')
17
+
15
18
  const MODULE_TYPE = shims.constants.MODULE_TYPE
16
19
 
17
20
  const CORE_INSTRUMENTATION = {
@@ -90,9 +93,8 @@ const shimmer = (module.exports = {
90
93
  /**
91
94
  * Detects if the given function has already been wrapped.
92
95
  *
93
- * @param {function} fn - The function to look for a wrapper on.
94
- *
95
- * @return {bool} True if `fn` exists and has an attached original, else false.
96
+ * @param {Function} fn - The function to look for a wrapper on.
97
+ * @returns {bool} True if `fn` exists and has an attached original, else false.
96
98
  */
97
99
  isWrapped: function isWrapped(fn) {
98
100
  return !!(fn && fn.__NR_original)
@@ -111,7 +113,7 @@ const shimmer = (module.exports = {
111
113
  * helpful than you'd think.
112
114
  * @param {string} methods One or more names of methods or functions to extract
113
115
  * and wrap.
114
- * @param {function} wrapper A generator that, when called, returns a
116
+ * @param {Function} wrapper A generator that, when called, returns a
115
117
  * wrapped version of the original function.
116
118
  */
117
119
  wrapMethod: function wrapMethod(nodule, noduleName, methods, wrapper) {
@@ -177,8 +179,7 @@ const shimmer = (module.exports = {
177
179
  * @param {object} noduleName Human-readable module / Class name. More
178
180
  * helpful than you'd think.
179
181
  * @param {string} property The property to replace with the accessor.
180
- * @param {function} options Optional getter and setter to use for the accessor.
181
- *
182
+ * @param {Function} options Optional getter and setter to use for the accessor.
182
183
  * @returns {object} The original value of the property.
183
184
  */
184
185
  wrapDeprecated: function wrapDeprecated(nodule, noduleName, property, options) {
@@ -275,6 +276,8 @@ const shimmer = (module.exports = {
275
276
  /**
276
277
  * Patch the module.load function so that we see modules loading and
277
278
  * have an opportunity to patch them with instrumentation.
279
+ *
280
+ * @param agent
278
281
  */
279
282
  patchModule: function patchModule(agent) {
280
283
  logger.trace('Wrapping module loader.')
@@ -286,7 +289,14 @@ const shimmer = (module.exports = {
286
289
  // This is triggered by the load call, so record the path that has been seen so
287
290
  // we can examine it after the load call has returned.
288
291
  const resolvedFilepath = resolve.apply(this, arguments)
289
- filepathMap[file] = resolvedFilepath
292
+
293
+ // Only fire the first time we see a specific module resolved
294
+ if (filepathMap[file] !== resolvedFilepath) {
295
+ filepathMap[file] = resolvedFilepath
296
+
297
+ _onResolveFileName(agent, file, resolvedFilepath)
298
+ }
299
+
290
300
  return resolvedFilepath
291
301
  }
292
302
  })
@@ -306,6 +316,7 @@ const shimmer = (module.exports = {
306
316
  * their parent has already been loaded/cached by Node.
307
317
  * Provides a fall-back for unexpected cases that may occur.
308
318
  * Also provides flexibility for testing now that node 11+ caches these.
319
+ *
309
320
  * @param {*} request
310
321
  * @param {*} parent
311
322
  * @param {*} isMain
@@ -398,6 +409,10 @@ const shimmer = (module.exports = {
398
409
  },
399
410
 
400
411
  registerInstrumentation: function registerInstrumentation(opts) {
412
+ if (!hasValidRegisterOptions(opts)) {
413
+ return
414
+ }
415
+
401
416
  shimmer.registeredInstrumentations[opts.moduleName] = opts
402
417
  },
403
418
 
@@ -419,6 +434,9 @@ const shimmer = (module.exports = {
419
434
  * re-wrap them.
420
435
  *
421
436
  * Use this to re-apply any applicable instrumentation.
437
+ *
438
+ * @param agent
439
+ * @param modulePath
422
440
  */
423
441
  reinstrument: function reinstrument(agent, modulePath) {
424
442
  return _postLoad(agent, require(modulePath), modulePath)
@@ -428,6 +446,8 @@ const shimmer = (module.exports = {
428
446
  * Given a NodeJS module name, return the name/identifier of our
429
447
  * instrumentation. These two things are usually, but not always,
430
448
  * the same.
449
+ *
450
+ * @param moduleName
431
451
  */
432
452
  getInstrumentationNameFromModuleName(moduleName) {
433
453
  let instrumentation
@@ -445,6 +465,14 @@ const shimmer = (module.exports = {
445
465
  instrumentation = moduleName
446
466
  }
447
467
  return instrumentation
468
+ },
469
+
470
+ instrumentPostLoad(agent, module, moduleName, resolvedName) {
471
+ const result = _postLoad(agent, module, moduleName, resolvedName)
472
+ // This is to not break the public API
473
+ // previously it would just call instrumentation
474
+ // and not check the result
475
+ return !!result.__NR_instrumented
448
476
  }
449
477
  })
450
478
 
@@ -467,8 +495,13 @@ function applyDebugState(shim, nodule) {
467
495
  * All instrumentation files must export the same interface: a single
468
496
  * initialization function that takes the agent and the module to be
469
497
  * instrumented.
498
+ *
499
+ * @param agent
500
+ * @param nodule
501
+ * @param moduleName
502
+ * @param resolvedName
470
503
  */
471
- function instrument(agent, nodule, moduleName, resolvedName) {
504
+ function instrumentPostLoad(agent, nodule, moduleName, resolvedName) {
472
505
  const instrumentation = shimmer.registeredInstrumentations[moduleName]
473
506
  if (
474
507
  properties.hasOwn(nodule, '__NR_instrumented') ||
@@ -484,6 +517,7 @@ function instrument(agent, nodule, moduleName, resolvedName) {
484
517
  const shim = shims.createShimFromType(instrumentation.type, agent, moduleName, resolvedName)
485
518
 
486
519
  applyDebugState(shim, nodule)
520
+ trackInstrumentationUsage(agent, shim, moduleName, NAMES.FEATURES.INSTRUMENTATION.ON_REQUIRE)
487
521
 
488
522
  try {
489
523
  if (instrumentation.onRequire(shim, nodule, moduleName) !== false) {
@@ -536,11 +570,137 @@ function _firstPartyInstrumentation(agent, fileName, shim, nodule, moduleName) {
536
570
  function _postLoad(agent, nodule, name, resolvedName) {
537
571
  const instrumentation = shimmer.getInstrumentationNameFromModuleName(name)
538
572
 
573
+ const registeredInstrumentation = shimmer.registeredInstrumentations[instrumentation]
574
+ const hasPostLoadInstrumentation =
575
+ registeredInstrumentation && registeredInstrumentation.onRequire
576
+
539
577
  // Check if this is a known instrumentation and then run it.
540
- if (shimmer.registeredInstrumentations[instrumentation]) {
541
- logger.trace('Instrumenting %s.', name)
542
- return instrument(agent, nodule, instrumentation, resolvedName)
578
+ if (hasPostLoadInstrumentation) {
579
+ logger.trace('Instrumenting %s with onRequire (module loaded) hook.', name)
580
+ return instrumentPostLoad(agent, nodule, instrumentation, resolvedName)
543
581
  }
544
582
 
545
583
  return nodule
546
584
  }
585
+
586
+ function _onResolveFileName(agent, requiredNameOrPath, resolvedFilepath) {
587
+ const instrumentation = shimmer.getInstrumentationNameFromModuleName(requiredNameOrPath)
588
+
589
+ const registeredInstrumentation = shimmer.registeredInstrumentations[instrumentation]
590
+ const hasResolvedFileInstrumentation =
591
+ registeredInstrumentation && registeredInstrumentation.onResolved
592
+
593
+ // Check if this is a known instrumentation and then run it.
594
+ if (hasResolvedFileInstrumentation) {
595
+ logger.trace('Instrumenting %s with onResolved hook.', requiredNameOrPath)
596
+ _instrumentOnResolved(agent, instrumentation, resolvedFilepath)
597
+ }
598
+ }
599
+
600
+ /**
601
+ * Invokes the onResolved handler with a shim instance.
602
+ *
603
+ * Given Node.js caches resolvedFilePaths in versions we support and we cache as well
604
+ * for the cases we force resolution, we should not run into the case of multiple
605
+ * invocations for the same module. As such, this function does not defend against multiple runs.
606
+ *
607
+ * @param agent
608
+ * @param moduleName
609
+ * @param resolvedFilepath
610
+ */
611
+ function _instrumentOnResolved(agent, moduleName, resolvedFilepath) {
612
+ const instrumentation = shimmer.registeredInstrumentations[moduleName]
613
+
614
+ const shim = shims.createShimFromType(instrumentation.type, agent, moduleName, resolvedFilepath)
615
+
616
+ trackInstrumentationUsage(agent, shim, moduleName, NAMES.FEATURES.INSTRUMENTATION.ON_RESOLVED)
617
+
618
+ try {
619
+ instrumentation.onResolved(shim, moduleName, resolvedFilepath)
620
+ } catch (instrumentationError) {
621
+ if (instrumentation.onError) {
622
+ try {
623
+ instrumentation.onError(instrumentationError)
624
+ } catch (error) {
625
+ logger.warn(
626
+ error,
627
+ instrumentationError,
628
+ 'OnResolved instrumentation for %s failed, then the onError handler threw an error',
629
+ moduleName
630
+ )
631
+ }
632
+ } else {
633
+ logger.warn(
634
+ instrumentationError,
635
+ 'OnResolved instrumentation for %s failed. Please report this to the ' +
636
+ 'maintainers of the custom instrumentation.',
637
+ moduleName
638
+ )
639
+ }
640
+ }
641
+ }
642
+
643
+ function hasValidRegisterOptions(opts) {
644
+ if (!opts) {
645
+ logger.warn('Instrumentation registration failed, no options provided')
646
+ return false
647
+ }
648
+
649
+ if (!opts.moduleName) {
650
+ logger.warn(`Instrumentation registration failed, 'moduleName' not provided`)
651
+ return false
652
+ }
653
+
654
+ if (!opts.onRequire && !opts.onResolved) {
655
+ logger.warn(
656
+ 'Instrumentation registration for %s failed, no require hooks provided.',
657
+ opts.moduleName
658
+ )
659
+
660
+ return false
661
+ }
662
+
663
+ return true
664
+ }
665
+
666
+ /**
667
+ * Adds metrics to indicate instrumentation was used for a particular module and
668
+ * what major version the module was at, if possible.
669
+ *
670
+ * @param {*} agent The agent instance.
671
+ * @param {*} shim The instance of the shim used to instrument the module.
672
+ * @param {string} moduleName The name of the required module.
673
+ * @param {string} metricPrefix Support metric prefix to prepend to the metrics. Will indicate onRequire or onResolved
674
+ * from NAMES.FEATURES.INSTRUMENTATION.
675
+ */
676
+ function trackInstrumentationUsage(agent, shim, moduleName, metricPrefix) {
677
+ try {
678
+ const version = tryGetVersion(shim)
679
+ const instrumentationMetricName = `${metricPrefix}/${moduleName}`
680
+
681
+ agent.metrics.getOrCreateMetric(instrumentationMetricName).incrementCallCount()
682
+
683
+ if (version) {
684
+ const majorVersion = semver.major(version)
685
+ const versionMetricName = `${instrumentationMetricName}/Version/${majorVersion}`
686
+
687
+ agent.metrics.getOrCreateMetric(versionMetricName).incrementCallCount()
688
+ }
689
+ } catch (error) {
690
+ logger.debug('Unable to track instrumentation usage for: ', moduleName, error)
691
+ }
692
+ }
693
+
694
+ function tryGetVersion(shim) {
695
+ // Global module (i.e. domain) or finding root failed
696
+ if (shim._moduleRoot === '.') {
697
+ return
698
+ }
699
+
700
+ const packageInfo = shim.require('./package.json')
701
+ if (!packageInfo) {
702
+ return
703
+ }
704
+
705
+ return packageInfo.version
706
+ }
@@ -16,13 +16,13 @@ const SEGMENT = '__NR_segment'
16
16
 
17
17
  module.exports = Tracer
18
18
 
19
- function Tracer(agent) {
19
+ function Tracer(agent, contextManager) {
20
20
  if (!agent) {
21
21
  throw new Error('Must be initialized with an agent.')
22
22
  }
23
23
 
24
24
  this.agent = agent
25
- this._segment = null
25
+ this._contextManager = contextManager
26
26
  }
27
27
 
28
28
  Tracer.prototype.getTransaction = getTransaction
@@ -45,35 +45,28 @@ Tracer.prototype.wrapFunctionFirst = wrapFunctionFirst
45
45
  Tracer.prototype.wrapSyncFunction = wrapSyncFunction
46
46
  Tracer.prototype.wrapCallback = wrapCallback
47
47
 
48
- Object.defineProperty(Tracer.prototype, 'segment', {
49
- get: function segmentGetter() {
50
- return this._segment
51
- },
52
- set: function segmentSetter(segment) {
53
- this._segment && this._segment.probe('Segment removed from tracer')
54
- segment && segment.probe('Set tracer.segment')
55
- return (this._segment = segment)
56
- }
57
- })
58
-
59
48
  function getTransaction() {
60
- if (this.segment && this.segment.transaction && this.segment.transaction.isActive()) {
61
- return this.segment.transaction
49
+ const currentSegment = this._contextManager.getContext()
50
+ if (currentSegment && currentSegment.transaction && currentSegment.transaction.isActive()) {
51
+ return currentSegment.transaction
62
52
  }
63
53
 
64
54
  return null
65
55
  }
66
56
 
57
+ // TODO: Remove/replace external uses to tracer.getSegment()
67
58
  function getSegment() {
68
- return this.segment
59
+ return this._contextManager.getContext()
69
60
  }
70
61
 
62
+ // TODO: Remove/replace external uses to tracer.getSpanContext()
71
63
  function getSpanContext() {
72
- return this.segment && this.segment.getSpanContext()
64
+ const currentSegment = this.getSegment()
65
+ return currentSegment && currentSegment.getSpanContext()
73
66
  }
74
67
 
75
68
  function createSegment(name, recorder, _parent) {
76
- const parent = _parent || this.segment
69
+ const parent = _parent || this.getSegment()
77
70
  if (!parent || !parent.transaction.isActive()) {
78
71
  logger.trace(
79
72
  {
@@ -111,7 +104,7 @@ function transactionProxy(handler) {
111
104
  }
112
105
 
113
106
  // don't nest transactions, reuse existing ones
114
- const segment = tracer.segment
107
+ const segment = tracer.getSegment()
115
108
  if (segment) {
116
109
  if (segment.transaction.traceStacks) {
117
110
  segment.probe('!!! Nested transaction creation !!!')
@@ -143,9 +136,9 @@ function transactionProxy(handler) {
143
136
  * if there is an in play segment and uses that as the root instead of
144
137
  * transaction.trace.root.
145
138
  *
146
- * @param {Function} handler - Generator to be proxied.
147
- *
148
- * @return {Function} Proxy.
139
+ * @param {string} type - Type of transaction to create. 'web' or 'bg'.
140
+ * @param {Function} handler - Generator to proxy.
141
+ * @returns {Function} Proxy.
149
142
  */
150
143
  function transactionNestProxy(type, handler) {
151
144
  if (handler === undefined && typeof type === 'function') {
@@ -165,7 +158,7 @@ function transactionNestProxy(type, handler) {
165
158
 
166
159
  // don't nest transactions, reuse existing ones
167
160
  let transaction = tracer.getTransaction()
168
- let segment = tracer.segment
161
+ let segment = tracer.getSegment()
169
162
 
170
163
  let createNew = false
171
164
 
@@ -192,7 +185,7 @@ function bindFunction(handler, segment, full) {
192
185
  return handler
193
186
  }
194
187
 
195
- return _makeWrapped(this, handler, segment || this.segment, !!full)
188
+ return _makeWrapped(this, handler, segment || this.getSegment(), !!full)
196
189
  }
197
190
  function _makeWrapped(tracer, handler, active, full) {
198
191
  wrapped[ORIGINAL] = getOriginal(handler)
@@ -201,18 +194,19 @@ function _makeWrapped(tracer, handler, active, full) {
201
194
  return wrapped
202
195
 
203
196
  function wrapped() {
204
- const prev = tracer.segment
205
- tracer.segment = active
197
+ const prev = tracer.getSegment()
198
+
206
199
  if (active && full) {
207
200
  active.start()
208
201
  }
202
+
209
203
  try {
210
- return handler.apply(this, arguments)
204
+ return tracer._contextManager.runInContext(active, handler, this, arguments)
211
205
  } catch (err) {
212
206
  logger.trace(err, 'Error from wrapped function:')
213
207
 
214
208
  if (prev === null && process.domain != null) {
215
- process.domain.__NR_transactionSegment = tracer.segment
209
+ process.domain.__NR_transactionSegment = tracer.getSegment()
216
210
  }
217
211
 
218
212
  throw err // Re-throwing application error, this is not an agent error.
@@ -220,7 +214,6 @@ function _makeWrapped(tracer, handler, active, full) {
220
214
  if (active && full) {
221
215
  active.touch()
222
216
  }
223
- tracer.segment = prev
224
217
  }
225
218
  }
226
219
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "newrelic",
3
- "version": "8.5.0",
3
+ "version": "8.7.0",
4
4
  "author": "New Relic Node.js agent team <nodejs@newrelic.com>",
5
5
  "license": "Apache-2.0",
6
6
  "contributors": [
@@ -148,9 +148,11 @@
148
148
  "update-cross-agent-tests": "./bin/update-cats.sh",
149
149
  "versioned-tests": "./bin/run-versioned-tests.sh",
150
150
  "update-changelog-version": "node ./bin/update-changelog-version",
151
+ "checkout-external-versioned": "node ./test/versioned-external/checkout-external-tests.js",
151
152
  "versioned": "npm run versioned:npm7",
152
- "versioned:npm6": "npm run prepare-test && time ./bin/run-versioned-tests.sh",
153
- "versioned:npm7": "npm run prepare-test && NPM7=1 time ./bin/run-versioned-tests.sh",
153
+ "versioned:major": "npm run checkout-external-versioned && npm run prepare-test && VERSIONED_MODE=--major NPM7=1 time ./bin/run-versioned-tests.sh",
154
+ "versioned:npm6": "npm run checkout-external-versioned && npm run prepare-test && time ./bin/run-versioned-tests.sh",
155
+ "versioned:npm7": "npm run checkout-external-versioned && npm run prepare-test && NPM7=1 time ./bin/run-versioned-tests.sh",
154
156
  "prepare": "husky install"
155
157
  },
156
158
  "bin": {
@@ -177,8 +179,9 @@
177
179
  "@newrelic/eslint-config": "^0.0.3",
178
180
  "@newrelic/newrelic-oss-cli": "^0.1.2",
179
181
  "@newrelic/proxy": "^2.0.0",
180
- "@newrelic/test-utilities": "^6.0.0",
182
+ "@newrelic/test-utilities": "^6.1.1",
181
183
  "@octokit/rest": "^18.0.15",
184
+ "@slack/bolt": "^3.7.0",
182
185
  "ajv": "^6.12.6",
183
186
  "architect": "*",
184
187
  "benchmark": "^2.1.4",