newrelic 8.4.0 → 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.
@@ -0,0 +1,242 @@
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 cat = require('../util/cat')
9
+ const recordExternal = require('../metrics/recorders/http_external')
10
+ const logger = require('../logger').child({ component: 'undici' })
11
+ const NAMES = require('../metrics/names')
12
+ const NEWRELIC_SYNTHETICS_HEADER = 'x-newrelic-synthetics'
13
+ const SYMBOLS = {
14
+ SEGMENT: Symbol('__NR_segment'),
15
+ PARENT_SEGMENT: Symbol('__NR_parent_segment')
16
+ }
17
+ const { executionAsyncResource } = require('async_hooks')
18
+
19
+ let diagnosticsChannel = null
20
+ try {
21
+ diagnosticsChannel = require('diagnostics_channel')
22
+ } catch (e) {
23
+ // quick check to see if module exists
24
+ // module was not added until v15.x
25
+ }
26
+
27
+ module.exports = function addUndiciChannels(agent, undici, modName, shim) {
28
+ if (!diagnosticsChannel || !agent.config.feature_flag.undici_instrumentation) {
29
+ logger.warn(
30
+ 'diagnostics_channel or feature_flag.undici_instrumentation = false. Skipping undici instrumentation.'
31
+ )
32
+ return
33
+ }
34
+
35
+ /**
36
+ * Retrieves the current segment in transaction(parent in our context) from executionAsyncResource
37
+ * or from `shim.getSegment()` then adds to the executionAsyncResource for future
38
+ * undici requests within same async context.
39
+ *
40
+ * It was found that when running concurrent undici requests
41
+ * within a transaction that the parent segment would get out of sync
42
+ * depending on the async context of the transaction. By using
43
+ * `async_hooks.executionResource` it is more reliable.
44
+ *
45
+ * Note: However, if you have concurrent undici requests in a transaction
46
+ * and the request to the transaction is using a keep alive there is a chance the
47
+ * executionAsyncResource may be incorrect because of shared connections. To revert to a more
48
+ * naive tracking of parent set `config.feature_flag.undici_async_tracking: false` and
49
+ * it will just call `shim.getSegment()`
50
+ */
51
+ function getParentSegment() {
52
+ if (agent.config.feature_flag.undici_async_tracking) {
53
+ const resource = executionAsyncResource()
54
+
55
+ if (!resource[SYMBOLS.PARENT_SEGMENT]) {
56
+ const parent = shim.getSegment()
57
+ resource[SYMBOLS.PARENT_SEGMENT] = parent
58
+ }
59
+ return resource[SYMBOLS.PARENT_SEGMENT]
60
+ }
61
+ return shim.getSegment()
62
+ }
63
+
64
+ /**
65
+ * This event occurs after the Undici Request is created
66
+ * We will check current segment for opaque and also attach
67
+ * relevant headers to outgoing http request
68
+ *
69
+ * @param {object} params
70
+ * @param {object} params.request undici request object
71
+ */
72
+ diagnosticsChannel.channel('undici:request:create').subscribe(({ request }) => {
73
+ const parent = getParentSegment()
74
+ request[SYMBOLS.PARENT_SEGMENT] = parent
75
+ if (!parent || (parent && parent.opaque)) {
76
+ logger.trace(
77
+ 'Not capturing data for outbound request (%s) because parent segment opaque (%s)',
78
+ request.path,
79
+ parent && parent.name
80
+ )
81
+
82
+ return
83
+ }
84
+
85
+ const transaction = parent.transaction
86
+ const outboundHeaders = Object.create(null)
87
+ if (agent.config.encoding_key && transaction.syntheticsHeader) {
88
+ outboundHeaders[NEWRELIC_SYNTHETICS_HEADER] = transaction.syntheticsHeader
89
+ }
90
+
91
+ if (agent.config.distributed_tracing.enabled) {
92
+ transaction.insertDistributedTraceHeaders(outboundHeaders)
93
+ } else if (agent.config.cross_application_tracer.enabled) {
94
+ cat.addCatHeaders(agent.config, transaction, outboundHeaders)
95
+ } else {
96
+ logger.trace('Both DT and CAT are disabled, not adding headers!')
97
+ }
98
+
99
+ // eslint-disable-next-line guard-for-in
100
+ for (const key in outboundHeaders) {
101
+ request.addHeader(key, outboundHeaders[key])
102
+ }
103
+ })
104
+
105
+ /**
106
+ * This event occurs right before the data is written to the socket.
107
+ * Undici has some abstracted headers that are only created at this time, one
108
+ * is the `host` header which we need to name the Undici segment. So in this
109
+ * handler we create, start and set the segment active, name it, and
110
+ * attach the url/procedure/request.parameters
111
+ *
112
+ * @param {object} params
113
+ * @param {object} params.request undicie request object
114
+ * @param {TLSSocket | net.Socket} socket active socket connection
115
+ */
116
+ diagnosticsChannel.channel('undici:client:sendHeaders').subscribe(({ request, socket }) => {
117
+ const parentSegment = request[SYMBOLS.PARENT_SEGMENT]
118
+ if (!parentSegment || (parentSegment && parentSegment.opaque)) {
119
+ return
120
+ }
121
+
122
+ const port = socket.remotePort
123
+ const isHttps = socket.servername
124
+ let urlString
125
+ if (isHttps) {
126
+ urlString = `https://${socket.servername}`
127
+ urlString += port === 443 ? request.path : `:${port}${request.path}`
128
+ } else {
129
+ urlString = `http://${socket._host}`
130
+ urlString += port === 80 ? request.path : `:${port}${request.path}`
131
+ }
132
+
133
+ const url = new URL(urlString)
134
+
135
+ const name = NAMES.EXTERNAL.PREFIX + url.host + url.pathname
136
+ const segment = shim.createSegment(name, recordExternal(url.host, 'undici'), parentSegment)
137
+ if (segment) {
138
+ segment.start()
139
+ shim.setActiveSegment(segment)
140
+ segment.addAttribute('url', `${url.protocol}//${url.host}${url.pathname}`)
141
+
142
+ url.searchParams.forEach((value, key) => {
143
+ segment.addSpanAttribute(`request.parameters.${key}`, value)
144
+ })
145
+ segment.addAttribute('procedure', request.method || 'GET')
146
+ request[SYMBOLS.SEGMENT] = segment
147
+ }
148
+ })
149
+
150
+ /**
151
+ * This event occurs after the response headers have been received.
152
+ * We will add the relevant http response attributes to active segment.
153
+ * Also add CAT specific keys to active segment.
154
+ *
155
+ * @param {object} params
156
+ * @param {object} params.request undici request object
157
+ * @param {object} params.response { statusCode, headers, statusText }
158
+ */
159
+ diagnosticsChannel.channel('undici:request:headers').subscribe(({ request, response }) => {
160
+ const activeSegment = request[SYMBOLS.SEGMENT]
161
+ if (!activeSegment) {
162
+ return
163
+ }
164
+
165
+ activeSegment.addSpanAttribute('http.statusCode', response.statusCode)
166
+ activeSegment.addSpanAttribute('http.statusText', response.statusText)
167
+
168
+ if (
169
+ agent.config.cross_application_tracer.enabled &&
170
+ !agent.config.distributed_tracing.enabled
171
+ ) {
172
+ try {
173
+ const { appData } = cat.extractCatHeaders(response.headers)
174
+ const decodedAppData = cat.parseAppData(agent.config, appData)
175
+ const attrs = activeSegment.getAttributes()
176
+ const url = new URL(attrs.url)
177
+ cat.assignCatToSegment(decodedAppData, activeSegment, url.host)
178
+ } catch (err) {
179
+ logger.warn(err, 'Cannot add CAT data to segment')
180
+ }
181
+ }
182
+ })
183
+
184
+ /**
185
+ * This event occurs after the response body has been received.
186
+ * We will end the active segment and set the active back to parent before request
187
+ *
188
+ * @param {object} params.request undici request object
189
+ */
190
+ diagnosticsChannel.channel('undici:request:trailers').subscribe(({ request }) => {
191
+ endAndRestoreSegment(request)
192
+ })
193
+
194
+ /**
195
+ * This event occurs right before the request emits an error.
196
+ * We will end the active segment and set the active back to parent before request.
197
+ * We will also log errors to NR
198
+ *
199
+ * Note: This event occurs before the error handler so we will always log it for now.
200
+ */
201
+ diagnosticsChannel.channel('undici:request:error').subscribe(({ request, error }) => {
202
+ endAndRestoreSegment(request, error)
203
+ })
204
+
205
+ /**
206
+ * Gets the active and parent from given ctx(request, client connector)
207
+ * and ends active and restores parent to active. If an error exists
208
+ * it will add the error to the transaction
209
+ *
210
+ * @param {object} ctx request or client connector
211
+ * @param {Error} error
212
+ */
213
+ function endAndRestoreSegment(ctx, error) {
214
+ const activeSegment = ctx[SYMBOLS.SEGMENT]
215
+ const parentSegment = ctx[SYMBOLS.PARENT_SEGMENT]
216
+ if (activeSegment) {
217
+ activeSegment.end()
218
+
219
+ if (error) {
220
+ handleError(activeSegment, error)
221
+ }
222
+
223
+ if (parentSegment) {
224
+ shim.setActiveSegment(parentSegment)
225
+ }
226
+ }
227
+ }
228
+
229
+ /**
230
+ * Adds the error to the active transaction
231
+ *
232
+ * @param {TraceSegment} activeSegment
233
+ * @param {Error} error
234
+ */
235
+ function handleError(activeSegment, error) {
236
+ logger.trace(error, 'Captured outbound error on behalf of the user.')
237
+ const tx = activeSegment.transaction
238
+ shim.agent.errors.add(tx, error)
239
+ }
240
+ }
241
+
242
+ module.exports.SYMBOLS = SYMBOLS
@@ -31,6 +31,7 @@ module.exports = function instrumentations() {
31
31
  'redis': { type: MODULE_TYPE.DATASTORE },
32
32
  'restify': { type: MODULE_TYPE.WEB_FRAMEWORK },
33
33
  'superagent': { module: '@newrelic/superagent' },
34
+ 'undici': { type: MODULE_TYPE.TRANSACTION },
34
35
  'oracle': { type: null },
35
36
  'vision': { type: MODULE_TYPE.WEB_FRAMEWORK },
36
37
  'when': { type: null }
@@ -17,6 +17,12 @@ function parseProcCPUInfo(data) {
17
17
  packages: null
18
18
  }
19
19
 
20
+ // In some rare cases the OS may be locked down so that you cannot retrieve this info.
21
+ if (!data) {
22
+ logger.debug('No CPU data to parse, returning empty stats.')
23
+ return processorStats
24
+ }
25
+
20
26
  // separate the processors
21
27
  let splitData = data.split('\n').map(function formatAttribute(attr) {
22
28
  return attr.split(':').map(function eliminateExtraWhitespace(s) {
@@ -34,7 +40,7 @@ function parseProcCPUInfo(data) {
34
40
 
35
41
  splitData = collapseMultilineValues(splitData)
36
42
 
37
- const processors = seperateProcessors(splitData)
43
+ const processors = separateProcessors(splitData)
38
44
 
39
45
  processorStats = countProcessorStats(processors)
40
46
  if (!processorStats.cores) {
@@ -73,7 +79,7 @@ function collapseMultilineValues(li) {
73
79
 
74
80
  // walk through the processed list of key, value pairs and populate
75
81
  // objects till you find a collision
76
- function seperateProcessors(processorData) {
82
+ function separateProcessors(processorData) {
77
83
  const processors = []
78
84
  let processor = Object.create(null)
79
85
  for (let i = 0; i < processorData.length; ++i) {
@@ -10,6 +10,12 @@ const logger = require('./logger.js').child({ component: 'proc-meminfo' })
10
10
  module.exports = parseProcMeminfo
11
11
 
12
12
  function parseProcMeminfo(data) {
13
+ // In some rare cases the OS may be locked down so that you cannot retrieve this info.
14
+ if (!data) {
15
+ logger.debug('No memory data to parse.')
16
+ return null
17
+ }
18
+
13
19
  const memTotal = parseInt(data.replace(/MemTotal:\s*(\d*)\skB/, '$1'), 10)
14
20
 
15
21
  if (memTotal) {
@@ -82,8 +82,14 @@ class AwsLambda {
82
82
  // NOTE: This may be converted to holding onto a single ender function if only
83
83
  // one invocation is executing at a time.
84
84
  shim.wrap(process, 'emit', function wrapEmit(shim, emit) {
85
- return function wrappedEmit(ev) {
86
- if (ev === 'beforeExit') {
85
+ return function wrappedEmit(ev, error) {
86
+ // need to add error as uncaughtException to be used
87
+ // later to add to transaction errors
88
+ if (ev === 'unhandledRejection') {
89
+ uncaughtException = error
90
+ }
91
+
92
+ if (['beforeExit', 'unhandledRejection'].includes(ev)) {
87
93
  transactionEnders.forEach((ender) => {
88
94
  ender()
89
95
  })
@@ -62,20 +62,16 @@ const DESTINATION_TYPES = {
62
62
  /**
63
63
  * Constructs a shim specialized for instrumenting message brokers.
64
64
  *
65
- * @constructor
66
- * @extends TransactionShim
65
+ * @class
66
+ * @augments TransactionShim
67
67
  * @classdesc
68
68
  * Used for instrumenting message broker client libraries.
69
- *
70
69
  * @param {Agent} agent
71
70
  * The agent this shim will use.
72
- *
73
71
  * @param {string} moduleName
74
72
  * The name of the module being instrumented.
75
- *
76
73
  * @param {string} resolvedName
77
74
  * The full path to the loaded module.
78
- *
79
75
  * @see Shim
80
76
  * @see TransactionShim
81
77
  */
@@ -112,124 +108,93 @@ MessageShim.prototype.recordSubscribedConsume = recordSubscribedConsume
112
108
 
113
109
  /**
114
110
  * @callback MessageFunction
115
- *
116
111
  * @summary
117
112
  * Used for determining information about a message either being produced or
118
113
  * consumed.
119
- *
120
114
  * @param {MessageShim} shim
121
115
  * The shim this function was handed to.
122
- *
123
116
  * @param {Function} func
124
117
  * The produce method or message consumer.
125
- *
126
118
  * @param {string} name
127
119
  * The name of the producer or consumer.
128
- *
129
120
  * @param {Array.<*>} args
130
121
  * The arguments being passed into the produce method or consumer.
131
- *
132
- * @return {MessageSpec} The specification for the message being produced or
122
+ * @returns {MessageSpec} The specification for the message being produced or
133
123
  * consumed.
134
- *
135
124
  * @see MessageShim#recordProduce
136
125
  * @see MessageShim#recordConsume
137
126
  */
138
127
 
139
128
  /**
140
129
  * @callback MessageHandlerFunction
141
- *
142
130
  * @summary
143
131
  * A function that is used to extract properties from a consumed message. This
144
132
  * method is handed the results of a consume call. If the consume used a
145
133
  * callback, then this method will receive the arguments to the callback. If
146
134
  * the consume used a promise, then this method will receive the resolved
147
135
  * value.
148
- *
149
136
  * @param {MessageShim} shim
150
137
  * The shim this function was handed to.
151
- *
152
138
  * @param {Function} func
153
139
  * The produce method or message consumer.
154
- *
155
140
  * @param {string} name
156
141
  * The name of the producer or consumer.
157
- *
158
142
  * @param {Array|*} args
159
143
  * Either the arguments for the consumer callback function or the result of
160
144
  * the resolved consume promise, depending on the mode of the instrumented
161
145
  * method.
162
- *
163
- * @return {MessageSpec} The extracted properties of the consumed message.
164
- *
146
+ * @returns {MessageSpec} The extracted properties of the consumed message.
165
147
  * @see MessageShim#recordConsume
166
148
  */
167
149
 
168
150
  /**
169
151
  * @callback MessageConsumerWrapperFunction
170
- *
171
152
  * @summary
172
153
  * Function that is used to wrap message consumer functions. Used along side
173
154
  * the MessageShim#recordSubscribedConsume API method.
174
- *
175
155
  * @param {MessageShim} shim
176
156
  * The shim this function was handed to.
177
- *
178
157
  * @param {Function} consumer
179
158
  * The message consumer to wrap.
180
- *
181
159
  * @param {string} name
182
160
  * The name of the consumer method.
183
- *
184
161
  * @param {string} queue
185
162
  * The name of the queue this consumer is being subscribed to.
186
- *
187
- * @return {Function} The consumer method, possibly wrapped.
188
- *
163
+ * @returns {Function} The consumer method, possibly wrapped.
189
164
  * @see MessageShim#recordSubscribedConsume
190
165
  * @see MessageShim#recordConsume
191
166
  */
192
167
 
193
168
  /**
194
169
  * @interface MessageSpec
195
- * @extends RecorderSpec
196
- *
170
+ * @augments RecorderSpec
197
171
  * @description
198
172
  * The specification for a message being produced or consumed.
199
- *
200
173
  * @property {string} destinationName
201
174
  * The name of the exchange or queue the message is being produced to or
202
175
  * consumed from.
203
- *
204
176
  * @property {MessageShim.DESTINATION_TYPES} [destinationType=null]
205
177
  * The type of the destination. Defaults to `shim.EXCHANGE`.
206
- *
207
- * @property {Object} [headers=null]
178
+ * @property {object} [headers=null]
208
179
  * A reference to the message headers. On produce, more headers will be added
209
180
  * to this object which should be sent along with the message. On consume,
210
181
  * cross-application headers will be read from this object.
211
- *
212
182
  * @property {string} [routingKey=null]
213
183
  * The routing key for the message. If provided on consume, the routing key
214
184
  * will be added to the transaction attributes as `message.routingKey`.
215
- *
216
185
  * @property {string} [queue=null]
217
186
  * The name of the queue the message was consumed from. If provided on
218
187
  * consume, the queue name will be added to the transaction attributes as
219
188
  * `message.queueName`.
220
- *
221
189
  * @property {string} [parameters.correlation_id]
222
190
  * In AMQP, this should be the correlation Id of the message, if it has one.
223
- *
224
191
  * @property {string} [parameters.reply_to]
225
192
  * In AMQP, this should be the name of the queue to reply to, if the message
226
193
  * has one.
227
- *
228
194
  * @property {MessageHandlerFunction} [messageHandler]
229
195
  * An optional function to extract message properties from a consumed message.
230
196
  * This method is only used in the consume case to pull data from the
231
197
  * retrieved message.
232
- *
233
198
  * @see RecorderSpec
234
199
  * @see MessageShim#recordProduce
235
200
  * @see MessageShim#recordConsume
@@ -238,23 +203,19 @@ MessageShim.prototype.recordSubscribedConsume = recordSubscribedConsume
238
203
 
239
204
  /**
240
205
  * @interface MessageSubscribeSpec
241
- * @extends MessageSpec
242
- *
206
+ * @augments MessageSpec
243
207
  * @description
244
208
  * Specification for message subscriber methods. That is, methods which
245
209
  * register a consumer to start receiving messages.
246
- *
247
210
  * @property {number} consumer
248
211
  * The index of the consumer in the method's arguments. Note that if the
249
212
  * consumer and callback indexes point to the same argument, the argument will
250
213
  * be wrapped as a consumer.
251
- *
252
214
  * @property {MessageHandlerFunction} messageHandler
253
215
  * A function to extract message properties from a consumed message.
254
216
  * This method is only used in the consume case to pull data from the
255
217
  * retrieved message. Its return value is combined with the `MessageSubscribeSpec`
256
218
  * to fully describe the consumed message.
257
- *
258
219
  * @see MessageSpec
259
220
  * @see MessageConsumerWrapperFunction
260
221
  * @see MessageShim#recordSubscribedConsume
@@ -269,11 +230,9 @@ MessageShim.prototype.recordSubscribedConsume = recordSubscribedConsume
269
230
  * passed, metric names will be generated using that.
270
231
  *
271
232
  * @memberof MessageShim.prototype
272
- *
273
233
  * @param {MessageShim.LIBRARY_NAMES|string} library
274
234
  * The name of the message broker library. Use one of the well-known constants
275
235
  * listed in {@link MessageShim.LIBRARY_NAMES} if available for the library.
276
- *
277
236
  * @see MessageShim.LIBRARY_NAMES
278
237
  */
279
238
  function setLibrary(library) {
@@ -305,20 +264,15 @@ function setLibrary(library) {
305
264
  * `PRODUCE` metric.
306
265
  *
307
266
  * @memberof MessageShim.prototype
308
- *
309
- * @param {Object|Function} nodule
267
+ * @param {object | Function} nodule
310
268
  * The source for the properties to wrap, or a single function to wrap.
311
- *
312
269
  * @param {string|Array.<string>} [properties]
313
270
  * One or more properties to wrap. If omitted, the `nodule` parameter is
314
271
  * assumed to be the function to wrap.
315
- *
316
272
  * @param {MessageFunction} recordNamer
317
273
  * A function which specifies details of the message.
318
- *
319
- * @return {Object|Function} The first parameter to this function, after
274
+ * @returns {object | Function} The first parameter to this function, after
320
275
  * wrapping it or its properties.
321
- *
322
276
  * @see Shim#wrap
323
277
  * @see Shim#record
324
278
  * @see MessageSpec
@@ -374,21 +328,16 @@ function recordProduce(nodule, properties, recordNamer) {
374
328
  * consumers see {@link MessageShim#recordSubscribedConsume}
375
329
  *
376
330
  * @memberof MessageShim.prototype
377
- *
378
- * @param {Object|Function} nodule
331
+ * @param {object | Function} nodule
379
332
  * The source for the properties to wrap, or a single function to wrap.
380
- *
381
333
  * @param {string|Array.<string>} [properties]
382
334
  * One or more properties to wrap. If omitted, the `nodule` parameter is
383
335
  * assumed to be the function to wrap.
384
- *
385
336
  * @param {MessageSpec|MessageFunction} spec
386
337
  * The spec for the method or a function which returns the details of the
387
338
  * method.
388
- *
389
- * @return {Object|Function} The first parameter to this function, after
339
+ * @returns {object | Function} The first parameter to this function, after
390
340
  * wrapping it or its properties.
391
- *
392
341
  * @see Shim#wrap
393
342
  * @see Shim#record
394
343
  * @see MessageShim#recordSubscribedConsume
@@ -411,6 +360,10 @@ function recordConsume(nodule, properties, spec) {
411
360
  spec = this.setDefaults(spec, DEFAULT_SPEC)
412
361
  }
413
362
 
363
+ // This is using wrap instead of record because the spec allows for a messageHandler
364
+ // which is being used to handle the result of the callback or promise of the
365
+ // original wrapped consume function.
366
+ // TODO: https://github.com/newrelic/node-newrelic/issues/981
414
367
  return this.wrap(nodule, properties, function wrapConsume(shim, fn, fnName) {
415
368
  if (!shim.isFunction(fn)) {
416
369
  shim.logger.debug('Not wrapping %s (%s) as consume', fn, fnName)
@@ -487,15 +440,19 @@ function recordConsume(nodule, properties, spec) {
487
440
  // Call the method in the context of our segment.
488
441
  let ret = shim.applySegment(fn, segment, true, this, args)
489
442
 
490
- // Intercept the promise to handle the result.
491
- if (resHandler && ret && msgDesc.promise && shim.isPromise(ret)) {
492
- ret = ret.then(function interceptValue(res) {
493
- const msgProps = resHandler.call(this, shim, fn, fnName, res)
494
- if (getParams && msgProps && msgProps.parameters) {
495
- shim.copySegmentParameters(segment, msgProps.parameters)
496
- }
497
- return res
498
- })
443
+ if (ret && msgDesc.promise && shim.isPromise(ret)) {
444
+ ret = shim.bindPromise(ret, segment)
445
+
446
+ // Intercept the promise to handle the result.
447
+ if (resHandler) {
448
+ ret = ret.then(function interceptValue(res) {
449
+ const msgProps = resHandler.call(this, shim, fn, fnName, res)
450
+ if (getParams && msgProps && msgProps.parameters) {
451
+ shim.copySegmentParameters(segment, msgProps.parameters)
452
+ }
453
+ return res
454
+ })
455
+ }
499
456
  }
500
457
 
501
458
  return ret
@@ -510,23 +467,17 @@ function recordConsume(nodule, properties, spec) {
510
467
  * - `recordPurgeQueue(func, spec)`
511
468
  *
512
469
  * @memberof MessageShim.prototype
513
- *
514
- * @param {Object|Function} nodule
470
+ * @param {object | Function} nodule
515
471
  * The source for the properties to wrap, or a single function to wrap.
516
- *
517
472
  * @param {string|Array.<string>} [properties]
518
473
  * One or more properties to wrap. If omitted, the `nodule` parameter is
519
474
  * assumed to be the function to wrap.
520
- *
521
475
  * @param {RecorderSpec} spec
522
476
  * The specification for this queue purge method's interface.
523
- *
524
477
  * @param {string} spec.queue
525
478
  * The name of the queue being purged.
526
- *
527
- * @return {Object|Function} The first parameter to this function, after
479
+ * @returns {object | Function} The first parameter to this function, after
528
480
  * wrapping it or its properties.
529
- *
530
481
  * @see Shim#wrap
531
482
  * @see Shim#record
532
483
  * @see RecorderSpec
@@ -598,20 +549,15 @@ function recordPurgeQueue(nodule, properties, spec) {
598
549
  * `spec.wrapper` method even if no transaction is active.
599
550
  *
600
551
  * @memberof MessageShim.prototype
601
- *
602
- * @param {Object|Function} nodule
552
+ * @param {object | Function} nodule
603
553
  * The source for the properties to wrap, or a single function to wrap.
604
- *
605
554
  * @param {string|Array.<string>} [properties]
606
555
  * One or more properties to wrap. If omitted, the `nodule` parameter is
607
556
  * assumed to be the function to wrap.
608
- *
609
557
  * @param {MessageSubscribeSpec} spec
610
558
  * The specification for this subscription method's interface.
611
- *
612
- * @return {Object|Function} The first parameter to this function, after
559
+ * @returns {object | Function} The first parameter to this function, after
613
560
  * wrapping it or its properties.
614
- *
615
561
  * @see Shim#wrap
616
562
  * @see Shim#record
617
563
  * @see MessageShim#recordConsume
@@ -702,6 +648,10 @@ function recordSubscribedConsume(nodule, properties, spec) {
702
648
  }
703
649
  })
704
650
 
651
+ /**
652
+ * @param queue
653
+ * @param destinationName
654
+ */
705
655
  function makeWrapConsumer(queue, destinationName) {
706
656
  const msgDescDefaults = copy.shallow(spec)
707
657
  if (destNameIsArg && destinationName != null) {
@@ -810,6 +760,9 @@ function recordSubscribedConsume(nodule, properties, spec) {
810
760
 
811
761
  return ret
812
762
 
763
+ /**
764
+ *
765
+ */
813
766
  function endTransaction() {
814
767
  tx.finalizeName(null) // Use existing partial name.
815
768
  tx.end()
@@ -830,12 +783,10 @@ function recordSubscribedConsume(nodule, properties, spec) {
830
783
  * Constructs a message segment name from the given message descriptor.
831
784
  *
832
785
  * @private
833
- *
834
786
  * @param {MessageShim} shim - The shim the segment will be constructed by.
835
787
  * @param {MessageSpec} msgDesc - The message descriptor.
836
788
  * @param {string} action - Produce or consume?
837
- *
838
- * @return {string} The generated name of the message segment.
789
+ * @returns {string} The generated name of the message segment.
839
790
  */
840
791
  function _nameMessageSegment(shim, msgDesc, action) {
841
792
  let name =
@@ -855,6 +806,10 @@ function _nameMessageSegment(shim, msgDesc, action) {
855
806
  return name
856
807
  }
857
808
 
809
+ /**
810
+ * @param shim
811
+ * @param msgDesc
812
+ */
858
813
  function _nameMessageTransaction(shim, msgDesc) {
859
814
  let name = shim._metrics.LIBRARY + '/' + (msgDesc.destinationType || shim.EXCHANGE) + '/'
860
815