newrelic 11.17.0 → 11.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NEWS.md +33 -0
- package/lib/feature_flags.js +4 -1
- package/lib/instrumentation/@node-redis/client.js +4 -0
- package/lib/instrumentation/amqplib/amqplib.js +9 -9
- package/lib/instrumentation/aws-sdk/v3/bedrock.js +1 -2
- package/lib/instrumentation/core/inspector.js +1 -1
- package/lib/instrumentation/langchain/runnable.js +2 -4
- package/lib/instrumentation/langchain/tools.js +1 -2
- package/lib/instrumentation/langchain/vectorstore.js +1 -2
- package/lib/instrumentation/memcached.js +1 -1
- package/lib/instrumentation/openai.js +2 -4
- package/lib/instrumentation/redis.js +3 -3
- package/lib/instrumentation/superagent.js +1 -1
- package/lib/shim/message-shim/consume.js +9 -119
- package/lib/shim/message-shim/index.js +2 -11
- package/lib/shim/message-shim/subscribe-consume.js +4 -5
- package/lib/shim/shim.js +61 -35
- package/lib/shim/specs/recorder.js +10 -7
- package/lib/shim/webframework-shim/middleware.js +6 -6
- package/package.json +1 -2
package/NEWS.md
CHANGED
|
@@ -1,3 +1,36 @@
|
|
|
1
|
+
### v11.18.0 (2024-05-29)
|
|
2
|
+
|
|
3
|
+
#### Features
|
|
4
|
+
|
|
5
|
+
* Added support for redis v4 legacyMode `client.v4.<command>` ([#2200](https://github.com/newrelic/node-newrelic/pull/2200)) ([b2284c5](https://github.com/newrelic/node-newrelic/commit/b2284c58eb798ab00a141ce08f4072584795c728))
|
|
6
|
+
|
|
7
|
+
#### Code refactoring
|
|
8
|
+
|
|
9
|
+
* Updated `shim.recordConsume` to use `shim.record` and added ability to invoke an after hook with callback args ([#2207](https://github.com/newrelic/node-newrelic/pull/2207)) ([4f48fc3](https://github.com/newrelic/node-newrelic/commit/4f48fc3bbd5afce4954019620b112f600b2dfb53))
|
|
10
|
+
|
|
11
|
+
#### Documentation
|
|
12
|
+
|
|
13
|
+
* Updated compatibility report ([#2223](https://github.com/newrelic/node-newrelic/pull/2223)) ([a256ca0](https://github.com/newrelic/node-newrelic/commit/a256ca0f2060efe576018527d37718a041ffc925))
|
|
14
|
+
|
|
15
|
+
#### Miscellaneous chores
|
|
16
|
+
|
|
17
|
+
* Removed outdated Slack reference ([#2198](https://github.com/newrelic/node-newrelic/pull/2198)) ([8110d42](https://github.com/newrelic/node-newrelic/commit/8110d426f402659d44bf786fec0503ca2413ee6b))
|
|
18
|
+
* Removed package-lock.json ([#2208](https://github.com/newrelic/node-newrelic/pull/2208)) ([b267695](https://github.com/newrelic/node-newrelic/commit/b26769502b4cb38f9133f76f427ee96ce718c15b))
|
|
19
|
+
* Removed unused express5 feature flag ([#2197](https://github.com/newrelic/node-newrelic/pull/2197)) ([366504b](https://github.com/newrelic/node-newrelic/commit/366504ba1e3bfed477a37be5d61f4e30e46b690d))
|
|
20
|
+
|
|
21
|
+
#### Tests
|
|
22
|
+
|
|
23
|
+
* Updated langchain versioned tests to separate the vectorstore and other tests. This is to avoid peer resolution of `@langchain/community` package that is being used to test the elasticsearch vectorstore ([#2216](https://github.com/newrelic/node-newrelic/pull/2216)) ([e768955](https://github.com/newrelic/node-newrelic/commit/e7689554aec2a038d5b80c54d4b6b603075856ac))
|
|
24
|
+
* Fixed aws-sdk-v3 bedrock tests ([#2211](https://github.com/newrelic/node-newrelic/pull/2211)) ([050469e](https://github.com/newrelic/node-newrelic/commit/050469ecc59ccc9ba6a6e78527ac392f262ff939))
|
|
25
|
+
* Fixed aws-sdk-v3 bedrock tests (again) ([#2212](https://github.com/newrelic/node-newrelic/pull/2212)) ([330cc4b](https://github.com/newrelic/node-newrelic/commit/330cc4b6ff8e3777b1dfa0fda7f5b4c5b20005af))
|
|
26
|
+
|
|
27
|
+
#### Continuous integration
|
|
28
|
+
|
|
29
|
+
* Updated the langchain vectorstore test to reference the correct version of `@langchain/core` getting tested ([#2202](https://github.com/newrelic/node-newrelic/pull/2202)) ([ed81852](https://github.com/newrelic/node-newrelic/commit/ed81852a4b3c582a54c0d274ba9d5887041ebeef))
|
|
30
|
+
* Added updating of docs site with compatibility table ([#2205](https://github.com/newrelic/node-newrelic/pull/2205)) ([c28a938](https://github.com/newrelic/node-newrelic/commit/c28a9387f68feb8fa59d4134828662b3babeb9d0))
|
|
31
|
+
* Fixed CI jobs ([#2215](https://github.com/newrelic/node-newrelic/pull/2215)) ([8b030fb](https://github.com/newrelic/node-newrelic/commit/8b030fbf479cd348e9b75544bc753c1d618bfca7))
|
|
32
|
+
* Fixed should-run CI step ([#2214](https://github.com/newrelic/node-newrelic/pull/2214)) ([d0a481d](https://github.com/newrelic/node-newrelic/commit/d0a481d4b58706c4793fa12fa7706091eaffa0a4))
|
|
33
|
+
|
|
1
34
|
### v11.17.0 (2024-05-15)
|
|
2
35
|
|
|
3
36
|
#### Features
|
package/lib/feature_flags.js
CHANGED
|
@@ -7,7 +7,10 @@
|
|
|
7
7
|
|
|
8
8
|
// unreleased flags gating an active feature
|
|
9
9
|
exports.prerelease = {
|
|
10
|
-
|
|
10
|
+
// internal_test_only is used for testing our feature flag implementation.
|
|
11
|
+
// It is not used to gate any features.
|
|
12
|
+
internal_test_only: false,
|
|
13
|
+
|
|
11
14
|
promise_segments: false,
|
|
12
15
|
reverse_naming_rules: false,
|
|
13
16
|
undici_async_tracking: true,
|
|
@@ -21,6 +21,10 @@ module.exports = function initialize(_agent, redis, _moduleName, shim) {
|
|
|
21
21
|
const client = original.apply(this, arguments)
|
|
22
22
|
client[opts] = getRedisParams(client.options)
|
|
23
23
|
CMDS_TO_INSTRUMENT.forEach(instrumentClientCommand.bind(null, shim, client))
|
|
24
|
+
if (client.options.legacyMode) {
|
|
25
|
+
client.v4[opts] = getRedisParams(client.options)
|
|
26
|
+
CMDS_TO_INSTRUMENT.forEach(instrumentClientCommand.bind(null, shim, client.v4))
|
|
27
|
+
}
|
|
24
28
|
return client
|
|
25
29
|
}
|
|
26
30
|
})
|
|
@@ -266,18 +266,20 @@ function wrapModel(shim, Model, promiseMode) {
|
|
|
266
266
|
destinationName: shim.FIRST,
|
|
267
267
|
callback: setCallback(shim, promiseMode),
|
|
268
268
|
promise: promiseMode,
|
|
269
|
-
|
|
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
|
+
|
|
270
275
|
// the message is the param when using the promised based model
|
|
271
|
-
message = promiseMode ?
|
|
276
|
+
const message = promiseMode ? result : args?.[1]
|
|
272
277
|
if (!message) {
|
|
273
278
|
shim.logger.trace('No results from consume.')
|
|
274
279
|
return null
|
|
275
280
|
}
|
|
276
281
|
const parameters = getParametersFromMessage(message)
|
|
277
|
-
|
|
278
|
-
const headers = message?.properties?.headers
|
|
279
|
-
|
|
280
|
-
return { parameters, headers }
|
|
282
|
+
shim.copySegmentParameters(segment, parameters)
|
|
281
283
|
}
|
|
282
284
|
})
|
|
283
285
|
)
|
|
@@ -312,12 +314,10 @@ function wrapModel(shim, Model, promiseMode) {
|
|
|
312
314
|
* Extracts the appropriate messageHandler parameters for the consume method.
|
|
313
315
|
*
|
|
314
316
|
* @param {Shim} shim instance of shim
|
|
315
|
-
* @param {object} _consumer not used
|
|
316
|
-
* @param {string} _name not used
|
|
317
317
|
* @param {Array} args arguments passed to the consume method
|
|
318
318
|
* @returns {object} message params
|
|
319
319
|
*/
|
|
320
|
-
function describeMessage(shim,
|
|
320
|
+
function describeMessage(shim, args) {
|
|
321
321
|
const [message] = args
|
|
322
322
|
|
|
323
323
|
if (!message?.properties) {
|
|
@@ -197,8 +197,7 @@ function getBedrockSpec({ commandName }, shim, _original, _name, args) {
|
|
|
197
197
|
return new RecorderSpec({
|
|
198
198
|
promise: true,
|
|
199
199
|
name: `Llm/${modelType}/Bedrock/${commandName}`,
|
|
200
|
-
|
|
201
|
-
after: (shim, _fn, _fnName, err, response, segment) => {
|
|
200
|
+
after: ({ shim, error: err, result: response, segment }) => {
|
|
202
201
|
const passThroughParams = {
|
|
203
202
|
shim,
|
|
204
203
|
err,
|
|
@@ -16,7 +16,7 @@ function initialize(agent, inspector, name, shim) {
|
|
|
16
16
|
shim.wrap(sessionProto, 'post', function wrapPost(shim, fn) {
|
|
17
17
|
return function wrappedPost() {
|
|
18
18
|
const args = shim.argsToArray.apply(shim, arguments)
|
|
19
|
-
shim.bindCallbackSegment(args, shim.LAST)
|
|
19
|
+
shim.bindCallbackSegment(null, args, shim.LAST)
|
|
20
20
|
return fn.apply(this, args)
|
|
21
21
|
}
|
|
22
22
|
})
|
|
@@ -61,8 +61,7 @@ function instrumentInvokeChain({ langchain, shim }) {
|
|
|
61
61
|
return new RecorderSpec({
|
|
62
62
|
name: `${LANGCHAIN.CHAIN}/${fnName}`,
|
|
63
63
|
promise: true,
|
|
64
|
-
|
|
65
|
-
after(_shim, _fn, _name, err, output, segment) {
|
|
64
|
+
after({ error: err, result: output, segment }) {
|
|
66
65
|
recordChatCompletionEvents({
|
|
67
66
|
segment,
|
|
68
67
|
messages: [output],
|
|
@@ -97,8 +96,7 @@ function instrumentStream({ langchain, shim }) {
|
|
|
97
96
|
return new RecorderSpec({
|
|
98
97
|
name: `${LANGCHAIN.CHAIN}/${fnName}`,
|
|
99
98
|
promise: true,
|
|
100
|
-
|
|
101
|
-
after(_shim, _fn, _name, err, output, segment) {
|
|
99
|
+
after({ error: err, result: output, segment }) {
|
|
102
100
|
// Input error occurred which means a stream was not created.
|
|
103
101
|
// Skip instrumenting streaming and create Llm Events from
|
|
104
102
|
// the data we have
|
|
@@ -31,8 +31,7 @@ module.exports = function initialize(shim, tools) {
|
|
|
31
31
|
return new RecorderSpec({
|
|
32
32
|
name: `${LANGCHAIN.TOOL}/${name}`,
|
|
33
33
|
promise: true,
|
|
34
|
-
|
|
35
|
-
after(_shim, _fn, _name, err, output, segment) {
|
|
34
|
+
after({ error: err, result: output, segment }) {
|
|
36
35
|
const metadata = mergeMetadata(instanceMeta, paramsMeta)
|
|
37
36
|
const tags = mergeTags(instanceTags, paramsTags)
|
|
38
37
|
segment.end()
|
|
@@ -89,8 +89,7 @@ module.exports = function initialize(shim, vectorstores) {
|
|
|
89
89
|
return new RecorderSpec({
|
|
90
90
|
name: `${LANGCHAIN.VECTORSTORE}/${fnName}`,
|
|
91
91
|
promise: true,
|
|
92
|
-
|
|
93
|
-
after(_shim, _fn, _name, err, output, segment) {
|
|
92
|
+
after({ error: err, result: output, segment }) {
|
|
94
93
|
if (!output) {
|
|
95
94
|
// If we get an error, it is possible that `output = null`.
|
|
96
95
|
// In that case, we define it to be an empty array.
|
|
@@ -76,7 +76,7 @@ module.exports = function initialize(agent, memcached, moduleName, shim) {
|
|
|
76
76
|
return new OperationSpec({
|
|
77
77
|
name: metacall.type || 'Unknown',
|
|
78
78
|
callback: function wrapCallback(shim, fn, fnName, opSegment) {
|
|
79
|
-
shim.bindCallbackSegment(metacall, 'callback', opSegment)
|
|
79
|
+
shim.bindCallbackSegment(null, metacall, 'callback', opSegment)
|
|
80
80
|
},
|
|
81
81
|
parameters
|
|
82
82
|
})
|
|
@@ -262,8 +262,7 @@ module.exports = function initialize(agent, openai, moduleName, shim) {
|
|
|
262
262
|
return new RecorderSpec({
|
|
263
263
|
name: OPENAI.COMPLETION,
|
|
264
264
|
promise: true,
|
|
265
|
-
|
|
266
|
-
after(_shim, _fn, _name, err, response, segment) {
|
|
265
|
+
after({ error: err, result: response, segment }) {
|
|
267
266
|
if (request.stream) {
|
|
268
267
|
instrumentStream({ agent, shim, request, response, segment })
|
|
269
268
|
} else {
|
|
@@ -294,8 +293,7 @@ module.exports = function initialize(agent, openai, moduleName, shim) {
|
|
|
294
293
|
return new RecorderSpec({
|
|
295
294
|
name: OPENAI.EMBEDDING,
|
|
296
295
|
promise: true,
|
|
297
|
-
|
|
298
|
-
after(_shim, _fn, _name, err, response, segment) {
|
|
296
|
+
after({ error: err, result: response, segment }) {
|
|
299
297
|
addLlmMeta({ agent, segment })
|
|
300
298
|
|
|
301
299
|
if (!response) {
|
|
@@ -49,7 +49,7 @@ function registerInternalSendCommand(shim, proto) {
|
|
|
49
49
|
parameters,
|
|
50
50
|
callback: function bindCallback(shim, _f, _n, segment) {
|
|
51
51
|
if (shim.isFunction(commandObject.callback)) {
|
|
52
|
-
shim.bindCallbackSegment(commandObject, 'callback', segment)
|
|
52
|
+
shim.bindCallbackSegment(null, commandObject, 'callback', segment)
|
|
53
53
|
} else {
|
|
54
54
|
const self = this
|
|
55
55
|
commandObject.callback = shim.bindSegment(
|
|
@@ -87,9 +87,9 @@ function registerSendCommand(shim, proto) {
|
|
|
87
87
|
callback: function bindCallback(shim, _f, _n, segment) {
|
|
88
88
|
const last = args[args.length - 1]
|
|
89
89
|
if (shim.isFunction(last)) {
|
|
90
|
-
shim.bindCallbackSegment(args, shim.LAST, segment)
|
|
90
|
+
shim.bindCallbackSegment(null, args, shim.LAST, segment)
|
|
91
91
|
} else if (shim.isArray(last) && shim.isFunction(last[last.length - 1])) {
|
|
92
|
-
shim.bindCallbackSegment(last, shim.LAST, segment)
|
|
92
|
+
shim.bindCallbackSegment(null, last, shim.LAST, segment)
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
})
|
|
@@ -50,7 +50,7 @@ function wrapCallback(shim, callback) {
|
|
|
50
50
|
return function wrappedCallback() {
|
|
51
51
|
const segment = shim.getSegment(this)
|
|
52
52
|
if (segment && segment.transaction.isActive()) {
|
|
53
|
-
shim.bindCallbackSegment(this, '_callback', segment)
|
|
53
|
+
shim.bindCallbackSegment(null, this, '_callback', segment)
|
|
54
54
|
}
|
|
55
55
|
return callback.apply(this, arguments)
|
|
56
56
|
}
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
|
-
const TraceSegment = require('../../transaction/trace/segment')
|
|
8
7
|
const genericRecorder = require('../../metrics/recorders/generic')
|
|
9
8
|
const { _nameMessageSegment } = require('./common')
|
|
10
9
|
const specs = require('../specs')
|
|
@@ -25,7 +24,7 @@ module.exports = createRecorder
|
|
|
25
24
|
function updateSpecFromArgs({ shim, fn, fnName, args, spec }) {
|
|
26
25
|
let msgDesc = null
|
|
27
26
|
if (shim.isFunction(spec)) {
|
|
28
|
-
msgDesc = spec
|
|
27
|
+
msgDesc = spec(shim, fn, fnName, args)
|
|
29
28
|
} else {
|
|
30
29
|
msgDesc = spec
|
|
31
30
|
const destIdx = shim.normalizeIndex(args.length, spec.destinationName)
|
|
@@ -37,81 +36,6 @@ function updateSpecFromArgs({ shim, fn, fnName, args, spec }) {
|
|
|
37
36
|
return msgDesc
|
|
38
37
|
}
|
|
39
38
|
|
|
40
|
-
/**
|
|
41
|
-
* Binds the consumer callback to the active segment.
|
|
42
|
-
*
|
|
43
|
-
* @private
|
|
44
|
-
* @param {object} params to function
|
|
45
|
-
* @param {MessageShim} params.shim instance of shim
|
|
46
|
-
* @param {Array} params.args arguments passed to original consume function
|
|
47
|
-
* @param {specs.MessageSpec} params.msgDesc spec for the wrapped consume function
|
|
48
|
-
* @param {TraceSegment} params.segment active segment to bind callback
|
|
49
|
-
* @param {boolean} params.getParams flag to copy message parameters to segment
|
|
50
|
-
* @param {Function} params.resHandler function to handle response from callback to obtain the message parameters
|
|
51
|
-
*/
|
|
52
|
-
function bindCallback({ shim, args, msgDesc, segment, getParams, resHandler }) {
|
|
53
|
-
const cbIdx = shim.normalizeIndex(args.length, msgDesc.callback)
|
|
54
|
-
if (cbIdx !== null) {
|
|
55
|
-
shim.bindCallbackSegment(args, cbIdx, segment)
|
|
56
|
-
|
|
57
|
-
// If we have a callback and a results handler, then wrap the callback so
|
|
58
|
-
// we can call the results handler and get the message properties.
|
|
59
|
-
if (resHandler) {
|
|
60
|
-
shim.wrap(args, cbIdx, function wrapCb(shim, cb, cbName) {
|
|
61
|
-
if (shim.isFunction(cb)) {
|
|
62
|
-
return function cbWrapper() {
|
|
63
|
-
const cbArgs = shim.argsToArray.apply(shim, arguments)
|
|
64
|
-
const msgProps = resHandler.call(this, shim, cb, cbName, cbArgs)
|
|
65
|
-
if (getParams && msgProps && msgProps.parameters) {
|
|
66
|
-
shim.copySegmentParameters(segment, msgProps.parameters)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return cb.apply(this, arguments)
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
})
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Binds the consumer function to the async context and checks return to possibly
|
|
79
|
-
* bind the promise
|
|
80
|
-
*
|
|
81
|
-
* @private
|
|
82
|
-
* @param {object} params to function
|
|
83
|
-
* @param {MessageShim} params.shim instance of shim
|
|
84
|
-
* @param {Function} params.fn consumer function
|
|
85
|
-
* @param {string} params.fnName name of function
|
|
86
|
-
* @param {Array} params.args arguments passed to original consume function
|
|
87
|
-
* @param {specs.MessageSpec} params.msgDesc spec for the wrapped consume function
|
|
88
|
-
* @param {TraceSegment} params.segment active segment to bind callback
|
|
89
|
-
* @param {boolean} params.getParams flag to copy message parameters to segment
|
|
90
|
-
* @param {Function} params.resHandler function to handle response from callback to obtain the message parameters
|
|
91
|
-
* @returns {Promise|*} response from consume function
|
|
92
|
-
*/
|
|
93
|
-
function bindConsumer({ shim, fn, fnName, args, msgDesc, segment, getParams, resHandler }) {
|
|
94
|
-
// Call the method in the context of our segment.
|
|
95
|
-
let ret = shim.applySegment(fn, segment, true, this, args)
|
|
96
|
-
|
|
97
|
-
if (ret && msgDesc.promise && shim.isPromise(ret)) {
|
|
98
|
-
ret = shim.bindPromise(ret, segment)
|
|
99
|
-
|
|
100
|
-
// Intercept the promise to handle the result.
|
|
101
|
-
if (resHandler) {
|
|
102
|
-
ret = ret.then(function interceptValue(res) {
|
|
103
|
-
const msgProps = resHandler.call(this, shim, fn, fnName, res)
|
|
104
|
-
if (getParams && msgProps && msgProps.parameters) {
|
|
105
|
-
shim.copySegmentParameters(segment, msgProps.parameters)
|
|
106
|
-
}
|
|
107
|
-
return res
|
|
108
|
-
})
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return ret
|
|
113
|
-
}
|
|
114
|
-
|
|
115
39
|
/**
|
|
116
40
|
*
|
|
117
41
|
* @private
|
|
@@ -119,48 +43,14 @@ function bindConsumer({ shim, fn, fnName, args, msgDesc, segment, getParams, res
|
|
|
119
43
|
* @param {MessageShim} params.shim instance of shim
|
|
120
44
|
* @param {Function} params.fn function that is being wrapped
|
|
121
45
|
* @param {string} params.fnName name of function
|
|
46
|
+
* @param params.args
|
|
122
47
|
* @param {specs.MessageSpec} params.spec spec for the wrapped consume function
|
|
123
|
-
* @returns {
|
|
48
|
+
* @returns {specs.MessageSpec} updated spec with logic to name segment and apply the genericRecorder
|
|
124
49
|
*/
|
|
125
|
-
function createRecorder({ shim, fn, fnName,
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Process the message args.
|
|
134
|
-
const args = shim.argsToArray.apply(shim, arguments)
|
|
135
|
-
const msgDesc = updateSpecFromArgs.call(this, { shim, fn, fnName, args, spec })
|
|
136
|
-
|
|
137
|
-
// Make the segment if we can.
|
|
138
|
-
if (!msgDesc) {
|
|
139
|
-
shim.logger.trace('Not recording consume, no message descriptor.')
|
|
140
|
-
return fn.apply(this, args)
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const name = _nameMessageSegment(shim, msgDesc, shim._metrics.CONSUME)
|
|
144
|
-
|
|
145
|
-
// Adds details needed by createSegment when used with a spec
|
|
146
|
-
msgDesc.name = name
|
|
147
|
-
msgDesc.recorder = genericRecorder
|
|
148
|
-
msgDesc.parent = parent
|
|
149
|
-
|
|
150
|
-
const segment = shim.createSegment(msgDesc)
|
|
151
|
-
const getParams = shim.agent.config.message_tracer.segment_parameters.enabled
|
|
152
|
-
const resHandler = shim.isFunction(msgDesc.messageHandler) ? msgDesc.messageHandler : null
|
|
153
|
-
|
|
154
|
-
bindCallback({ shim, args, msgDesc, segment, getParams, resHandler })
|
|
155
|
-
return bindConsumer.call(this, {
|
|
156
|
-
shim,
|
|
157
|
-
fn,
|
|
158
|
-
fnName,
|
|
159
|
-
args,
|
|
160
|
-
msgDesc,
|
|
161
|
-
segment,
|
|
162
|
-
getParams,
|
|
163
|
-
resHandler
|
|
164
|
-
})
|
|
165
|
-
}
|
|
50
|
+
function createRecorder({ spec, shim, fn, fnName, args }) {
|
|
51
|
+
const msgDesc = updateSpecFromArgs({ shim, fn, fnName, args, spec })
|
|
52
|
+
// Adds details needed by createSegment when used with a spec
|
|
53
|
+
msgDesc.name = _nameMessageSegment(shim, msgDesc, shim._metrics.CONSUME)
|
|
54
|
+
msgDesc.recorder = genericRecorder
|
|
55
|
+
return msgDesc
|
|
166
56
|
}
|
|
@@ -287,17 +287,8 @@ function recordConsume(nodule, properties, spec) {
|
|
|
287
287
|
properties = null
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
// original wrapped consume function.
|
|
293
|
-
// TODO: https://github.com/newrelic/node-newrelic/issues/981
|
|
294
|
-
return this.wrap(nodule, properties, function wrapConsume(shim, fn, fnName) {
|
|
295
|
-
if (!shim.isFunction(fn)) {
|
|
296
|
-
shim.logger.debug('Not wrapping %s (%s) as consume', fn, fnName)
|
|
297
|
-
return fn
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
return createRecorder({ shim, fn, fnName, spec })
|
|
290
|
+
return this.record(nodule, properties, function wrapConsume(shim, fn, fnName, args) {
|
|
291
|
+
return createRecorder({ spec, shim, fn, fnName, args })
|
|
301
292
|
})
|
|
302
293
|
}
|
|
303
294
|
|
|
@@ -84,12 +84,12 @@ function makeWrapConsumer({ spec, queue, destinationName, destNameIsArg }) {
|
|
|
84
84
|
spec.queue = queue
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
return function wrapConsumer(shim, consumer
|
|
87
|
+
return function wrapConsumer(shim, consumer) {
|
|
88
88
|
if (!shim.isFunction(consumer)) {
|
|
89
89
|
return consumer
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
const consumerWrapper = createConsumerWrapper({ shim, consumer,
|
|
92
|
+
const consumerWrapper = createConsumerWrapper({ shim, consumer, spec })
|
|
93
93
|
return shim.bindCreateTransaction(
|
|
94
94
|
consumerWrapper,
|
|
95
95
|
new specs.TransactionSpec({
|
|
@@ -108,10 +108,9 @@ function makeWrapConsumer({ spec, queue, destinationName, destNameIsArg }) {
|
|
|
108
108
|
* @param {MessageShim} params.shim instance of shim
|
|
109
109
|
* @param {specs.MessageSubscribeSpec} params.spec spec for function
|
|
110
110
|
* @param {Function} params.consumer function for consuming message
|
|
111
|
-
* @param {string} params.cName name of consumer function
|
|
112
111
|
* @returns {Function} handler for the transaction being created
|
|
113
112
|
*/
|
|
114
|
-
function createConsumerWrapper({ shim, spec, consumer
|
|
113
|
+
function createConsumerWrapper({ shim, spec, consumer }) {
|
|
115
114
|
return function createConsumeTrans() {
|
|
116
115
|
// If there is no transaction or we're in a pre-existing transaction,
|
|
117
116
|
// then don't do anything. Note that the latter should never happen.
|
|
@@ -123,7 +122,7 @@ function createConsumerWrapper({ shim, spec, consumer, cName }) {
|
|
|
123
122
|
return consumer.apply(this, args)
|
|
124
123
|
}
|
|
125
124
|
|
|
126
|
-
const msgDesc = spec.messageHandler.call(this, shim,
|
|
125
|
+
const msgDesc = spec.messageHandler.call(this, shim, args)
|
|
127
126
|
|
|
128
127
|
// If message could not be handled, immediately kill this transaction.
|
|
129
128
|
if (!msgDesc) {
|
package/lib/shim/shim.js
CHANGED
|
@@ -799,12 +799,13 @@ function _applyRecorderSegment({ segment, ctx, args, segDesc, shim, fn, name })
|
|
|
799
799
|
return ret.then(
|
|
800
800
|
function onThen(val) {
|
|
801
801
|
segment.touch()
|
|
802
|
-
|
|
802
|
+
// passing in error as some instrumentation checks if it's not equal to `null`
|
|
803
|
+
segDesc.after({ shim, fn, name, error, result: val, segment })
|
|
803
804
|
return val
|
|
804
805
|
},
|
|
805
806
|
function onCatch(err) {
|
|
806
807
|
segment.touch()
|
|
807
|
-
segDesc.after(shim, fn, name, err,
|
|
808
|
+
segDesc.after({ shim, fn, name, error: err, segment })
|
|
808
809
|
throw err // NOTE: This is not an error from our instrumentation.
|
|
809
810
|
}
|
|
810
811
|
)
|
|
@@ -815,7 +816,7 @@ function _applyRecorderSegment({ segment, ctx, args, segDesc, shim, fn, name })
|
|
|
815
816
|
throw err // Just rethrowing this error, not our error!
|
|
816
817
|
} finally {
|
|
817
818
|
if (segDesc.after && (error || !promised)) {
|
|
818
|
-
segDesc.after(shim, fn, name, error, ret, segment)
|
|
819
|
+
segDesc.after({ shim, fn, name, error, result: ret, segment })
|
|
819
820
|
}
|
|
820
821
|
}
|
|
821
822
|
}
|
|
@@ -977,10 +978,11 @@ function bindSegment(nodule, property, segment, full) {
|
|
|
977
978
|
* Replaces the callback in an arguments array with one that has been bound to
|
|
978
979
|
* the given segment.
|
|
979
980
|
*
|
|
980
|
-
* - `bindCallbackSegment(args, cbIdx [, segment])`
|
|
981
|
-
* - `bindCallbackSegment(obj, property [, segment])`
|
|
981
|
+
* - `bindCallbackSegment(spec, args, cbIdx [, segment])`
|
|
982
|
+
* - `bindCallbackSegment(spec, obj, property [, segment])`
|
|
982
983
|
*
|
|
983
984
|
* @memberof Shim.prototype
|
|
985
|
+
* @param {Spec} spec spec to original wrapped function, used to call after method with arguments passed to callback
|
|
984
986
|
* @param {Array | object} args
|
|
985
987
|
* The arguments array to pull the cb from.
|
|
986
988
|
* @param {number|string} cbIdx
|
|
@@ -990,7 +992,7 @@ function bindSegment(nodule, property, segment, full) {
|
|
|
990
992
|
* currently active segment.
|
|
991
993
|
* @see Shim#bindSegment
|
|
992
994
|
*/
|
|
993
|
-
function bindCallbackSegment(args, cbIdx, parentSegment) {
|
|
995
|
+
function bindCallbackSegment(spec, args, cbIdx, parentSegment) {
|
|
994
996
|
if (!args) {
|
|
995
997
|
return
|
|
996
998
|
}
|
|
@@ -1009,35 +1011,59 @@ function bindCallbackSegment(args, cbIdx, parentSegment) {
|
|
|
1009
1011
|
cbIdx = normalizedCBIdx
|
|
1010
1012
|
}
|
|
1011
1013
|
|
|
1012
|
-
//
|
|
1014
|
+
// Make sure cb is function before wrapping
|
|
1015
|
+
if (this.isFunction(args[cbIdx])) {
|
|
1016
|
+
wrapCallback({ shim: this, args, cbIdx, parentSegment, spec })
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
/**
|
|
1021
|
+
* Wraps the callback and creates a segment for the callback function.
|
|
1022
|
+
* It will also call an after hook with the arguments passed to callback
|
|
1023
|
+
*
|
|
1024
|
+
* @private
|
|
1025
|
+
* @param {Object} params to function
|
|
1026
|
+
* @param {Shim} params.shim instance of shim
|
|
1027
|
+
* @param {Array | object} params.args
|
|
1028
|
+
* The arguments array to pull the cb from.
|
|
1029
|
+
* @param {number|string} params.cbIdx
|
|
1030
|
+
* The index of the callback.
|
|
1031
|
+
* @param {TraceSegment} [params.parentSegment]
|
|
1032
|
+
* The segment to use as the callback segment's parent. Defaults to the
|
|
1033
|
+
* currently active segment.
|
|
1034
|
+
* @param {Spec} params.spec spec to original wrapped function, used to call after method with arguments passed to callback
|
|
1035
|
+
*
|
|
1036
|
+
*/
|
|
1037
|
+
function wrapCallback({ shim, args, cbIdx, parentSegment, spec }) {
|
|
1013
1038
|
const cb = args[cbIdx]
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
})
|
|
1028
|
-
)
|
|
1029
|
-
|
|
1030
|
-
if (segment) {
|
|
1031
|
-
segment.async = false
|
|
1032
|
-
}
|
|
1039
|
+
const realParent = parentSegment || shim.getSegment()
|
|
1040
|
+
args[cbIdx] = shim.wrap(cb, null, function callbackWrapper(shim, fn, name) {
|
|
1041
|
+
return function wrappedCallback() {
|
|
1042
|
+
if (realParent) {
|
|
1043
|
+
realParent.opaque = false
|
|
1044
|
+
}
|
|
1045
|
+
const segment = _rawCreateSegment(
|
|
1046
|
+
shim,
|
|
1047
|
+
new specs.SegmentSpec({
|
|
1048
|
+
name: 'Callback: ' + name,
|
|
1049
|
+
parent: realParent
|
|
1050
|
+
})
|
|
1051
|
+
)
|
|
1033
1052
|
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
return shim.applySegment(cb, segment, true, this, arguments)
|
|
1053
|
+
if (segment) {
|
|
1054
|
+
segment.async = false
|
|
1037
1055
|
}
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1056
|
+
|
|
1057
|
+
if (spec?.after) {
|
|
1058
|
+
spec.after({ shim, fn, name, args: arguments, segment: realParent })
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
// CB may end the transaction so update the parent's time preemptively.
|
|
1062
|
+
realParent && realParent.touch()
|
|
1063
|
+
return shim.applySegment(cb, segment, true, this, arguments)
|
|
1064
|
+
}
|
|
1065
|
+
})
|
|
1066
|
+
shim.storeSegment(args[cbIdx], realParent)
|
|
1041
1067
|
}
|
|
1042
1068
|
|
|
1043
1069
|
/**
|
|
@@ -1792,7 +1818,7 @@ function _bindAllCallbacks(shim, fn, name, args, spec) {
|
|
|
1792
1818
|
_bindCallback({
|
|
1793
1819
|
context: this,
|
|
1794
1820
|
callback: spec.spec.callback,
|
|
1795
|
-
binder: shim.bindCallbackSegment,
|
|
1821
|
+
binder: shim.bindCallbackSegment.bind(shim, spec.spec),
|
|
1796
1822
|
shim,
|
|
1797
1823
|
fn,
|
|
1798
1824
|
args,
|
|
@@ -1806,7 +1832,7 @@ function _bindAllCallbacks(shim, fn, name, args, spec) {
|
|
|
1806
1832
|
_bindCallback({
|
|
1807
1833
|
context: this,
|
|
1808
1834
|
callback: spec.spec.rowCallback,
|
|
1809
|
-
binder: shim
|
|
1835
|
+
binder: shim?.bindRowCallbackSegment || shim?.bindCallbackSegment?.bind(shim, spec.spec),
|
|
1810
1836
|
shim,
|
|
1811
1837
|
fn,
|
|
1812
1838
|
args,
|
|
@@ -1954,7 +1980,7 @@ function wrapStreamListeners({ stream, shim, segment, specEvent }) {
|
|
|
1954
1980
|
return function wrappedOn(onEvent) {
|
|
1955
1981
|
if (onEvent !== specEvent && (onEvent === 'end' || onEvent === 'error')) {
|
|
1956
1982
|
const args = argsToArray.apply(shim, arguments)
|
|
1957
|
-
shim.bindCallbackSegment(args, shim.LAST, segment)
|
|
1983
|
+
shim.bindCallbackSegment(specEvent, args, shim.LAST, segment)
|
|
1958
1984
|
return fn.apply(this, args)
|
|
1959
1985
|
}
|
|
1960
1986
|
return fn.apply(this, arguments)
|
|
@@ -24,14 +24,17 @@ const WrapSpec = require('./wrap')
|
|
|
24
24
|
* The instrumented function must have been invoked synchronously.
|
|
25
25
|
*
|
|
26
26
|
* @typedef {Function} SpecAfterFunction
|
|
27
|
-
* @param {
|
|
28
|
-
* @param {
|
|
27
|
+
* @param {Object} params params to function
|
|
28
|
+
* @param {object} params.shim The shim used to instrument the external library.
|
|
29
|
+
* @param {Function} params.fn The function/method from the external library being
|
|
29
30
|
* instrumented.
|
|
30
|
-
* @param {string} name The name of the current function.
|
|
31
|
-
* @param {Error|null} error If the instrumented function threw an error, this
|
|
32
|
-
* will be that error.
|
|
33
|
-
* @param {
|
|
34
|
-
* @param {
|
|
31
|
+
* @param {string} params.name The name of the current function.
|
|
32
|
+
* @param {Error|null} [params.error] If the instrumented function threw an error, this
|
|
33
|
+
* will be that error. In the case of a callback this will be omitted.
|
|
34
|
+
* @param {Array} [params.args] arguments passed to a callback function getting instrumented.
|
|
35
|
+
* @param {*} [params.result] The result returned by the instrumented function. In the case of a wrapped
|
|
36
|
+
* callback, the data needed is in `params.args`.
|
|
37
|
+
* @param {TraceSegment} params.segment The segment used while instrumenting the
|
|
35
38
|
* function.
|
|
36
39
|
*/
|
|
37
40
|
|
|
@@ -176,10 +176,10 @@ function middlewareWithCallbackRecorder({ spec, typeDetails, metricName, isError
|
|
|
176
176
|
parent: txInfo.segmentStack[txInfo.segmentStack.length - 1],
|
|
177
177
|
recorder,
|
|
178
178
|
parameters: params,
|
|
179
|
-
after: function afterExec(shim,
|
|
180
|
-
const errIsError = isError(shim,
|
|
179
|
+
after: function afterExec({ shim, error }) {
|
|
180
|
+
const errIsError = isError(shim, error)
|
|
181
181
|
if (errIsError) {
|
|
182
|
-
assignError(txInfo,
|
|
182
|
+
assignError(txInfo, error)
|
|
183
183
|
} else if (!nextWrapper && !isErrorWare && spec.appendPath) {
|
|
184
184
|
txInfo.transaction.nameState.popPath(route)
|
|
185
185
|
}
|
|
@@ -243,12 +243,12 @@ function middlewareWithPromiseRecorder({ spec, typeDetails, metricName, isErrorW
|
|
|
243
243
|
callback: nextWrapper,
|
|
244
244
|
recorder,
|
|
245
245
|
parameters: params,
|
|
246
|
-
after: function afterExec(shim,
|
|
246
|
+
after: function afterExec({ shim, error, result }) {
|
|
247
247
|
if (shim._responsePredicate(args, result)) {
|
|
248
248
|
txInfo.transaction.nameState.freeze()
|
|
249
249
|
}
|
|
250
|
-
if (isError(shim,
|
|
251
|
-
assignError(txInfo,
|
|
250
|
+
if (isError(shim, error)) {
|
|
251
|
+
assignError(txInfo, error)
|
|
252
252
|
} else {
|
|
253
253
|
txInfo.errorHandled = true
|
|
254
254
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "newrelic",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.18.0",
|
|
4
4
|
"author": "New Relic Node.js agent team <nodejs@newrelic.com>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"contributors": [
|
|
@@ -161,7 +161,6 @@
|
|
|
161
161
|
"prepare-test": "npm run ssl && npm run docker-env",
|
|
162
162
|
"lint": "eslint ./*.{js,mjs} lib test bin examples",
|
|
163
163
|
"lint:fix": "eslint --fix, ./*.{js,mjs} lib test bin examples",
|
|
164
|
-
"lint:lockfile": "lockfile-lint --path package-lock.json --type npm --allowed-hosts npm --validate-https --validate-integrity",
|
|
165
164
|
"public-docs": "jsdoc -c ./jsdoc-conf.jsonc && cp examples/shim/*.png out/",
|
|
166
165
|
"publish-docs": "./bin/publish-docs.sh",
|
|
167
166
|
"services": "docker compose up -d --wait",
|