newrelic 9.7.0 → 9.7.2

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.
Files changed (37) hide show
  1. package/NEWS.md +42 -18
  2. package/THIRD_PARTY_NOTICES.md +203 -2
  3. package/api.js +155 -103
  4. package/lib/agent.js +29 -82
  5. package/lib/collector/api.js +234 -201
  6. package/lib/config/attribute-filter.js +35 -25
  7. package/lib/config/default.js +45 -19
  8. package/lib/config/index.js +260 -199
  9. package/lib/environment.js +16 -12
  10. package/lib/errors/error-collector.js +124 -55
  11. package/lib/errors/index.js +59 -49
  12. package/lib/instrumentation/@hapi/hapi.js +56 -50
  13. package/lib/instrumentation/@node-redis/client.js +50 -41
  14. package/lib/instrumentation/amqplib.js +116 -151
  15. package/lib/instrumentation/core/{async_hooks.js → async-hooks.js} +26 -11
  16. package/lib/instrumentation/core/globals.js +1 -1
  17. package/lib/instrumentation/core/http-outbound.js +193 -78
  18. package/lib/instrumentation/core/timers.js +106 -59
  19. package/lib/instrumentation/grpc-js/grpc.js +20 -23
  20. package/lib/instrumentation/mongodb/common.js +87 -85
  21. package/lib/instrumentation/redis.js +112 -90
  22. package/lib/instrumentation/undici.js +204 -192
  23. package/lib/instrumentation/{when.js → when/constants.js} +13 -10
  24. package/lib/instrumentation/when/contextualizer.js +168 -0
  25. package/lib/instrumentation/when/index.js +354 -0
  26. package/lib/instrumentation/when/nr-hooks.js +15 -0
  27. package/lib/instrumentations.js +1 -1
  28. package/lib/shim/shim.js +2 -0
  29. package/lib/shim/webframework-shim.js +19 -0
  30. package/lib/symbols.js +1 -0
  31. package/lib/system-info.js +240 -163
  32. package/lib/util/async-each-limit.js +30 -0
  33. package/lib/util/attributes.js +159 -0
  34. package/lib/util/code-level-metrics.js +58 -0
  35. package/lib/util/deep-equal.js +11 -144
  36. package/package.json +5 -4
  37. package/lib/instrumentation/promise.js +0 -572
@@ -10,6 +10,7 @@ const { fsPromises } = require('./util/unwrapped-core')
10
10
  const os = require('os')
11
11
  const logger = require('./logger').child({ component: 'environment' })
12
12
  const stringify = require('json-stringify-safe')
13
+ const asyncEachLimit = require('./util/async-each-limit')
13
14
  const DISPATCHER_VERSION = 'Dispatcher Version'
14
15
 
15
16
  // As of 1.7.0 you can no longer dynamically link v8
