newrelic 11.23.2 → 12.0.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.
Files changed (38) hide show
  1. package/NEWS.md +39 -0
  2. package/README.md +31 -0
  3. package/THIRD_PARTY_NOTICES.md +262 -31
  4. package/index.js +1 -10
  5. package/lib/context-manager/create-context-manager.js +0 -11
  6. package/lib/feature_flags.js +1 -2
  7. package/lib/instrumentation/amqplib/amqplib.js +4 -243
  8. package/lib/instrumentation/amqplib/channel-model.js +129 -0
  9. package/lib/instrumentation/amqplib/channel.js +70 -0
  10. package/lib/instrumentation/amqplib/utils.js +141 -0
  11. package/lib/instrumentation/core/globals.js +0 -5
  12. package/lib/instrumentation/core/timers.js +1 -72
  13. package/lib/instrumentation/kafkajs/consumer.js +64 -48
  14. package/lib/instrumentation/kafkajs/index.js +13 -13
  15. package/lib/instrumentation/kafkajs/producer.js +68 -52
  16. package/lib/instrumentation/kafkajs/record-linking-metrics.js +17 -0
  17. package/lib/instrumentation/kafkajs/record-method-metric.js +21 -0
  18. package/lib/instrumentation/mongodb.js +9 -10
  19. package/lib/instrumentation/nextjs/next-server.js +178 -0
  20. package/lib/instrumentation/nextjs/nr-hooks.js +22 -0
  21. package/lib/instrumentation/nextjs/utils.js +71 -0
  22. package/lib/instrumentation/redis.js +13 -59
  23. package/lib/instrumentations.js +1 -1
  24. package/lib/metrics/names.js +1 -2
  25. package/lib/shim/message-shim/consume.js +9 -4
  26. package/lib/shim/message-shim/index.js +7 -14
  27. package/lib/shim/message-shim/subscribe-consume.js +25 -6
  28. package/lib/shim/specs/params/queue-message.js +2 -0
  29. package/lib/spans/span-event.js +17 -11
  30. package/lib/spans/streaming-span-event.js +15 -13
  31. package/lib/symbols.js +1 -0
  32. package/load-externals.js +15 -0
  33. package/package.json +10 -10
  34. package/lib/context-manager/legacy-context-manager.js +0 -66
  35. package/lib/instrumentation/core/async-hooks.js +0 -132
  36. package/lib/instrumentation/director.js +0 -64
  37. package/lib/instrumentation/mongodb/v2-mongo.js +0 -118
  38. package/lib/instrumentation/mongodb/v3-mongo.js +0 -85
@@ -6,38 +6,17 @@
6
6
  'use strict'
7
7
 
8
8
  const {
9
- MessageSpec,
10
- MessageSubscribeSpec,
11
9
  OperationSpec,
12
- RecorderSpec,
13
-
14
- params: { QueueMessageParameters, DatastoreParameters }
10
+ params: { DatastoreParameters }
15
11
  } = require('../../shim/specs')
16
12
  const url = require('url')
13
+ const wrapModel = require('./channel-model')
14
+ const { setCallback } = require('./utils')
15
+ const wrapChannel = require('./channel')
17
16
 
18
17
  module.exports.instrumentPromiseAPI = instrumentChannelAPI
19
18
  module.exports.instrumentCallbackAPI = instrumentCallbackAPI
20
19
 
