newrelic 11.22.0 → 11.23.1

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 CHANGED
@@ -1,5 +1,42 @@
1
+ ### v11.23.1 (2024-07-11)
2
+
3
+ #### Bug fixes
4
+
5
+ * Updated redis v4 instrumentation to work with transactions(multi/exec) ([#2343](https://github.com/newrelic/node-newrelic/pull/2343)) ([39eb842](https://github.com/newrelic/node-newrelic/commit/39eb8421b84f7fe298acf5c9c89de31ee0cc2604))
6
+
7
+ #### Documentation
8
+
9
+ * Updated compatibility report ([#2342](https://github.com/newrelic/node-newrelic/pull/2342)) ([5c9e3e6](https://github.com/newrelic/node-newrelic/commit/5c9e3e6bfa8a388c7dd071ecb0231b069f065645))
10
+
11
+ ### v11.23.0 (2024-07-10)
12
+
13
+ #### Features
14
+
15
+ * Added support for account level governance of AI Monitoring ([#2326](https://github.com/newrelic/node-newrelic/pull/2326)) ([7069335](https://github.com/newrelic/node-newrelic/commit/7069335bfee38b1774da00bdbb63138ebf38da90))
16
+
17
+ #### Code refactoring
18
+
19
+ * Removed redundant isExpected in the Exception class ([#2328](https://github.com/newrelic/node-newrelic/pull/2328)) ([38f9825](https://github.com/newrelic/node-newrelic/commit/38f982564c0e0b93f17146be8beed005f9405ead))
20
+ * Reduced duplication in the error-collector ([#2323](https://github.com/newrelic/node-newrelic/pull/2323)) ([10581bf](https://github.com/newrelic/node-newrelic/commit/10581bf8cdad5c61c25dc1309ad97ca36d58cf79))
21
+ * Refactored benchmark tests to complete async functions ([#2334](https://github.com/newrelic/node-newrelic/pull/2334)) ([57a4dfb](https://github.com/newrelic/node-newrelic/commit/57a4dfb77c0408cbd81291c71db770005a0f2b5a))
22
+
23
+ #### Documentation
24
+
25
+ * Included commands and links for Mac setup ([#2327](https://github.com/newrelic/node-newrelic/pull/2327)) ([6eddb72](https://github.com/newrelic/node-newrelic/commit/6eddb721b676b246e5ace28bea75c6cd723d5ddb))
26
+ * Updated compatibility report ([#2318](https://github.com/newrelic/node-newrelic/pull/2318)) ([3a910ef](https://github.com/newrelic/node-newrelic/commit/3a910ef29c76cfd05903f01fb84d6775f8669578))
27
+
28
+ #### Miscellaneous chores
29
+
30
+ * Fixed copy paste error in post release workflow ([#2329](https://github.com/newrelic/node-newrelic/pull/2329)) ([6f2da7a](https://github.com/newrelic/node-newrelic/commit/6f2da7a2a07ce699f8d6ef859b4a90f0bd68df15))
31
+ * Implemented split jobs for post release docs publishing ([#2319](https://github.com/newrelic/node-newrelic/pull/2319)) ([c14ec3b](https://github.com/newrelic/node-newrelic/commit/c14ec3b7020f43f6515609346f3b2f9586e63430))
32
+
33
+ #### Tests
34
+
35
+ * Fixed recordMiddlewawre benchmark test ([#2338](https://github.com/newrelic/node-newrelic/pull/2338)) ([fb55ac7](https://github.com/newrelic/node-newrelic/commit/fb55ac7e19a26c76d19ead169664e40e0df4b822))
36
+
1
37
  ### v11.22.0 (2024-06-28)
2
38
 
39
+
3
40
  #### Features
4
41
 
5
42
  * Added support for Node 22([#2305](https://github.com/newrelic/node-newrelic/pull/2305)) ([0bf8908](https://github.com/newrelic/node-newrelic/commit/0bf89081a59fe598b22613257f519c171149c454))
@@ -306,6 +306,12 @@ Config.prototype._fromServer = function _fromServer(params, key) {
306
306
  case 'high_security':
307
307
  break
308
308
 
309
+ // interpret AI Monitoring account setting
310
+ case 'collect_ai':
311
+ this._disableOption(params.collect_ai, 'ai_monitoring')
312
+ this.emit('change', this)
313
+ break
314
+
309
315
  // always accept these settings
310
316
  case 'cross_process_id':
311
317
  case 'encoding_key':
@@ -1071,10 +1077,10 @@ function setFromEnv({ config, key, envVar, formatter, paths }) {
1071
1077
  /**
1072
1078
  * Recursively visit the nodes of the config definition and look for environment variable names, overriding any configuration values that are found.
1073
1079
  *
1074
- * @param {object} [config=this] The current level of the configuration object.
1075
- * @param {object} [data=configDefinition] The current level of the config definition object.
1076
- * @param {Array} [paths=[]] keeps track of the nested path to properly derive the env var
1077
- * @param {number} [objectKeys=1] indicator of how many keys exist in current node to know when to remove current node after all keys are processed
1080
+ * @param {object} [config] The current level of the configuration object.
1081
+ * @param {object} [data] The current level of the config definition object.
1082
+ * @param {Array} [paths] keeps track of the nested path to properly derive the env var
1083
+ * @param {number} [objectKeys] indicator of how many keys exist in current node to know when to remove current node after all keys are processed
1078
1084
  */
1079
1085
  Config.prototype._fromEnvironment = function _fromEnvironment(
1080
1086
  config = this,
@@ -89,75 +89,62 @@ class ErrorCollector {
89
89
  }
90
90
 
91
91
  /**
92
- * Helper method for processing errors that are created with .noticeError()
92
+ * Gets the iterable property from the transaction based on the error type
93
93
  *
94
94
  * @param {Transaction} transaction the collected exception's transaction
95
- * @param {number} collectedErrors the number of errors we've successfully .collect()-ed
96
- * @param {number} expectedErrors the number of errors marked as expected in noticeError
97
- * @returns {Array.<number>} the updated [collectedErrors, expectedErrors] numbers post-processing
95
+ * @param {string} errorType the type of error: "user", "transactionException", "transaction"
96
+ * @returns {object[]} the iterable property from the transaction based on the error type
98
97
  */
99
- _processUserErrors(transaction, collectedErrors, expectedErrors) {
100
- if (transaction.userErrors.length) {
101
- for (let i = 0; i < transaction.userErrors.length; i++) {
102
- const exception = transaction.userErrors[i]
103
- if (this.collect(transaction, exception)) {
104
- ++collectedErrors
105
- // if we could collect it, then check if expected
106
- if (
107
- urltils.isExpectedError(this.config, transaction.statusCode) ||
108
- errorHelper.isExpectedException(transaction, exception, this.config, urltils)
109
- ) {
110
- ++expectedErrors
111
- }
112
- }
113
- }
98
+ _getIterableProperty(transaction, errorType) {
99
+ let iterableProperty = null
100
+ if (errorType === 'user') {
101
+ iterableProperty = transaction.userErrors
114
102
  }
115
-
116
- return [collectedErrors, expectedErrors]
103
+ if (errorType === 'transactionException') {
104
+ iterableProperty = transaction.exceptions
105
+ }
106
+ return iterableProperty
117
107
  }
118
108
 
119
109
  /**
120
- * Helper method for processing exceptions on the transaction (transaction.exceptions array)
110
+ * Helper method for processing errors that are created with .noticeError(), exceptions
111
+ * on the transaction (transaction.exceptions array), and inferred errors based on Transaction metadata.
121
112
  *
122
- * @param {Transaction} transaction the transaction being processed
123
- * @param {number} collectedErrors the number of errors successfully .collect()-ed
124
- * @param {number} expectedErrors the number of collected errors that were expected
125
- * @returns {Array.<number>} the updated [collectedErrors, expectedErrors] numbers post-processing
113
+ * @param {Transaction} transaction the collected exception's transaction
114
+ * @param {number} collectedErrors the number of errors we've successfully .collect()-ed
115
+ * @param {number} expectedErrors the number of errors marked as expected in noticeError
116
+ * @param {string} errorType the type of error to be processed; "user", "transactionException", "transaction"
117
+ * @returns {Array.<number>} the updated [collectedErrors, expectedErrors] numbers post processing
126
118
  */
127
- _processTransactionExceptions(transaction, collectedErrors, expectedErrors) {
128
- for (let i = 0; i < transaction.exceptions.length; i++) {
129
- const exception = transaction.exceptions[i]
130
- if (this.collect(transaction, exception)) {
131
- ++collectedErrors
132
- // if we could collect it, then check if expected
133
- if (
134
- urltils.isExpectedError(this.config, transaction.statusCode) ||
135
- errorHelper.isExpectedException(transaction, exception, this.config, urltils)
136
- ) {
137
- ++expectedErrors
119
+ _processErrors(transaction, collectedErrors, expectedErrors, errorType) {
120
+ const iterableProperty = this._getIterableProperty(transaction, errorType)
121
+ if (iterableProperty === null && errorType === 'transaction') {
122
+ if (this.collect(transaction)) {
123
+ collectedErrors++
124
+ if (urltils.isExpectedError(this.config, transaction.statusCode)) {
125
+ expectedErrors++
138
126
  }
139
127
  }
128
+ return [collectedErrors, expectedErrors]
140
129
  }
141
130
 
142
- return [collectedErrors, expectedErrors]
143
- }
131
+ if (iterableProperty === null) {
132
+ return [collectedErrors, expectedErrors]
133
+ }
144
134
 
145
- /**
146
- * Helper method for processing an inferred error based on Transaction metadata
147
- *
148
- * @param {Transaction} transaction the transaction being processed
149
- * @param {number} collectedErrors the number of errors successfully .collect()-ed
150
- * @param {number} expectedErrors the number of collected errors that were expected
151
- * @returns {Array.<number>} the updated [collectedErrors, expectedErrors] numbers post-processing
152
- */
153
- _processTransactionErrors(transaction, collectedErrors, expectedErrors) {
154
- if (this.collect(transaction)) {
155
- ++collectedErrors
156
- if (urltils.isExpectedError(this.config, transaction.statusCode)) {
157
- ++expectedErrors
135
+ for (let i = 0; i < iterableProperty.length; i++) {
136
+ const exception = iterableProperty[i]
137
+ if (!this.collect(transaction, exception)) {
138
+ continue
139
+ }
140
+ collectedErrors++
141
+ if (
142
+ urltils.isExpectedError(this.config, transaction.statusCode) ||
143
+ errorHelper.isExpectedException(transaction, exception, this.config, urltils)
144
+ ) {
145
+ expectedErrors++
158
146
  }
159
147
  }
160
-
161
148
  return [collectedErrors, expectedErrors]
162
149
  }
163
150
 
@@ -183,10 +170,11 @@ class ErrorCollector {
183
170
 
184
171
  // errors from noticeError are currently exempt from
185
172
  // ignore and exclude rules
186
- ;[collectedErrors, expectedErrors] = this._processUserErrors(
173
+ ;[collectedErrors, expectedErrors] = this._processErrors(
187
174
  transaction,
188
175
  collectedErrors,
189
- expectedErrors
176
+ expectedErrors,
177
+ 'user'
190
178
  )
191
179
 
192
180
  const isErroredTransaction = urltils.isError(this.config, transaction.statusCode)
@@ -194,16 +182,18 @@ class ErrorCollector {
194
182
 
195
183
  // collect other exceptions only if status code is not ignored
196
184
  if (transaction.exceptions.length && !isIgnoredErrorStatusCode) {
197
- ;[collectedErrors, expectedErrors] = this._processTransactionExceptions(
185
+ ;[collectedErrors, expectedErrors] = this._processErrors(
198
186
  transaction,
199
187
  collectedErrors,
200
- expectedErrors
188
+ expectedErrors,
189
+ 'transactionException'
201
190
  )
202
191
  } else if (isErroredTransaction) {
203
- ;[collectedErrors, expectedErrors] = this._processTransactionErrors(
192
+ ;[collectedErrors, expectedErrors] = this._processErrors(
204
193
  transaction,
205
194
  collectedErrors,
206
- expectedErrors
195
+ expectedErrors,
196
+ 'transaction'
207
197
  )
208
198
  }
209
199
 
@@ -31,19 +31,18 @@ class Exception {
31
31
 
32
32
  getErrorDetails(config) {
33
33
  const errorDetails = errorHelper.extractErrorInformation(null, this.error, config)
34
- errorDetails.expected = this.isExpected(config, errorDetails)
35
-
36
- return errorDetails
37
- }
38
-
39
- isExpected(config, { type, message }) {
40
34
  if (typeof this._expected === 'undefined') {
41
- this._expected =
42
- errorHelper.isExpectedErrorClass(config, type) ||
43
- errorHelper.isExpectedErrorMessage(config, type, message)
35
+ this._expected = errorHelper.isExpected(
36
+ errorDetails.type,
37
+ errorDetails.message,
38
+ null,
39
+ config,
40
+ urltils
41
+ )
44
42
  }
43
+ errorDetails.expected = this._expected
45
44
 
46
- return this._expected
45
+ return errorDetails
47
46
  }
48
47
  }
49
48
 
@@ -7,63 +7,78 @@
7
7
 
8
8
  const {
9
9
  OperationSpec,
10
- params: { DatastoreParameters }
10
+ params: { DatastoreParameters },
11
+ ClassWrapSpec
11
12
  } = require('../../shim/specs')
12
- const CLIENT_COMMANDS = ['select', 'quit', 'SELECT', 'QUIT']
13
- const opts = Symbol('clientOptions')
13
+ const { redisClientOpts } = require('../../symbols')
14
14
 
15
15
  module.exports = function initialize(_agent, redis, _moduleName, shim) {
16
16
  shim.setDatastore(shim.REDIS)
17
- const COMMANDS = Object.keys(shim.require('dist/lib/client/commands.js').default)
18
- const CMDS_TO_INSTRUMENT = [...COMMANDS, ...CLIENT_COMMANDS]
19
- shim.wrap(redis, 'createClient', function wrapCreateClient(shim, original) {
20
- return function wrappedCreateClient() {
21
- const client = original.apply(this, arguments)
22
- client[opts] = getRedisParams(client.options)
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))
17
+ const commandsQueue = shim.require('dist/lib/client/commands-queue.js')
18
+
19
+ shim.wrapClass(
20
+ commandsQueue,
21
+ 'default',
22
+ new ClassWrapSpec({
23
+ post: function postConstructor(shim) {
24
+ instrumentAddCommand({ shim, commandsQueue: this })
27
25
  }
26
+ })
27
+ )
28
+
29
+ shim.wrap(redis, 'createClient', function wrapCreateClient(_shim, createClient) {
30
+ return function wrappedCreateClient(options) {
31
+ // saving connection opts to shim
32
+ // since the RedisCommandsQueue gets constructed at createClient
33
+ // we can delete the symbol afterwards to ensure the appropriate
34
+ // connection options are for the given RedisCommandsQueue
35
+ shim[redisClientOpts] = getRedisParams(options)
36
+ const client = createClient.apply(this, arguments)
37
+ delete shim[redisClientOpts]
28
38
  return client
29
39
  }
30
40
  })
31
41
  }
32
42
 
33
43
  /**
34
- * Instruments a given command on the client by calling `shim.recordOperation`
44
+ * Instruments a given command when added to the command queue by calling `shim.recordOperation`
35
45
  *
36
- * @param {Shim} shim shim instance
37
- * @param {object} client redis client instance
38
- * @param {string} cmd command to instrument
46
+ * @param {object} params
47
+ * @param {Shim} params.shim shim instance
48
+ * @param {object} params.commandsQueue instance
39
49
  */
40
- function instrumentClientCommand(shim, client, cmd) {
50
+ function instrumentAddCommand({ shim, commandsQueue }) {
41
51
  const { agent } = shim
52
+ const clientOpts = shim[redisClientOpts]
42
53
 
43
- shim.recordOperation(client, cmd, function wrapCommand(_shim, _fn, _fnName, args) {
44
- const [key, value] = args
45
- const parameters = Object.assign({}, client[opts])
46
- // If selecting a database, subsequent commands
47
- // will be using said database, update the clientOptions
48
- // but not the current parameters(feature parity with v3)
49
- if (cmd.toLowerCase() === 'select') {
50
- client[opts].database_name = key
51
- }
52
- if (agent.config.attributes.enabled) {
53
- if (key) {
54
- parameters.key = JSON.stringify(key)
54
+ shim.recordOperation(
55
+ commandsQueue,
56
+ 'addCommand',
57
+ function wrapAddCommand(_shim, _fn, _fnName, args) {
58
+ const [cmd, key, value] = args[0]
59
+ const parameters = Object.assign({}, clientOpts)
60
+ // If selecting a database, subsequent commands
61
+ // will be using said database, update the clientOpts
62
+ // but not the current parameters(feature parity with v3)
63
+ if (cmd.toLowerCase() === 'select') {
64
+ clientOpts.database_name = key
55
65
  }
56
- if (value) {
57
- parameters.value = JSON.stringify(value)
66
+ if (agent.config.attributes.enabled) {
67
+ if (key) {
68
+ parameters.key = JSON.stringify(key)
69
+ }
70
+ if (value) {
71
+ parameters.value = JSON.stringify(value)
72
+ }
58
73
  }
59
- }
60
74
 
61
- return new OperationSpec({
62
- name: (cmd && cmd.toLowerCase()) || 'other',
63
- parameters,
64
- promise: true
65
- })
66
- })
75
+ return new OperationSpec({
76
+ name: (cmd && cmd.toLowerCase()) || 'other',
77
+ parameters,
78
+ promise: true
79
+ })
80
+ }
81
+ )
67
82
  }
68
83
 
69
84
  /**
@@ -73,6 +88,21 @@ function instrumentClientCommand(shim, client, cmd) {
73
88
  * @returns {object} params
74
89
  */
75
90
  function getRedisParams(clientOpts) {
91
+ // need to replicate logic done in RedisClient
92
+ // to parse the url to assign to socket.host/port
93
+ // see: https://github.com/redis/node-redis/blob/5576a0db492cda2cd88e09881bc330aa956dd0f5/packages/client/lib/client/index.ts#L160
94
+ if (clientOpts?.url) {
95
+ const parsedURL = new URL(clientOpts.url)
96
+ clientOpts.socket = { host: parsedURL.hostname }
97
+ if (parsedURL.port) {
98
+ clientOpts.socket.port = parsedURL.port
99
+ }
100
+
101
+ if (parsedURL.pathname) {
102
+ clientOpts.database = parsedURL.pathname.substring(1)
103
+ }
104
+ }
105
+
76
106
  return new DatastoreParameters({
77
107
  host: clientOpts?.socket?.host || 'localhost',
78
108
  port_path_or_id: clientOpts?.socket?.path || clientOpts?.socket?.port || '6379',
@@ -85,8 +85,21 @@ function addLlmMeta({ agent, segment }) {
85
85
  * @param {BedrockCommand} params.bedrockCommand parsed input
86
86
  * @param {Error|null} params.err error from request if exists
87
87
  * @param params.bedrockResponse
88
+ * @param params.shim
88
89
  */
89
- function recordChatCompletionMessages({ agent, segment, bedrockCommand, bedrockResponse, err }) {
90
+ function recordChatCompletionMessages({
91
+ agent,
92
+ shim,
93
+ segment,
94
+ bedrockCommand,
95
+ bedrockResponse,
96
+ err
97
+ }) {
98
+ if (shouldSkipInstrumentation(agent.config) === true) {
99
+ shim.logger.debug('skipping sending of ai data')
100
+ return
101
+ }
102
+
90
103
  const summary = new LlmChatCompletionSummary({
91
104
  agent,
92
105
  bedrockResponse,
@@ -133,12 +146,18 @@ function recordChatCompletionMessages({ agent, segment, bedrockCommand, bedrockR
133
146
  *
134
147
  * @param {object} params function params
135
148
  * @param {object} params.agent instance of agent
149
+ * @param {object} params.shim current shim instance
136
150
  * @param {object} params.segment active segment
137
151
  * @param {BedrockCommand} params.bedrockCommand parsed input
138
152
  * @param {Error|null} params.err error from request if exists
139
153
  * @param params.bedrockResponse
140
154
  */
141
- function recordEmbeddingMessage({ agent, segment, bedrockCommand, bedrockResponse, err }) {
155
+ function recordEmbeddingMessage({ agent, shim, segment, bedrockCommand, bedrockResponse, err }) {
156
+ if (shouldSkipInstrumentation(agent.config) === true) {
157
+ shim.logger.debug('skipping sending of ai data')
158
+ return
159
+ }
160
+
142
161
  const embedding = new LlmEmbedding({
143
162
  agent,
144
163
  segment,
@@ -239,6 +258,7 @@ function handleResponse({ shim, err, response, segment, bedrockCommand, modelTyp
239
258
  if (modelType === 'completion') {
240
259
  recordChatCompletionMessages({
241
260
  agent,
261
+ shim,
242
262
  segment,
243
263
  bedrockCommand,
244
264
  bedrockResponse,
@@ -247,6 +267,7 @@ function handleResponse({ shim, err, response, segment, bedrockCommand, modelTyp
247
267
  } else if (modelType === 'embedding') {
248
268
  recordEmbeddingMessage({
249
269
  agent,
270
+ shim,
250
271
  segment,
251
272
  bedrockCommand,
252
273
  bedrockResponse,
@@ -16,13 +16,14 @@ const LlmErrorMessage = require('../../llm-events/error-message')
16
16
  const { DESTINATIONS } = require('../../config/attribute-filter')
17
17
  const { langchainRunId } = require('../../symbols')
18
18
  const { RecorderSpec } = require('../../shim/specs')
19
+ const { shouldSkipInstrumentation } = require('./common')
19
20
 
20
21
  module.exports = function initialize(shim, langchain) {
21
22
  const { agent, pkgVersion } = shim
22
23
 
23
24
  if (common.shouldSkipInstrumentation(agent.config)) {
24
25
  shim.logger.debug(
25
- 'langchain instrumentation is disabled. To enable set `config.ai_monitoring.enabled` to true'
26
+ 'langchain instrumentation is disabled. To enable set `config.ai_monitoring.enabled` to true'
26
27
  )
27
28
  return
28
29
  }
@@ -186,6 +187,15 @@ function wrapNextHandler({ shim, output, segment, request, metadata, tags }) {
186
187
  function recordChatCompletionEvents({ segment, messages, events, metadata, tags, err, shim }) {
187
188
  const { pkgVersion, agent } = shim
188
189
  segment.end()
190
+
191
+ if (shouldSkipInstrumentation(shim.agent.config) === true) {
192
+ // We need this check inside the wrapper because it is possible for monitoring
193
+ // to be disabled at the account level. In such a case, the value is set
194
+ // after the instrumentation has been initialized.
195
+ shim.logger.debug('skipping sending of ai data')
196
+ return
197
+ }
198
+
189
199
  const completionSummary = new LangChainCompletionSummary({
190
200
  agent,
191
201
  messages,
@@ -198,6 +208,7 @@ function recordChatCompletionEvents({ segment, messages, events, metadata, tags,
198
208
 
199
209
  common.recordEvent({
200
210
  agent,
211
+ shim,
201
212
  type: 'LlmChatCompletionSummary',
202
213
  pkgVersion,
203
214
  msg: completionSummary
@@ -266,6 +277,7 @@ function recordCompletions({ events, completionSummary, agent, segment, shim })
266
277
 
267
278
  common.recordEvent({
268
279
  agent,
280
+ shim,
269
281
  type: 'LlmChatCompletionMessage',
270
282
  pkgVersion: shim.pkgVersion,
271
283
  msg: completionMsg
@@ -35,6 +35,15 @@ module.exports = function initialize(shim, tools) {
35
35
  const metadata = mergeMetadata(instanceMeta, paramsMeta)
36
36
  const tags = mergeTags(instanceTags, paramsTags)
37
37
  segment.end()
38
+
39
+ if (shouldSkipInstrumentation(shim.agent.config) === true) {
40
+ // We need this check inside the wrapper because it is possible for monitoring
41
+ // to be disabled at the account level. In such a case, the value is set
42
+ // after the instrumentation has been initialized.
43
+ shim.logger.debug('skipping sending of ai data')
44
+ return
45
+ }
46
+
38
47
  const toolEvent = new LangChainTool({
39
48
  agent,
40
49
  description,
@@ -47,7 +56,7 @@ module.exports = function initialize(shim, tools) {
47
56
  segment,
48
57
  error: err != null
49
58
  })
50
- recordEvent({ agent, type: 'LlmTool', pkgVersion, msg: toolEvent })
59
+ recordEvent({ agent, shim, type: 'LlmTool', pkgVersion, msg: toolEvent })
51
60
 
52
61
  if (err) {
53
62
  agent.errors.add(
@@ -23,11 +23,12 @@ const LlmErrorMessage = require('../../llm-events/error-message')
23
23
  * @param {number} params.k vector search top k
24
24
  * @param {object} params.output vector search documents
25
25
  * @param {Agent} params.agent NR agent instance
26
+ * @param {Shim} params.shim current shim instance
26
27
  * @param {TraceSegment} params.segment active segment from vector search
27
28
  * @param {string} params.pkgVersion langchain version
28
- * @param {err} params.err if it exists
29
+ * @param {Error} params.err if it exists
29
30
  */
30
- function recordVectorSearch({ request, k, output, agent, segment, pkgVersion, err }) {
31
+ function recordVectorSearch({ request, k, output, agent, shim, segment, pkgVersion, err }) {
31
32
  const vectorSearch = new LangChainVectorSearch({
32
33
  agent,
33
34
  segment,
@@ -37,7 +38,7 @@ function recordVectorSearch({ request, k, output, agent, segment, pkgVersion, er
37
38
  error: err !== null
38
39
  })
39
40
 
40
- recordEvent({ agent, type: 'LlmVectorSearch', pkgVersion, msg: vectorSearch })
41
+ recordEvent({ agent, shim, type: 'LlmVectorSearch', pkgVersion, msg: vectorSearch })
41
42
 
42
43
  output.forEach((document, sequence) => {
43
44
  const vectorSearchResult = new LangChainVectorSearchResult({
@@ -51,6 +52,7 @@ function recordVectorSearch({ request, k, output, agent, segment, pkgVersion, er
51
52
 
52
53
  recordEvent({
53
54
  agent,
55
+ shim,
54
56
  type: 'LlmVectorSearchResult',
55
57
  pkgVersion,
56
58
  msg: vectorSearchResult
@@ -97,7 +99,15 @@ module.exports = function initialize(shim, vectorstores) {
97
99
  }
98
100
 
99
101
  segment.end()
100
- recordVectorSearch({ request, k, output, agent, segment, pkgVersion, err })
102
+ if (shouldSkipInstrumentation(shim.agent.config) === true) {
103
+ // We need this check inside the wrapper because it is possible for monitoring
104
+ // to be disabled at the account level. In such a case, the value is set
105
+ // after the instrumentation has been initialized.
106
+ shim.logger.debug('skipping sending of ai data')
107
+ return
108
+ }
109
+
110
+ recordVectorSearch({ request, k, output, agent, shim, segment, pkgVersion, err })
101
111
 
102
112
  segment.transaction.trace.attributes.addAttribute(DESTINATIONS.TRANS_EVENT, 'llm', true)
103
113
  }
@@ -99,12 +99,18 @@ function addLlmMeta({ agent, segment }) {
99
99
  *
100
100
  * @param {object} params input params
101
101
  * @param {Agent} params.agent NR agent instance
102
+ * @param {Shim} params.shim the current shim instance
102
103
  * @param {TraceSegment} params.segment active segment from chat completion
103
104
  * @param {object} params.request chat completion params
104
105
  * @param {object} params.response chat completion response
105
106
  * @param {boolean} [params.err] err if it exists
106
107
  */
107
- function recordChatCompletionMessages({ agent, segment, request, response, err }) {
108
+ function recordChatCompletionMessages({ agent, shim, segment, request, response, err }) {
109
+ if (shouldSkipInstrumentation(agent.config, shim) === true) {
110
+ shim.logger.debug('skipping sending of ai data')
111
+ return
112
+ }
113
+
108
114
  if (!response) {
109
115
  // If we get an error, it is possible that `response = null`.
110
116
  // In that case, we define it to be an empty object.
@@ -195,6 +201,7 @@ function instrumentStream({ agent, shim, request, response, segment }) {
195
201
 
196
202
  recordChatCompletionMessages({
197
203
  agent: shim.agent,
204
+ shim,
198
205
  segment,
199
206
  request,
200
207
  response: chunk,
@@ -205,6 +212,7 @@ function instrumentStream({ agent, shim, request, response, segment }) {
205
212
  })
206
213
  }
207
214
 
215
+ /* eslint-disable sonarjs/cognitive-complexity */
208
216
  module.exports = function initialize(agent, openai, moduleName, shim) {
209
217
  if (shouldSkipInstrumentation(agent.config, shim)) {
210
218
  shim.logger.debug(
@@ -268,6 +276,7 @@ module.exports = function initialize(agent, openai, moduleName, shim) {
268
276
  } else {
269
277
  recordChatCompletionMessages({
270
278
  agent,
279
+ shim,
271
280
  segment,
272
281
  request,
273
282
  response,
@@ -301,10 +310,20 @@ module.exports = function initialize(agent, openai, moduleName, shim) {
301
310
  // In that case, we define it to be an empty object.
302
311
  response = {}
303
312
  }
313
+
314
+ segment.end()
315
+ if (shouldSkipInstrumentation(shim.agent.config, shim) === true) {
316
+ // We need this check inside the wrapper because it is possible for monitoring
317
+ // to be disabled at the account level. In such a case, the value is set
318
+ // after the instrumentation has been initialized.
319
+ shim.logger.debug('skipping sending of ai data')
320
+ return
321
+ }
322
+
304
323
  response.headers = segment[openAiHeaders]
305
324
  // explicitly end segment to get consistent duration
306
325
  // for both LLM events and the segment
307
- segment.end()
326
+
308
327
  const embedding = new LlmEmbedding({
309
328
  agent,
310
329
  segment,
package/lib/symbols.js CHANGED
@@ -27,6 +27,7 @@ module.exports = {
27
27
  langchainRunId: Symbol('runId'),
28
28
  prismaConnection: Symbol('prismaConnection'),
29
29
  prismaModelCall: Symbol('modelCall'),
30
+ redisClientOpts: Symbol('clientOptions'),
30
31
  segment: Symbol('segment'),
31
32
  shim: Symbol('shim'),
32
33
  storeDatabase: Symbol('storeDatabase'),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "newrelic",
3
- "version": "11.22.0",
3
+ "version": "11.23.1",
4
4
  "author": "New Relic Node.js agent team <nodejs@newrelic.com>",
5
5
  "license": "Apache-2.0",
6
6
  "contributors": [