@@ -72,7 +73,7 @@ async function listPackages(root, packages = []) {
72
73
 
73
74
  try {
74
75
  const dirs = await fsPromises.readdir(root)
75
- await Promise.all(dirs.map(forEachDir))
76
+ await asyncEachLimit(dirs, forEachDir, 2)
76
77
  _log('Done listing packages in %s', root)
77
78
  } catch (err) {
78
79
  logger.trace(err, 'Could not list packages in %s (probably not an error)', root)
@@ -122,7 +123,7 @@ async function listDependencies(root, children = [], visited = Object.create(nul
122
123
 
123
124
  try {
124
125
  const dirs = await fsPromises.readdir(root)
125
- await Promise.all(dirs.map(forEachEntry))
126
+ await asyncEachLimit(dirs, forEachEntry, 2)
126
127
  _log('Done listing dependencies in %s', root)
127
128
  } catch (err) {
128
129
  logger.trace(err, 'Could not read directories in %s (probably not an error)', root)
@@ -232,7 +233,7 @@ function getGlobalPackages() {
232
233
  * package appears at most once, with all the versions joined into a
233
234
  * comma-delimited list.
234
235
  *
235
- * @param packages
236
+ * @param {Array} packages list of packages to process
236
237
  * @returns {Array.<string[]>} Sorted list of [name, version] pairs.
237
238
  */
238
239
  function flattenVersions(packages) {
@@ -308,15 +309,18 @@ async function getOtherPackages() {
308
309
  }
309
310
  _log('Looking for other packages in %j', paths)
310
311
 
311
- const pathPromises = paths.map((nodePath) => {
312
- if (nodePath[0] !== '/') {
313
- nodePath = path.resolve(process.cwd(), nodePath)
314
- }
315
- _log('Getting other packages from %s', nodePath)
316
- return getPackages(nodePath)
317
- })
312
+ const otherPackages = await asyncEachLimit(
313
+ paths,
314
+ (nodePath) => {
315
+ if (nodePath[0] !== '/') {
316
+ nodePath = path.resolve(process.cwd(), nodePath)
317
+ }
318
+ _log('Getting other packages from %s', nodePath)
319
+ return getPackages(nodePath)
320
+ },
321
+ 2
322
+ )
318
323
 
319
- const otherPackages = await Promise.all(pathPromises)
320
324
  otherPackages.forEach((pkg) => {
321
325
  other.packages.push.apply(other.packages, pkg.packages)
322
326
  other.dependencies.push.apply(other.dependencies, pkg.dependencies)
@@ -470,7 +474,7 @@ async function refresh() {
470
474
  * Refreshes settings and returns the settings object.
471
475
  *
472
476
  * @private
473
- * @returns {Promise}
477
+ * @returns {Promise} the updated/refreshed settings
474
478
  */
475
479
  async function getJSON() {
476
480
  _log('Getting environment JSON')
@@ -5,13 +5,12 @@
5
5
 
6
6
  'use strict'
7
7
 
8
- /* eslint sonarjs/cognitive-complexity: ["error", 25] -- TODO: https://issues.newrelic.com/browse/NEWRELIC-5252 */
9
-
10
8
  const errorsModule = require('./index')
11
9
 
12
10
  const logger = require('../logger').child({ component: 'error_tracer' })
13
11
  const urltils = require('../util/urltils')
14
12
  const Exception = require('../errors').Exception
13
+ const Transaction = require('../transaction')
15
14
  const errorHelper = require('./helper')
16
15
  const createError = errorsModule.createError
17
16
  const createEvent = errorsModule.createEvent
@@ -75,6 +74,7 @@ class ErrorCollector {
75
74
  *
76
75
  * @param {?Transaction} transaction -
77
76
  * @param {Error} exception - The error to be checked.
77
+ * @returns {boolean} whether or not the exception has already been tracked
78
78
  */
79
79
  _haveSeen(transaction, exception) {
80
80
  const txId = transaction ? transaction.id : 'Unknown'
@@ -109,12 +109,78 @@ class ErrorCollector {
109
109
  return false
110
110
  }
111
111
 
112
+ /**
113
+ * Helper method for processing errors that are created with .noticeError()
114
+ *
115
+ * @param {Transaction} transaction the collected exception's transaction
116
+ * @param {number} collectedErrors the number of errors we've successfully .collect()-ed
117
+ * @returns {number} the new number of errors successfully .collect()-ed
118
+ */
119
+ _processUserErrors(transaction, collectedErrors) {
120
+ if (transaction.userErrors.length) {
121
+ for (let i = 0; i < transaction.userErrors.length; i++) {
122
+ const exception = transaction.userErrors[i]
123
+ if (this.collect(transaction, exception)) {
124
+ ++collectedErrors
125
+ }
126
+ }
127
+ }
128
+
129
+ return collectedErrors
130
+ }
131
+
132
+ /**
133
+ * Helper method for processing exceptions on the transaction (transaction.exceptions array)
134
+ *
135
+ * @param {Transaction} transaction the transaction being processed
136
+ * @param {number} collectedErrors the number of errors successfully .collect()-ed
137
+ * @param {number} expectedErrors the number of collected errors that were expected
138
+ * @returns {Array.<number>} the updated [collectedErrors, expectedErrors] numbers post-processing
139
+ */
140
+ _processTransactionExceptions(transaction, collectedErrors, expectedErrors) {
141
+ for (let i = 0; i < transaction.exceptions.length; i++) {
142
+ const exception = transaction.exceptions[i]
143
+ if (this.collect(transaction, exception)) {
144
+ ++collectedErrors
145
+ // if we could collect it, then check if expected
146
+ if (
147
+ urltils.isExpectedError(this.config, transaction.statusCode) ||
148
+ errorHelper.isExpectedException(transaction, exception.error, this.config, urltils)
149
+ ) {
150
+ ++expectedErrors
151
+ }
152
+ }
153
+ }
154
+
155
+ return [collectedErrors, expectedErrors]
156
+ }
157
+
158
+ /**
159
+ * Helper method for processing an inferred error based on Transaction metadata
160
+ *
161
+ * @param {Transaction} transaction the transaction being processed
162
+ * @param {number} collectedErrors the number of errors successfully .collect()-ed
163
+ * @param {number} expectedErrors the number of collected errors that were expected
164
+ * @returns {Array.<number>} the updated [collectedErrors, expectedErrors] numbers post-processing
165
+ */
166
+ _processTransactionErrors(transaction, collectedErrors, expectedErrors) {
167
+ if (this.collect(transaction)) {
168
+ ++collectedErrors
169
+ if (urltils.isExpectedError(this.config, transaction.statusCode)) {
170
+ ++expectedErrors
171
+ }
172
+ }
173
+
174
+ return [collectedErrors, expectedErrors]
175
+ }
176
+
112
177
  /**
113
178
  * Every finished transaction goes through this handler, so do as little as
114
179
  * possible.
115
180
  *
116
- * @param {Transaction} transaction
117
- * @returns {number} The number of unexpected errors
181
+ * TODO: Prob shouldn't do any work if errors fully disabled.
182
+ *
183
+ * @param {Transaction} transaction the completed transaction
118
184
  */
119
185
  onTransactionFinished(transaction) {
120
186
  if (!transaction) {
@@ -124,48 +190,30 @@ class ErrorCollector {
124
190
  return
125
191
  }
126
192
 
127
- // TODO: Prob shouldn't do any work if errors fully disabled.
128
-
129
193
  // collect user errors even if status code is ignored
130
194
  let collectedErrors = 0
131
195
  let expectedErrors = 0
132
196
 
133
197
  // errors from noticeError are currently exempt from
134
198
  // ignore and exclude rules
135
- if (transaction.userErrors.length) {
136
- for (let i = 0; i < transaction.userErrors.length; i++) {
137
- const exception = transaction.userErrors[i]
138
- if (this.collect(transaction, exception)) {
139
- ++collectedErrors
140
- }
141
- }
142
- }
199
+ collectedErrors = this._processUserErrors(transaction, collectedErrors)
143
200
 
144
201
  const isErroredTransaction = urltils.isError(this.config, transaction.statusCode)
145
202
  const isIgnoredErrorStatusCode = urltils.isIgnoredError(this.config, transaction.statusCode)
146
203
 
147
- const isExpectedErrorStatusCode = urltils.isExpectedError(this.config, transaction.statusCode)
148
-
149
204
  // collect other exceptions only if status code is not ignored
150
205
  if (transaction.exceptions.length && !isIgnoredErrorStatusCode) {
151
- for (let i = 0; i < transaction.exceptions.length; i++) {
152
- const exception = transaction.exceptions[i]
153
- if (this.collect(transaction, exception)) {
154
- ++collectedErrors
155
- // if we could collect it, then check if expected
156
- if (
157
- isExpectedErrorStatusCode ||
158
- errorHelper.isExpectedException(transaction, exception.error, this.config, urltils)
159
- ) {
160
- ++expectedErrors
161
- }
162
- }
163
- }
164
- } else if (isErroredTransaction && this.collect(transaction)) {
165
- ++collectedErrors
166
- if (isExpectedErrorStatusCode) {
167
- ++expectedErrors
168
- }
206
+ ;[collectedErrors, expectedErrors] = this._processTransactionExceptions(
207
+ transaction,
208
+ collectedErrors,
209
+ expectedErrors
210
+ )
211
+ } else if (isErroredTransaction) {
212
+ ;[collectedErrors, expectedErrors] = this._processTransactionErrors(
213
+ transaction,
214
+ collectedErrors,
215
+ expectedErrors
216
+ )
169
217
  }
170
218
 
171
219
  const unexpectedErrors = collectedErrors - expectedErrors
@@ -226,9 +274,8 @@ class ErrorCollector {
226
274
  * NOTE: this interface is unofficial and may change in future.
227
275
  *
228
276
  * @param {?Transaction} transaction Transaction associated with the error.
229
- * @param {Exception} exception The Exception to be traced.
230
- * @param error
231
- * @param customAttributes
277
+ * @param {*} error The error passed into `API#noticeError()`
278
+ * @param {object} customAttributes custom attributes to add to the error
232
279
  */
233
280
  addUserError(transaction, error, customAttributes) {
234
281
  if (!error) {
@@ -263,13 +310,38 @@ class ErrorCollector {
263
310
  *
264
311
  * @param {?Transaction} transaction Transaction associated with the error.
265
312
  * @param {?Exception} exception The Exception object to be traced.
266
- * @returns {bool} True if the error was collected.
313
+ * @returns {boolean} True if the error was collected.
267
314
  */
268
- collect(transaction, exception) {
269
- if (!exception) {
270
- exception = new Exception({})
315
+ collect(transaction, exception = new Exception({})) {
316
+ if (!this._isValidException(exception, transaction)) {
317
+ return false
271
318
  }
272
319
 
320
+ const errorTrace = createError(transaction, exception, this.config)
321
+ this._maybeRecordErrorMetrics(errorTrace, transaction)
322
+
323
+ // defaults true in config/index. can be modified server-side
324
+ if (this.config.collect_errors) {
325
+ this.traceAggregator.add(errorTrace)
326
+ }
327
+
328
+ if (this.config.error_collector.capture_events === true) {
329
+ const priority = (transaction && transaction.priority) || Math.random()
330
+ const event = createEvent(transaction, errorTrace, exception.timestamp, this.config)
331
+ this.eventAggregator.add(event, priority)
332
+ }
333
+
334
+ return true
335
+ }
336
+
337
+ /**
338
+ * Helper method for ensuring that a collected exception/transaction combination can be collected
339
+ *
340
+ * @param {object} exception the exception to validate
341
+ * @param {Transaction} transaction the Transaction to validate, if exception is malformed we'll try to fallback to transaction data
342
+ * @returns {boolean} whether or not the exception/transaction combo has everything needed for processing
343
+ */
344
+ _isValidException(exception, transaction) {
273
345
  if (exception.error) {
274
346
  if (this._haveSeen(transaction, exception.error)) {
275
347
  return false
@@ -288,10 +360,20 @@ class ErrorCollector {
288
360
 
289
361
  if (exception.error) {
290
362
  logger.trace(exception.error, 'Got exception to trace:')
363
+ } else {
364
+ logger.trace(transaction, 'Got transaction error to trace:')
291
365
  }
292
366
 
293
- const errorTrace = createError(transaction, exception, this.config)
367
+ return true
368
+ }
294
369
 
370
+ /**
371
+ * Helper method for recording metrics about errors depending on the type of error that happened
372
+ *
373
+ * @param {Array} errorTrace list of error information
374
+ * @param {Transaction} transaction the transaction associated with the trace
375
+ */
376
+ _maybeRecordErrorMetrics(errorTrace, transaction) {
295
377
  const isExpectedError = true === errorTrace[4].intrinsics['error.expected']
296
378
 
297
379
  if (isExpectedError) {
@@ -307,19 +389,6 @@ class ErrorCollector {
307
389
  }
308
390
  }
309
391
  }
310
-
311
- // defaults true in config/index. can be modified server-side
312
- if (this.config.collect_errors) {
313
- this.traceAggregator.add(errorTrace)
314
- }
315
-
316
- if (this.config.error_collector.capture_events === true) {
317
- const priority = (transaction && transaction.priority) || Math.random()
318
- const event = createEvent(transaction, errorTrace, exception.timestamp, this.config)
319
- this.eventAggregator.add(event, priority)
320
- }
321
-
322
- return true
323
392
  }
324
393
 
325
394
  // TODO: ideally, this becomes unnecessary
@@ -5,13 +5,17 @@
5
5
 
6
6
  'use strict'
7
7
 
8
- /* eslint sonarjs/cognitive-complexity: ["error", 22] -- TODO: https://issues.newrelic.com/browse/NEWRELIC-5252 */
9
-
10
8
  const DESTINATIONS = require('../config/attribute-filter').DESTINATIONS
11
- const NAMES = require('../metrics/names')
12
9
  const props = require('../util/properties')
13
10
  const urltils = require('../util/urltils')
14
11
  const errorHelper = require('../errors/helper')
12
+ const {
13
+ maybeAddQueueAttributes,
14
+ maybeAddExternalAttributes,
15
+ maybeAddDatabaseAttributes,
16
+ maybeAddSyntheticAttributes
17
+ } = require('../util/attributes')
18
+ const Transaction = require('../transaction')
15
19
  const ERROR_EXPECTED_PATH = 'error.expected'
16
20
 
17
21
  class Exception {
@@ -48,9 +52,19 @@ class Exception {
48
52
  * handler, which traps actual instances of Error, try to set sensible
49
53
  * defaults for everything.
50
54
  *
55
+ * NOTE: this function returns an array, but also conditionally mutates the array
56
+ * to add a "transaction" property with the transaction id to the array, which works
57
+ * because everything's an object in JS. I'm not entirely sure why we do this, but
58
+ * weird enough to make note of
59
+ *
51
60
  * @param {Transaction} transaction The agent transaction, coming from the instrumentatation
52
61
  * @param {Exception} exception An custom Exception object with the error and other information
53
62
  * @param {object} config The configuration to use when creating the object
63
+ * @returns {Array} an Array of Error information, [0] -> placeholder,
64
+ * [1] -> name extracted from error info,
65
+ * [2] -> extracted error message,
66
+ * [3] -> extracted error type,
67
+ * [4] -> attributes
54
68
  */
55
69
  function createError(transaction, exception, config) {
56
70
  const error = exception.error
@@ -70,60 +84,74 @@ function createError(transaction, exception, config) {
70
84
  if (transaction) {
71
85
  // Copy all of the parameters off of the transaction.
72
86
  params.intrinsics = transaction.getIntrinsicAttributes()
73
- let transactionAgentAttributes = transaction.trace.attributes.get(DESTINATIONS.ERROR_EVENT)
74
- transactionAgentAttributes = transactionAgentAttributes || {}
87
+ const transactionAgentAttributes =
88
+ transaction.trace.attributes.get(DESTINATIONS.ERROR_EVENT) || {}
75
89
 
76
90
  // Merge the agent attributes specific to this error event with the transaction attributes
77
- const agentAttributes = Object.assign(exception.agentAttributes, transactionAgentAttributes)
78
- params.agentAttributes = agentAttributes
91
+ params.agentAttributes = Object.assign(exception.agentAttributes, transactionAgentAttributes)
79
92
 
80
93
  // There should be no attributes to copy in HSM, but check status anyway
81
94
  if (!config.high_security) {
82
- const custom = transaction.trace.custom.get(DESTINATIONS.ERROR_EVENT)
83
- urltils.overwriteParameters(custom, params.userAttributes)
95
+ urltils.overwriteParameters(
96
+ transaction.trace.custom.get(DESTINATIONS.ERROR_EVENT),
97
+ params.userAttributes
98
+ )
84
99
  }
85
100
  }
86
101
 
102
+ maybeAddUserAttributes(params.userAttributes, exception, config)
103
+
104
+ params.stack_trace = maybeAddStackTrace(exception, config)
105
+
106
+ params.intrinsics[ERROR_EXPECTED_PATH] = errorHelper.isExpected(
107
+ type,
108
+ message,
109
+ transaction,
110
+ config,
111
+ urltils
112
+ )
113
+
114
+ return [0, name, message, type, params]
115
+ }
116
+
117
+ function maybeAddUserAttributes(userAttributes, exception, config) {
87
118
  const customAttributes = exception.customAttributes
88
119
  if (!config.high_security && config.api.custom_attributes_enabled && customAttributes) {
89
120
  for (const key in customAttributes) {
90
121
  if (props.hasOwn(customAttributes, key)) {
91
122
  const dest = config.attributeFilter.filterTransaction(DESTINATIONS.ERROR_EVENT, key)
92
123
  if (dest & DESTINATIONS.ERROR_EVENT) {
93
- params.userAttributes[key] = customAttributes[key]
124
+ userAttributes[key] = customAttributes[key]
94
125
  }
95
126
  }
96
127
  }
97
128
  }
129
+ }
130
+
131
+ function maybeAddStackTrace(exception, config) {
132
+ const stack = exception.error?.stack
133
+ let parsedStack
98
134
 
99
- const stack = exception.error && exception.error.stack
100
135
  if (stack) {
101
- params.stack_trace = ('' + stack).split(/[\n\r]/g)
136
+ parsedStack = ('' + stack).split(/[\n\r]/g)
137
+
102
138
  if (config.high_security || config.strip_exception_messages.enabled) {
103
- params.stack_trace[0] = exception.error.name + ': <redacted>'
139
+ parsedStack[0] = exception.error.name + ': <redacted>'
104
140
  }
105
141
  }
106
142
 
107
- params.intrinsics[ERROR_EXPECTED_PATH] = false
108
- if (errorHelper.isExpected(type, message, transaction, config, urltils)) {
109
- params.intrinsics[ERROR_EXPECTED_PATH] = true
110
- }
111
-
112
- const res = [0, name, message, type, params]
113
- if (transaction) {
114
- res.transaction = transaction.id
115
- }
116
- return res
143
+ return parsedStack
117
144
  }
118
145
 
119
146
  /**
120
147
  * Creates a structure for error event that is sent to the collector.
121
148
  * The error parameter is an output of the createError() function for a given exception.
122
149
  *
123
- * @param transaction
124
- * @param error
125
- * @param timestamp
126
- * @param config
150
+ * @param {Transaction} transaction the current transaction
151
+ * @param {Array} error createError() output
152
+ * @param {string} timestamp the timestamp of the error event
153
+ * @param {object} config agent configuration object
154
+ * @returns {Array} an Array of different types of attributes [0] -> intrinsic, [1] -> user/custom, [2] -> agent
127
155
  */
128
156
  function createEvent(transaction, error, timestamp, config) {
129
157
  const message = error[2]
@@ -166,28 +194,10 @@ function _getErrorEventIntrinsicAttrs(transaction, errorClass, message, expected
166
194
  attributes.transactionName = transaction.getFullName()
167
195
  attributes.duration = transaction.timer.getDurationInMillis() / 1000
168
196
 
169
- let metric = transaction.metrics.getMetric(NAMES.QUEUETIME)
170
- if (metric) {
171
- attributes.queueDuration = metric.total
172
- }
173
-
174
- metric = transaction.metrics.getMetric(NAMES.EXTERNAL.ALL)
175
- if (metric) {
176
- attributes.externalDuration = metric.total
177
- attributes.externalCallCount = metric.callCount
178
- }
179
-
180
- metric = transaction.metrics.getMetric(NAMES.DB.ALL)
181
- if (metric) {
182
- attributes.databaseDuration = metric.total
183
- attributes.databaseCallCount = metric.callCount
184
- }
185
-
186
- if (transaction.syntheticsData) {
187
- attributes['nr.syntheticsResourceId'] = transaction.syntheticsData.resourceId
188
- attributes['nr.syntheticsJobId'] = transaction.syntheticsData.jobId
189
- attributes['nr.syntheticsMonitorId'] = transaction.syntheticsData.monitorId
190
- }
197
+ maybeAddQueueAttributes(transaction, attributes)
198
+ maybeAddExternalAttributes(transaction, attributes)
199
+ maybeAddDatabaseAttributes(transaction, attributes)
200
+ maybeAddSyntheticAttributes(transaction, attributes)
191
201
 
192
202
  if (transaction.agent.config.distributed_tracing.enabled) {
193
203
  transaction.addDistributedTraceIntrinsics(attributes)
@@ -5,8 +5,6 @@
5
5
 
6
6
  'use strict'
7
7
 
8
- /* eslint sonarjs/cognitive-complexity: ["error", 68] -- TODO: https://issues.newrelic.com/browse/NEWRELIC-5252 */
9
-
10
8
  const record = require('../../metrics/recorders/generic')
11
9
  // This object defines all the events that we want to wrap extensions
12
10
  // for, as they are the only ones associated with requests.
@@ -66,6 +64,12 @@ function serverPostConstructor(shim) {
66
64
  return
67
65
  }
68
66
 
67
+ wrapProtoDecorate(shim, proto)
68
+ wrapProtoRoute(shim, proto)
69
+ wrapProtoExt(shim, proto)
70
+ }
71
+
72
+ function wrapProtoDecorate(shim, proto) {
69
73
  shim.wrap(proto, 'decorate', function wrapDecorate(shim, original) {
70
74
  return function wrappedDecorate(type) {
71
75
  // server.decorate also accepts 'request', 'toolkit', 'server' types,
@@ -99,7 +103,9 @@ function serverPostConstructor(shim) {
99
103
  return original.apply(this, args)
100
104
  }
101
105
  })
106
+ }
102
107
 
108
+ function wrapProtoRoute(shim, proto) {
103
109
  shim.wrap(proto, 'route', function wrapRoute(shim, original) {
104
110
  return function wrappedRoute() {
105
111
  const args = shim.argsToArray.apply(shim, arguments)
@@ -116,51 +122,53 @@ function serverPostConstructor(shim) {
116
122
  this.realm.modifiers.route.prefix) ||
117
123
  ''
118
124
 
119
- _wrapRoute(shim, args[0])
125
+ _wrapRoute(shim, args[0], prefix)
120
126
 
121
127
  return original.apply(this, args)
128
+ }
129
+ })
130
+ }
122
131
 
123
- function _wrapRoute(shim, route) {
124
- const routePath = prefix + route.path
125
- if (shim.isArray(route)) {
126
- for (let i = 0; i < route.length; ++i) {
127
- _wrapRoute(shim, route[i])
128
- }
129
- return
130
- } else if (route.options) {
131
- // v17 now prefers `options` property...
132
- if (route.options.pre) {
133
- // config objects can also contain multiple OTHER handlers in a `pre` array
134
- route.options.pre = wrapPreHandlers(shim, route.options.pre, routePath)
135
- }
136
- if (route.options.handler) {
137
- _wrapRouteHandler(shim, route.options, routePath)
138
- return
139
- }
140
- } else if (route.config) {
141
- // ... but `config` still works
142
- if (route.config.pre) {
143
- route.config.pre = wrapPreHandlers(shim, route.config.pre, routePath)
144
- }
145
- if (route.config.handler) {
146
- _wrapRouteHandler(shim, route.config, routePath)
147
- return
148
- }
149
- }
150
- _wrapRouteHandler(shim, route, routePath)
151
- }
152
-
153
- function _wrapRouteHandler(shim, container, path) {
154
- if (typeof container.handler !== 'function') {
155
- return
156
- }
157
- shim.wrap(container, 'handler', function wrapHandler(shim, handler) {
158
- return wrapRouteHandler(shim, handler, path)
159
- })
160
- }
132
+ function _wrapRoute(shim, route, prefix) {
133
+ const routePath = prefix + route.path
134
+ if (shim.isArray(route)) {
135
+ for (let i = 0; i < route.length; ++i) {
136
+ _wrapRoute(shim, route[i], prefix)
161
137
  }
138
+ return
139
+ } else if (route.options) {
140
+ // v17 now prefers `options` property...
141
+ if (route.options.pre) {
142
+ // config objects can also contain multiple OTHER handlers in a `pre` array
143
+ route.options.pre = wrapPreHandlers(shim, route.options.pre, routePath)
144
+ }
145
+ if (route.options.handler) {
146
+ _wrapRouteHandler(shim, route.options, routePath)
147
+ return
148
+ }
149
+ } else if (route.config) {
150
+ // ... but `config` still works
151
+ if (route.config.pre) {
152
+ route.config.pre = wrapPreHandlers(shim, route.config.pre, routePath)
153
+ }
154
+ if (route.config.handler) {
155
+ _wrapRouteHandler(shim, route.config, routePath)
156
+ return
157
+ }
158
+ }
159
+ _wrapRouteHandler(shim, route, routePath)
160
+ }
161
+
162
+ function _wrapRouteHandler(shim, container, path) {
163
+ if (typeof container.handler !== 'function') {
164
+ return
165
+ }
166
+ shim.wrap(container, 'handler', function wrapHandler(shim, handler) {
167
+ return wrapRouteHandler(shim, handler, path)
162
168
  })
169
+ }
163
170
 
171
+ function wrapProtoExt(shim, proto) {
164
172
  shim.wrap(proto, 'ext', function wrapExt(shim, original) {
165
173
  return function wrappedExt(event, method) {
166
174
  const args = shim.argsToArray.apply(shim, arguments)
@@ -208,15 +216,13 @@ function wrapRouteHandler(shim, handler, path) {
208
216
  return shim.recordMiddleware(handler, {
209
217
  route: path,
210
218
  req: function getReq(shim, fn, fnName, args) {
211
- const request = args[0]
212
- if (request && request.raw) {
213
- return request.raw.req
214
- }
219
+ const [request] = args
220
+ return request?.raw?.req
215
221
  },
216
222
  promise: true,
217
223
  params: function getParams(shim, fn, fnName, args) {
218
- const req = args[0]
219
- return req && req.params
224
+ const [req] = args
225
+ return req?.params
220
226
  }
221
227
  })
222
228
  }
@@ -230,9 +236,9 @@ function wrapMiddleware(shim, middleware, event) {
230
236
  route: event,
231
237
  type: event === 'onPreResponse' ? shim.ERRORWARE : shim.MIDDLEWARE,
232
238
  promise: true,
233
- req: function getReq(shim, fn, fnName, args) {
234
- const req = args[0]
235
- return req && req.raw && req.raw.req
239
+ req: function getReq(_shim, _fn, _fnName, args) {
240
+ const [req] = args
241
+ return req?.raw?.req
236
242
  }
237
243
  })
238
244
  }