21
- const CHANNEL_METHODS = [
22
- 'close',
23
- 'open',
24
- 'assertQueue',
25
- 'checkQueue',
26
- 'deleteQueue',
27
- 'bindQueue',
28
- 'unbindQueue',
29
- 'assertExchange',
30
- 'checkExchange',
31
- 'deleteExchange',
32
- 'bindExchange',
33
- 'unbindExchange',
34
- 'cancel',
35
- 'prefetch',
36
- 'recover'
37
- ]
38
-
39
- const TEMP_RE = /^amq\./
40
-
41
20
  /**
42
21
  * Register all the necessary instrumentation when using
43
22
  * promise based methods
@@ -91,18 +70,6 @@ function instrumentAMQP(shim, amqp, promiseMode) {
91
70
  wrapChannel(shim)
92
71
  }
93
72
 
94
- /**
95
- * Helper to set the appropriate value of the callback property
96
- * in the spec. If it's a promise set to null otherwise set it to `shim.LAST`
97
- *
98
- * @param {Shim} shim instance of shim
99
- * @param {boolean} promiseMode is this promise based?
100
- * @returns {string|null} appropriate value
101
- */
102
- function setCallback(shim, promiseMode) {
103
- return promiseMode ? null : shim.LAST
104
- }
105
-
106
73
  /**
107
74
  *
108
75
  * Instruments the connect method
@@ -134,209 +101,3 @@ function wrapConnect(shim, amqp, promiseMode) {
134
101
  })
135
102
  })
136
103
  }
137
-
138
- /**
139
- *
140
- * Instruments the sendOrEnqueue and sendMessage methods of the ampqlib channel.
141
- *
142
- * @param {Shim} shim instance of shim
143
- */
144
- function wrapChannel(shim) {
145
- const libChannel = shim.require('./lib/channel')
146
- if (!libChannel?.Channel?.prototype) {
147
- shim.logger.debug('Could not get Channel class to instrument.')
148
- return
149
- }
150
-
151
- const proto = libChannel.Channel.prototype
152
- if (shim.isWrapped(proto.sendMessage)) {
153
- shim.logger.trace('Channel already instrumented.')
154
- return
155
- }
156
- shim.logger.trace('Instrumenting basic Channel class.')
157
-
158
- shim.wrap(proto, 'sendOrEnqueue', function wrapSendOrEnqueue(shim, fn) {
159
- if (!shim.isFunction(fn)) {
160
- return fn
161
- }
162
-
163
- return function wrappedSendOrEnqueue() {
164
- const segment = shim.getSegment()
165
- const cb = arguments[arguments.length - 1]
166
- if (!shim.isFunction(cb) || !segment) {
167
- shim.logger.debug({ cb: !!cb, segment: !!segment }, 'Not binding sendOrEnqueue callback')
168
- return fn.apply(this, arguments)
169
- }
170
-
171
- shim.logger.trace('Binding sendOrEnqueue callback to %s', segment.name)
172
- const args = shim.argsToArray.apply(shim, arguments)
173
- args[args.length - 1] = shim.bindSegment(cb, segment)
174
- return fn.apply(this, args)
175
- }
176
- })
177
-
178
- shim.recordProduce(proto, 'sendMessage', function recordSendMessage(shim, fn, n, args) {
179
- const fields = args[0]
180
- if (!fields) {
181
- return null
182
- }
183
- const isDefault = fields.exchange === ''
184
- let exchange = 'Default'
185
- if (!isDefault) {
186
- exchange = TEMP_RE.test(fields.exchange) ? null : fields.exchange
187
- }
188
-
189
- return new MessageSpec({
190
- destinationName: exchange,
191
- destinationType: shim.EXCHANGE,
192
- routingKey: fields.routingKey,
193
- headers: fields.headers,
194
- parameters: getParameters(Object.create(null), fields)
195
- })
196
- })
197
- }
198
-
199
- /**
200
- * Sets the relevant message parameters
201
- *
202
- * @param {object} parameters object used to store the message parameters
203
- * @param {object} fields fields from the sendMessage method
204
- * @returns {QueueMessageParameters} parameters updated parameters
205
- */
206
- function getParameters(parameters, fields) {
207
- if (fields.routingKey) {
208
- parameters.routing_key = fields.routingKey
209
- }
210
- if (fields.correlationId) {
211
- parameters.correlation_id = fields.correlationId
212
- }
213
- if (fields.replyTo) {
214
- parameters.reply_to = fields.replyTo
215
- }
216
-
217
- return new QueueMessageParameters(parameters)
218
- }
219
-
220
- /**
221
- * Sets the QueueMessageParameters from the amqp message
222
- *
223
- * @param {object} message queue message
224
- * @returns {QueueMessageParameters} parameters from message
225
- */
226
- function getParametersFromMessage(message) {
227
- const parameters = Object.create(null)
228
- getParameters(parameters, message.fields)
229
- getParameters(parameters, message.properties)
230
- return parameters
231
- }
232
-
233
- /**
234
- *
235
- * Instruments the relevant channel callback_model or channel_model.
236
- *
237
- * @param {Shim} shim instance of shim
238
- * @param {object} Model either channel or callback model
239
- * @param {boolean} promiseMode is this promise based?
240
- */
241
- function wrapModel(shim, Model, promiseMode) {
242
- if (!Model.Channel?.prototype) {
243
- shim.logger.debug(
244
- `Could not get ${promiseMode ? 'promise' : 'callback'} model Channel to instrument.`
245
- )
246
- }
247
-
248
- const proto = Model.Channel.prototype
249
- if (shim.isWrapped(proto.consume)) {
250
- shim.logger.trace(`${promiseMode ? 'promise' : 'callback'} model already instrumented.`)
251
- return
252
- }
253
-
254
- shim.record(proto, CHANNEL_METHODS, function recordChannelMethod(shim, fn, name) {
255
- return new RecorderSpec({
256
- name: 'Channel#' + name,
257
- callback: setCallback(shim, promiseMode),
258
- promise: promiseMode
259
- })
260
- })
261
-
262
- shim.recordConsume(
263
- proto,
264
- 'get',
265
- new MessageSpec({
266
- destinationName: shim.FIRST,
267
- callback: setCallback(shim, promiseMode),
268
- promise: promiseMode,
269
- after: function handleConsumedMessage({ shim, result, args, segment }) {
270
- if (!shim.agent.config.message_tracer.segment_parameters.enabled) {
271
- shim.logger.trace('Not capturing segment parameters')
272
- return
273
- }
274
-
275
- // the message is the param when using the promised based model
276
- const message = promiseMode ? result : args?.[1]
277
- if (!message) {
278
- shim.logger.trace('No results from consume.')
279
- return null
280
- }
281
- const parameters = getParametersFromMessage(message)
282
- shim.copySegmentParameters(segment, parameters)
283
- }
284
- })
285
- )
286
-
287
- shim.recordPurgeQueue(proto, 'purgeQueue', function recordPurge(shim, fn, name, args) {
288
- let queue = args[0]
289
- if (TEMP_RE.test(queue)) {
290
- queue = null
291
- }
292
- return new MessageSpec({
293
- queue,
294
- promise: promiseMode,
295
- callback: setCallback(shim, promiseMode)
296
- })
297
- })
298
-
299
- shim.recordSubscribedConsume(
300
- proto,
301
- 'consume',
302
- new MessageSubscribeSpec({
303
- name: 'amqplib.Channel#consume',
304
- queue: shim.FIRST,
305
- consumer: shim.SECOND,
306
- promise: promiseMode,
307
- callback: promiseMode ? null : shim.FOURTH,
308
- messageHandler: describeMessage
309
- })
310
- )
311
- }
312
-
313
- /**
314
- * Extracts the appropriate messageHandler parameters for the consume method.
315
- *
316
- * @param {Shim} shim instance of shim
317
- * @param {Array} args arguments passed to the consume method
318
- * @returns {object} message params
319
- */
320
- function describeMessage(shim, args) {
321
- const [message] = args
322
-
323
- if (!message?.properties) {
324
- shim.logger.debug({ message: message }, 'Failed to find message in consume arguments.')
325
- return null
326
- }
327
-
328
- const parameters = getParametersFromMessage(message)
329
- let exchangeName = message?.fields?.exchange || 'Default'
330
-
331
- if (TEMP_RE.test(exchangeName)) {
332
- exchangeName = null
333
- }
334
-
335
- return new MessageSpec({
336
- destinationName: exchangeName,
337
- destinationType: shim.EXCHANGE,
338
- routingKey: message?.fields?.routingKey,
339
- headers: message.properties.headers,
340
- parameters
341
- })
342
- }
@@ -0,0 +1,129 @@
1
+ /*
2
+ * Copyright 2024 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ 'use strict'
7
+ const { MessageSpec, MessageSubscribeSpec, RecorderSpec } = require('../../shim/specs')
8
+ const CHANNEL_METHODS = [
9
+ 'close',
10
+ 'open',
11
+ 'assertQueue',
12
+ 'checkQueue',
13
+ 'deleteQueue',
14
+ 'bindQueue',
15
+ 'unbindQueue',
16
+ 'assertExchange',
17
+ 'checkExchange',
18
+ 'deleteExchange',
19
+ 'bindExchange',
20
+ 'unbindExchange',
21
+ 'cancel',
22
+ 'prefetch',
23
+ 'recover'
24
+ ]
25
+ const {
26
+ describeMessage,
27
+ setCallback,
28
+ parseConnect,
29
+ getParametersFromMessage,
30
+ TEMP_RE
31
+ } = require('./utils')
32
+
33
+ /**
34
+ *
35
+ * Instruments the relevant channel callback_model or channel_model.
36
+ *
37
+ * @param {Shim} shim instance of shim
38
+ * @param {object} Model either channel or callback model
39
+ * @param {boolean} promiseMode is this promise based?
40
+ */
41
+ module.exports = function wrapModel(shim, Model, promiseMode) {
42
+ if (!Model.Channel?.prototype) {
43
+ shim.logger.debug(
44
+ `Could not get ${promiseMode ? 'promise' : 'callback'} model Channel to instrument.`
45
+ )
46
+ return
47
+ }
48
+
49
+ const proto = Model.Channel.prototype
50
+ if (shim.isWrapped(proto.consume)) {
51
+ shim.logger.trace(`${promiseMode ? 'promise' : 'callback'} model already instrumented.`)
52
+ return
53
+ }
54
+
55
+ recordChannelMethods({ shim, proto, promiseMode })
56
+ recordPurge({ shim, proto, promiseMode })
57
+ recordGet({ shim, proto, promiseMode })
58
+ recordConsume({ shim, proto, promiseMode })
59
+ }
60
+
61
+ /**
62
+ * Record spans for common methods on channel
63
+ *
64
+ * @param {Channel} proto prototype of Model.Channel
65
+ */
66
+ function recordChannelMethods({ shim, proto, promiseMode }) {
67
+ shim.record(proto, CHANNEL_METHODS, function recordChannelMethod(shim, fn, name) {
68
+ return new RecorderSpec({
69
+ name: 'Channel#' + name,
70
+ callback: setCallback(shim, promiseMode),
71
+ promise: promiseMode
72
+ })
73
+ })
74
+ }
75
+
76
+ function recordPurge({ shim, proto, promiseMode }) {
77
+ shim.recordPurgeQueue(proto, 'purgeQueue', function purge(shim, fn, name, args) {
78
+ let queue = args[0]
79
+ if (TEMP_RE.test(queue)) {
80
+ queue = null
81
+ }
82
+ return new MessageSpec({
83
+ queue,
84
+ promise: promiseMode,
85
+ callback: setCallback(shim, promiseMode)
86
+ })
87
+ })
88
+ }
89
+
90
+ function recordGet({ shim, proto, promiseMode }) {
91
+ shim.recordConsume(proto, 'get', function wrapGet() {
92
+ const { host, port } = parseConnect(this?.connection?.stream)
93
+ return new MessageSpec({
94
+ destinationName: shim.FIRST,
95
+ callback: setCallback(shim, promiseMode),
96
+ promise: promiseMode,
97
+ after: function handleConsumedMessage({ shim, result, args, segment }) {
98
+ if (!shim.agent.config.message_tracer.segment_parameters.enabled) {
99
+ shim.logger.trace('Not capturing segment parameters')
100
+ return
101
+ }
102
+
103
+ // the message is the param when using the promised based model
104
+ const message = promiseMode ? result : args?.[1]
105
+ if (!message) {
106
+ shim.logger.trace('No results from consume.')
107
+ return null
108
+ }
109
+ const parameters = getParametersFromMessage({ message, host, port })
110
+ shim.copySegmentParameters(segment, parameters)
111
+ }
112
+ })
113
+ })
114
+ }
115
+
116
+ function recordConsume({ shim, proto, promiseMode }) {
117
+ shim.recordSubscribedConsume(proto, 'consume', function consume() {
118
+ const { host, port } = parseConnect(this?.connection?.stream)
119
+ return new MessageSubscribeSpec({
120
+ name: 'amqplib.Channel#consume',
121
+ queue: shim.FIRST,
122
+ consumer: shim.SECOND,
123
+ promise: promiseMode,
124
+ parameters: { host, port },
125
+ callback: promiseMode ? null : shim.FOURTH,
126
+ messageHandler: describeMessage({ host, port })
127
+ })
128
+ })
129
+ }
@@ -0,0 +1,70 @@
1
+ /*
2
+ * Copyright 2024 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ 'use strict'
7
+ const { MessageSpec } = require('../../shim/specs')
8
+ const { parseConnect, getParameters, TEMP_RE } = require('./utils')
9
+
10
+ /**
11
+ *
12
+ * Instruments the sendOrEnqueue and sendMessage methods of the ampqlib channel.
13
+ *
14
+ * @param {Shim} shim instance of shim
15
+ */
16
+ module.exports = function wrapChannel(shim) {
17
+ const libChannel = shim.require('./lib/channel')
18
+ if (!libChannel?.Channel?.prototype) {
19
+ shim.logger.debug('Could not get Channel class to instrument.')
20
+ return
21
+ }
22
+
23
+ const proto = libChannel.Channel.prototype
24
+ if (shim.isWrapped(proto.sendMessage)) {
25
+ shim.logger.trace('Channel already instrumented.')
26
+ return
27
+ }
28
+ shim.logger.trace('Instrumenting basic Channel class.')
29
+
30
+ shim.wrap(proto, 'sendOrEnqueue', function wrapSendOrEnqueue(shim, fn) {
31
+ if (!shim.isFunction(fn)) {
32
+ return fn
33
+ }
34
+
35
+ return function wrappedSendOrEnqueue() {
36
+ const segment = shim.getSegment()
37
+ const cb = arguments[arguments.length - 1]
38
+ if (!shim.isFunction(cb) || !segment) {
39
+ shim.logger.debug({ cb: !!cb, segment: !!segment }, 'Not binding sendOrEnqueue callback')
40
+ return fn.apply(this, arguments)
41
+ }
42
+
43
+ shim.logger.trace('Binding sendOrEnqueue callback to %s', segment.name)
44
+ const args = shim.argsToArray.apply(shim, arguments)
45
+ args[args.length - 1] = shim.bindSegment(cb, segment)
46
+ return fn.apply(this, args)
47
+ }
48
+ })
49
+
50
+ shim.recordProduce(proto, 'sendMessage', function recordSendMessage(shim, fn, n, args) {
51
+ const fields = args[0]
52
+ if (!fields) {
53
+ return null
54
+ }
55
+ const isDefault = fields.exchange === ''
56
+ let exchange = 'Default'
57
+ if (!isDefault) {
58
+ exchange = TEMP_RE.test(fields.exchange) ? null : fields.exchange
59
+ }
60
+ const { host, port } = parseConnect(this?.connection?.stream)
61
+
62
+ return new MessageSpec({
63
+ destinationName: exchange,
64
+ destinationType: shim.EXCHANGE,
65
+ routingKey: fields.routingKey,
66
+ headers: fields.headers,
67
+ parameters: getParameters({ parameters: Object.create(null), fields, host, port })
68
+ })
69
+ })
70
+ }
@@ -0,0 +1,141 @@
1
+ /*
2
+ * Copyright 2024 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ 'use strict'
7
+ const {
8
+ MessageSpec,
9
+ params: { QueueMessageParameters }
10
+ } = require('../../shim/specs')
11
+ const { amqpConnection } = require('../../symbols')
12
+ const TEMP_RE = /^amq\./
13
+
14
+ /**
15
+ * Wrapper around message handler to pass host/port
16
+ *
17
+ * @param {object} params to function
18
+ * @param {string} params.host hostname
19
+ * @param {number} params.port port
20
+ * @returns {function} message handler
21
+ */
22
+ function describeMessage({ host, port }) {
23
+ /**
24
+ * Extracts the appropriate messageHandler parameters for the consume method.
25
+ *
26
+ * @param {Shim} shim instance of shim
27
+ * @param {Array} args arguments passed to the consume method
28
+ * @returns {object} message params
29
+ */
30
+ return function messageHandler(shim, args) {
31
+ const [message] = args
32
+
33
+ if (!message?.properties) {
34
+ shim.logger.debug({ message: message }, 'Failed to find message in consume arguments.')
35
+ return null
36
+ }
37
+
38
+ const parameters = getParametersFromMessage({ message, host, port })
39
+ let exchangeName = message?.fields?.exchange || 'Default'
40
+
41
+ if (TEMP_RE.test(exchangeName)) {
42
+ exchangeName = null
43
+ }
44
+
45
+ return new MessageSpec({
46
+ destinationName: exchangeName,
47
+ destinationType: shim.EXCHANGE,
48
+ routingKey: message?.fields?.routingKey,
49
+ headers: message.properties.headers,
50
+ parameters
51
+ })
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Sets the relevant message parameters
57
+ *
58
+ * @param {object} params to function
59
+ * @param {object} params.parameters object used to store the message parameters
60
+ * @param {object} params.fields fields from the sendMessage method
61
+ * @param {string} params.host hostname
62
+ * @param {number} params.port port
63
+ * @returns {QueueMessageParameters} parameters updated parameters
64
+ */
65
+ function getParameters({ parameters, fields, host, port }) {
66
+ if (fields.routingKey) {
67
+ parameters.routing_key = fields.routingKey
68
+ }
69
+ if (fields.correlationId) {
70
+ parameters.correlation_id = fields.correlationId
71
+ }
72
+ if (fields.replyTo) {
73
+ parameters.reply_to = fields.replyTo
74
+ }
75
+
76
+ if (host) {
77
+ parameters.host = host
78
+ }
79
+
80
+ if (port) {
81
+ parameters.port = port
82
+ }
83
+
84
+ return new QueueMessageParameters(parameters)
85
+ }
86
+
87
+ /**
88
+ * Sets the QueueMessageParameters from the amqp message
89
+ *
90
+ * @param {object} params to function
91
+ * @param {object} params.message queue message
92
+ * @param {string} params.host host
93
+ * @param {number} params.port port
94
+ * @returns {QueueMessageParameters} parameters from message
95
+ */
96
+ function getParametersFromMessage({ message, host, port }) {
97
+ const parameters = Object.create(null)
98
+ getParameters({ parameters, fields: message.fields, host, port })
99
+ getParameters({ parameters, fields: message.properties })
100
+ return parameters
101
+ }
102
+
103
+ /**
104
+ * Extracts the host/port from the amqp socket connection.
105
+ * Stores on connection as symbol to only parse once.
106
+ *
107
+ * @param {Socket} socket amqp connection
108
+ * @returns {object} {host, port } of connection
109
+ */
110
+ function parseConnect(socket) {
111
+ if (socket[amqpConnection]) {
112
+ return socket[amqpConnection]
113
+ }
114
+ const host = ['127.0.0.1', '::1', '[::1]'].includes(socket?.remoteAddress)
115
+ ? 'localhost'
116
+ : socket?.remoteAddress
117
+ const port = socket?.remotePort
118
+ socket[amqpConnection] = { host, port }
119
+ return { host, port }
120
+ }
121
+
122
+ /**
123
+ * Helper to set the appropriate value of the callback property
124
+ * in the spec. If it's a promise set to null otherwise set it to `shim.LAST`
125
+ *
126
+ * @param {Shim} shim instance of shim
127
+ * @param {boolean} promiseMode is this promise based?
128
+ * @returns {string|null} appropriate value
129
+ */
130
+ function setCallback(shim, promiseMode) {
131
+ return promiseMode ? null : shim.LAST
132
+ }
133
+
134
+ module.exports = {
135
+ describeMessage,
136
+ getParameters,
137
+ getParametersFromMessage,
138
+ parseConnect,
139
+ setCallback,
140
+ TEMP_RE
141
+ }
@@ -5,7 +5,6 @@
5
5
 
6
6
  'use strict'
7
7
 
8
- const asyncHooks = require('./async-hooks')
9
8
  const symbols = require('../../symbols')
10
9
 
11
10
  module.exports = initialize
@@ -63,8 +62,4 @@ function initialize(agent, nodule, name, shim) {
63
62
  return original.apply(this, arguments)
64
63
  }
65
64
  }
66
-
67
- // This will initialize the most optimal native-promise instrumentation that
68
- // we have available.
69
- asyncHooks(agent, shim)
70
65
  }