newrelic 13.6.2 → 13.6.3

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 (46) hide show
  1. package/NEWS.md +29 -11
  2. package/README.md +6 -11
  3. package/lib/config/default.js +46 -4
  4. package/lib/config/index.js +110 -1
  5. package/lib/instrumentation/@google/genai.js +15 -24
  6. package/lib/instrumentations.js +0 -1
  7. package/lib/llm-events/aws-bedrock/bedrock-response.js +25 -1
  8. package/lib/llm-events/aws-bedrock/chat-completion-message.js +2 -10
  9. package/lib/llm-events/aws-bedrock/chat-completion-summary.js +11 -15
  10. package/lib/llm-events/aws-bedrock/converse-stream-handler.js +11 -4
  11. package/lib/llm-events/aws-bedrock/embedding.js +3 -20
  12. package/lib/llm-events/aws-bedrock/event.js +3 -20
  13. package/lib/llm-events/aws-bedrock/stream-handler.js +21 -28
  14. package/lib/llm-events/aws-bedrock/utils.js +1 -59
  15. package/lib/llm-events/event.js +108 -0
  16. package/lib/llm-events/google-genai/chat-completion-message.js +3 -10
  17. package/lib/llm-events/google-genai/chat-completion-summary.js +4 -5
  18. package/lib/llm-events/google-genai/embedding.js +0 -34
  19. package/lib/llm-events/google-genai/event.js +7 -0
  20. package/lib/llm-events/openai/chat-completion-message.js +3 -9
  21. package/lib/llm-events/openai/chat-completion-summary.js +4 -5
  22. package/lib/llm-events/openai/embedding.js +4 -15
  23. package/lib/llm-events/openai/event.js +7 -0
  24. package/lib/shim/datastore-shim.js +5 -7
  25. package/lib/subscriber-configs.js +2 -0
  26. package/lib/subscribers/mysql/config.js +73 -0
  27. package/lib/subscribers/mysql/connection-query.js +56 -0
  28. package/lib/subscribers/mysql/helper.js +102 -0
  29. package/lib/subscribers/mysql/pool-get-connection.js +20 -0
  30. package/lib/subscribers/mysql/pool-namespace-query.js +19 -0
  31. package/lib/subscribers/mysql/pool-query.js +41 -0
  32. package/lib/subscribers/mysql2/config.js +127 -0
  33. package/lib/subscribers/mysql2/connection-execute.js +18 -0
  34. package/lib/subscribers/mysql2/connection-query.js +17 -0
  35. package/lib/subscribers/mysql2/pool-get-connection.js +20 -0
  36. package/lib/subscribers/mysql2/pool-namespace-query.js +19 -0
  37. package/lib/subscribers/mysql2/pool-query.js +19 -0
  38. package/lib/subscribers/openai/utils.js +11 -2
  39. package/lib/subscribers/pg/query.js +1 -1
  40. package/package.json +1 -1
  41. package/lib/db/utils.js +0 -19
  42. package/lib/instrumentation/mysql/mysql.js +0 -333
  43. package/lib/instrumentation/mysql/nr-hooks.js +0 -26
  44. package/lib/llm-events/google-genai/utils.js +0 -32
  45. package/lib/llm-events/openai/utils.js +0 -34
  46. package/lib/llm-events/utils.js +0 -110
@@ -1,333 +0,0 @@
1
- /*
2
- * Copyright 2020 New Relic Corporation. All rights reserved.
3
- * SPDX-License-Identifier: Apache-2.0
4
- */
5
-
6
- 'use strict'
7
-
8
- const dbutils = require('../../db/utils')
9
- const properties = require('../../util/properties')
10
- const symbols = require('../../symbols')
11
- const { QuerySpec } = require('../../shim/specs')
12
- const DatastoreParameters = require('../../shim/specs/params/datastore')
13
-
14
- /**
15
- * Used to instrument `mysql` and `mysql2` packages
16
- * the `mysql2/promise` instrumentation is below in `promiseInitialize`
17
- *
18
- * @param {Shim} shim instance of shim
19
- * @param {object} mysql package to instrument
20
- */
21
- function callbackInitialize(shim, mysql) {
22
- shim.setDatastore(shim.MYSQL)
23
- shim[symbols.wrappedPoolConnection] = false
24
-
25
- shim.wrapReturn(mysql, 'createConnection', wrapCreateConnection)
26
- shim.wrapReturn(mysql, 'createPool', wrapCreatePool)
27
- shim.wrapReturn(mysql, 'createPoolCluster', wrapCreatePoolCluster)
28
- }
29
-
30
- /**
31
- * Used to instrument `mysql2/promise`
32
- *
33
- * @param {Shim} shim instance of shim
34
- * @param {object} mysql2 package to instrument
35
- */
36
- function promiseInitialize(shim, mysql2) {
37
- shim.setDatastore(shim.MYSQL)
38
- shim[symbols.wrappedPoolConnection] = false
39
- shim.wrap(
40
- mysql2,
41
- 'createConnection',
42
- function wrapPromiseCreateConnection(shim, createConnection) {
43
- return async function wrappedPromiseCreateConnection() {
44
- const promiseConnection = await createConnection.apply(this, arguments)
45
- wrapCreateConnection(
46
- shim,
47
- createConnection,
48
- 'createConnection',
49
- promiseConnection.connection
50
- )
51
- return promiseConnection
52
- }
53
- }
54
- )
55
-
56
- shim.wrap(mysql2, 'createPool', function wrapPromiseCreatePool(shim, createPool) {
57
- return function wrappedPromiseCreatePool() {
58
- const promisePool = createPool.apply(this, arguments)
59
- wrapCreatePool(shim, createPool, 'createPool', promisePool.pool)
60
- return promisePool
61
- }
62
- })
63
-
64
- shim.wrap(
65
- mysql2,
66
- 'createPoolCluster',
67
- function wrapPromiseCreatePoolCluster(shim, createPoolCluster) {
68
- return function wrappedPromiseCreatePoolCluster() {
69
- const promisePoolCluster = createPoolCluster.apply(this, arguments)
70
- wrapCreatePoolCluster(
71
- shim,
72
- createPoolCluster,
73
- 'createPoolCluster',
74
- promisePoolCluster.poolCluster
75
- )
76
- return promisePoolCluster
77
- }
78
- }
79
- )
80
- }
81
-
82
- function wrapCreateConnection(shim, fn, fnName, connection) {
83
- if (shim[symbols.unwrapConnection]) {
84
- return
85
- }
86
- shim.logger.debug('Wrapping Connection#query')
87
- if (wrapQueryable(shim, connection, false)) {
88
- const connProto = Object.getPrototypeOf(connection)
89
- connProto[symbols.storeDatabase] = true
90
- shim[symbols.unwrapConnection] = true
91
- }
92
- }
93
-
94
- function wrapCreatePool(shim, fn, fnName, pool) {
95
- if (shim[symbols.unwrapPool]) {
96
- return
97
- }
98
- shim.logger.debug('Wrapping Pool#query and Pool#getConnection')
99
- if (wrapQueryable(shim, pool, true) && wrapGetConnection(shim, pool)) {
100
- shim[symbols.unwrapPool] = true
101
- }
102
- }
103
-
104
- function wrapCreatePoolCluster(shim, fn, fnName, poolCluster) {
105
- if (shim[symbols.createPoolCluster]) {
106
- return
107
- }
108
- shim.logger.debug('Wrapping PoolCluster#of')
109
- const proto = Object.getPrototypeOf(poolCluster)
110
- shim.wrapReturn(proto, 'of', wrapPoolClusterOf)
111
- function wrapPoolClusterOf(shim, of, _n, poolNamespace) {
112
- if (poolNamespace[symbols.clusterOf]) {
113
- return
114
- }
115
-
116
- if (wrapGetConnection(shim, poolNamespace) && wrapQueryable(shim, poolNamespace, false)) {
117
- poolNamespace[symbols.clusterOf] = true
118
- }
119
- }
120
-
121
- shim.logger.debug('Wrapping PoolCluster#getConnection')
122
- if (wrapGetConnection(shim, poolCluster)) {
123
- shim[symbols.createPoolCluster] = true
124
- }
125
- }
126
-
127
- function wrapGetConnection(shim, connectable) {
128
- if (!connectable || !connectable.getConnection || shim.isWrapped(connectable.getConnection)) {
129
- shim.logger.trace(
130
- {
131
- connectable: !!connectable,
132
- getConnection: !!(connectable && connectable.getConnection),
133
- isWrapped: !!(connectable && shim.isWrapped(connectable.getConnection))
134
- },
135
- 'Not wrapping getConnection'
136
- )
137
- return false
138
- }
139
-
140
- const proto = Object.getPrototypeOf(connectable)
141
- shim.wrap(proto, 'getConnection', function doWrapGetConnection(shim, fn) {
142
- return function wrappedGetConnection() {
143
- const args = shim.toArray(arguments)
144
- const cbIdx = args.length - 1
145
-
146
- // avoid an infinite loop and check both the cb and the "original" cb before re-wrapping
147
- // this is only applicable now with the security agent + us doing the same thing
148
- const original = shim.getOriginalOnce(args[cbIdx])
149
- if (
150
- shim.isFunction(args[cbIdx]) &&
151
- !(shim.isWrapped(args[cbIdx]) || shim.isWrapped(original))
152
- ) {
153
- shim.logger.trace(
154
- {
155
- hasSegment: !!shim.getSegment()
156
- },
157
- 'Wrapping callback with segment'
158
- )
159
- let cb = args[cbIdx]
160
- if (!shim[symbols.wrappedPoolConnection]) {
161
- cb = shim.wrap(cb, wrapGetConnectionCallback)
162
- }
163
- args[cbIdx] = shim.bindSegment(cb)
164
- }
165
- return fn.apply(this, args)
166
- }
167
- })
168
-
169
- return true
170
- }
171
-
172
- function wrapGetConnectionCallback(shim, cb) {
173
- return function wrappedGetConnectionCallback(err, conn) {
174
- try {
175
- shim.logger.debug('Wrapping PoolConnection#query')
176
- if (!err && wrapQueryable(shim, conn, false)) {
177
- // Leave getConnection wrapped in order to maintain TX state, but we can
178
- // simplify the wrapping of its callback in future calls.
179
- shim[symbols.wrappedPoolConnection] = true
180
- }
181
- } catch (_err) {
182
- shim.logger.debug(
183
- { error: _err },
184
- 'Attempt to wrap PoolConnection#query resulted in thrown error'
185
- )
186
- }
187
- return cb.apply(this, arguments)
188
- }
189
- }
190
-
191
- function wrapQueryable(shim, queryable, isPoolQuery) {
192
- if (!queryable || !queryable.query || shim.isWrapped(queryable.query)) {
193
- shim.logger.debug(
194
- {
195
- queryable: !!queryable,
196
- query: !!(queryable && queryable.query),
197
- isWrapped: !!(queryable && shim.isWrapped(queryable.query))
198
- },
199
- 'Not wrapping queryable'
200
- )
201
- return false
202
- }
203
-
204
- const proto = Object.getPrototypeOf(queryable)
205
-
206
- let describe
207
- if (isPoolQuery) {
208
- describe = describePoolQuery
209
- } else {
210
- describe = describeQuery
211
- proto[symbols.databaseName] = null
212
- }
213
-
214
- shim.recordQuery(proto, 'query', describe)
215
-
216
- if (queryable.execute) {
217
- shim.recordQuery(proto, 'execute', describe)
218
- }
219
-
220
- return true
221
- }
222
-
223
- function extractQueryArgs(shim, args) {
224
- let query = ''
225
- let callback = null
226
-
227
- // Figure out the query parameter.
228
- if (shim.isString(args[0])) {
229
- // query(sql [, values], callback)
230
- query = args[0]
231
- } else {
232
- // query(opts [, values], callback)
233
- query = args[0].sql
234
- }
235
-
236
- // Then determine the query values and callback parameters.
237
- if (shim.isArray(args[1])) {
238
- // query({opts|sql}, values, callback)
239
- callback = 2
240
- } else {
241
- // query({opts|sql}, callback)
242
- callback = 1
243
- }
244
-
245
- return {
246
- query,
247
- callback
248
- }
249
- }
250
-
251
- function describeQuery(shim, queryFn, fnName, args) {
252
- shim.logger.trace('Recording query')
253
- const extractedArgs = extractQueryArgs(shim, args)
254
-
255
- // Pull out instance attributes.
256
- const parameters = getInstanceParameters(shim, this, extractedArgs.query)
257
-
258
- shim.logger.trace(
259
- {
260
- query: !!extractedArgs.query,
261
- callback: !!extractedArgs.callback,
262
- parameters: !!parameters
263
- },
264
- 'Query segment descriptor'
265
- )
266
-
267
- return new QuerySpec({
268
- stream: true,
269
- query: extractedArgs.query,
270
- callback: extractedArgs.callback,
271
- parameters,
272
- record: true
273
- })
274
- }
275
-
276
- function describePoolQuery(shim, queryFn, fnName, args) {
277
- shim.logger.trace('Recording pool query')
278
- const extractedArgs = extractQueryArgs(shim, args)
279
- return new QuerySpec({
280
- internal: false,
281
- stream: true,
282
- query: null,
283
- callback: extractedArgs.callback,
284
- name: 'MySQL Pool#query',
285
- record: false
286
- })
287
- }
288
-
289
- function getInstanceParameters(shim, queryable, query) {
290
- const parameters = new DatastoreParameters()
291
- let conf = queryable.config
292
- conf = conf?.connectionConfig || conf
293
- const databaseName = queryable[symbols.databaseName] || null
294
- if (conf) {
295
- parameters.database_name = databaseName || conf.database
296
-
297
- if (properties.hasOwn(conf, 'socketPath') && conf.socketPath) {
298
- // In the unix domain socket case we force the host to be localhost
299
- parameters.host = 'localhost'
300
- parameters.port_path_or_id = conf.socketPath
301
- } else {
302
- parameters.host = conf.host
303
- parameters.port_path_or_id = conf.port
304
- }
305
- } else {
306
- shim.logger.trace('No query config detected, not collecting db instance data')
307
- }
308
-
309
- storeDatabaseName(queryable, query)
310
- return parameters
311
- }
312
-
313
- function storeDatabaseName(queryable, query) {
314
- if (queryable[symbols.storeDatabase]) {
315
- const databaseName = dbutils.extractDatabaseChangeFromUse(query)
316
- if (databaseName) {
317
- queryable[symbols.databaseName] = databaseName
318
- }
319
- }
320
- }
321
-
322
- module.exports = {
323
- callbackInitialize,
324
- promiseInitialize,
325
- wrapGetConnection,
326
- wrapGetConnectionCallback,
327
- wrapQueryable,
328
- extractQueryArgs,
329
- describeQuery,
330
- describePoolQuery,
331
- getInstanceParameters,
332
- storeDatabaseName
333
- }
@@ -1,26 +0,0 @@
1
- /*
2
- * Copyright 2022 New Relic Corporation. All rights reserved.
3
- * SPDX-License-Identifier: Apache-2.0
4
- */
5
-
6
- 'use strict'
7
- const instrumentation = require('./mysql')
8
- const InstrumentationDescriptor = require('../../instrumentation-descriptor')
9
-
10
- module.exports = [
11
- {
12
- type: InstrumentationDescriptor.TYPE_DATASTORE,
13
- moduleName: 'mysql',
14
- onRequire: instrumentation.callbackInitialize
15
- },
16
- {
17
- type: InstrumentationDescriptor.TYPE_DATASTORE,
18
- moduleName: 'mysql2',
19
- onRequire: instrumentation.callbackInitialize
20
- },
21
- {
22
- type: InstrumentationDescriptor.TYPE_DATASTORE,
23
- moduleName: 'mysql2/promise',
24
- onRequire: instrumentation.promiseInitialize
25
- }
26
- ]
@@ -1,32 +0,0 @@
1
- /*
2
- * Copyright 2025 New Relic Corporation. All rights reserved.
3
- * SPDX-License-Identifier: Apache-2.0
4
- */
5
-
6
- 'use strict'
7
-
8
- const { setTokensInResponse } = require('../utils')
9
-
10
- function setUsageTokens(response, context) {
11
- // prompt and completion token counts must available in order to add all usage attributes to response
12
- // if total tokens is not available, we can manually add it up (from input and output token count)
13
- if (tokenUsageAttributesExist(response) === false) {
14
- return
15
- }
16
-
17
- const promptTokens = Number(response?.usageMetadata?.promptTokenCount)
18
- const completionTokens = Number(response?.usageMetadata?.candidatesTokenCount)
19
- const totalTokens = Number(response?.usageMetadata?.totalTokenCount)
20
-
21
- setTokensInResponse(context, { promptTokens, completionTokens, totalTokens })
22
- }
23
-
24
- function tokenUsageAttributesExist(response) {
25
- const tokens = response?.usageMetadata?.promptTokenCount && response?.usageMetadata?.candidatesTokenCount
26
-
27
- return tokens !== undefined
28
- }
29
- module.exports = {
30
- tokenUsageAttributesExist,
31
- setUsageTokens
32
- }
@@ -1,34 +0,0 @@
1
- /*
2
- * Copyright 2024 New Relic Corporation. All rights reserved.
3
- * SPDX-License-Identifier: Apache-2.0
4
- */
5
-
6
- 'use strict'
7
-
8
- const { setTokensInResponse } = require('../utils')
9
-
10
- function setUsageTokens(response, context) {
11
- // input and output token counts must available in order to add all usage attributes to response
12
- // if total tokens is not available, we can manually add it up (from input and output token count)
13
- if (tokenUsageAttributesExist(response) === false) {
14
- return
15
- }
16
-
17
- const promptTokens = Number(response?.usage?.prompt_tokens || response?.usage?.input_tokens)
18
- const completionTokens = Number(response?.usage?.completion_tokens || response?.usage?.output_tokens)
19
- const totalTokens = Number(response?.usage?.total_tokens || response?.usage?.totalTokens)
20
-
21
- setTokensInResponse(context, { promptTokens, completionTokens, totalTokens })
22
- }
23
-
24
- function tokenUsageAttributesExist(response) {
25
- const tokensA = response?.usage?.prompt_tokens && response?.usage?.completion_tokens
26
- const tokensB = response?.usage?.input_tokens && response?.usage?.output_tokens
27
-
28
- return tokensA !== undefined || tokensB !== undefined
29
- }
30
-
31
- module.exports = {
32
- tokenUsageAttributesExist,
33
- setUsageTokens
34
- }
@@ -1,110 +0,0 @@
1
- /*
2
- * Copyright 2025 New Relic Corporation. All rights reserved.
3
- * SPDX-License-Identifier: Apache-2.0
4
- */
5
-
6
- 'use strict'
7
-
8
- /**
9
- * Determines if the provided token count is valid.
10
- * A valid token count is greater than 0 and not null.
11
- * @param {number} tokenCount The token count obtained from the token callback
12
- * @returns {boolean} Whether the token count is valid
13
- */
14
- function validCallbackTokenCount(tokenCount) {
15
- return tokenCount !== null && tokenCount > 0
16
- }
17
-
18
- /**
19
- * Calculates the total token count from the prompt tokens and completion tokens
20
- * set in the context.
21
- * @param {LlmEvent} context The context object containing token counts
22
- * @returns {number} The total token count
23
- */
24
- function getTotalTokenCount(context) {
25
- return Number(context['response.usage.prompt_tokens']) + Number(context['response.usage.completion_tokens'])
26
- }
27
-
28
- /**
29
- * Sets the provided tokens counts on the LLM event.
30
- * @param {LlmChatCompletionMessage} context The context object to set token usage counts on.
31
- * @param {object} tokens The object contains the token prompt, completion and total counts.
32
- */
33
- function setTokensInResponse(context, tokens) {
34
- context['response.usage.prompt_tokens'] = tokens.promptTokens
35
- context['response.usage.completion_tokens'] = tokens.completionTokens
36
- context['response.usage.total_tokens'] = tokens.totalTokens || getTotalTokenCount(context)
37
- }
38
-
39
- /**
40
- * Calculates prompt and completion token counts using the provided callback and models.
41
- * If both counts are valid, sets context.token_count to 0.
42
- *
43
- * @param {object} options - The params object.
44
- * @param {LlmChatCompletionMessage} options.context - The context object to set token count on.
45
- * @param {Function} options.tokenCB - The token counting callback function.
46
- * @param {string} options.reqModel - The model used for the prompt.
47
- * @param {string} options.resModel - The model used for the completion.
48
- * @param {string} options.promptContent - The prompt content to count tokens for.
49
- * @param {string} options.completionContent - The completion content to count tokens for.
50
- * @returns {void}
51
- */
52
- function setTokenFromCallback({ context, tokenCB, reqModel, resModel, promptContent, completionContent }) {
53
- const promptToken = calculateCallbackTokens(tokenCB, reqModel, promptContent)
54
- const completionToken = calculateCallbackTokens(tokenCB, resModel, completionContent)
55
-
56
- const hasValidCallbackCounts =
57
- validCallbackTokenCount(promptToken) && validCallbackTokenCount(completionToken)
58
-
59
- if (hasValidCallbackCounts) {
60
- context.token_count = 0
61
- }
62
- }
63
-
64
- /**
65
- * Calculates prompt and completion token counts using the provided callback and models.
66
- * If both counts are valid, sets token prompt, completion and total counts on the context.
67
- *
68
- * @param {object} options - The params object.
69
- * @param {LlmEvent} options.context - The context object (llm summary or llm embedding) to set token count on.
70
- * @param {Function} options.tokenCB - The token counting callback function.
71
- * @param {string} options.reqModel - The model used for the prompt.
72
- * @param {string} options.resModel - The model used for the completion.
73
- * @param {string} options.promptContent - The prompt content to count tokens for.
74
- * @param {string} options.completionContent - The completion content to count tokens for.
75
- * @returns {void}
76
- */
77
- function setTokenUsageFromCallback({ context, tokenCB, reqModel, resModel, promptContent, completionContent }) {
78
- const promptTokens = calculateCallbackTokens(tokenCB, reqModel, promptContent)
79
- const completionTokens = calculateCallbackTokens(tokenCB, resModel, completionContent)
80
-
81
- const hasValidCallbackCounts =
82
- validCallbackTokenCount(promptTokens) && validCallbackTokenCount(completionTokens)
83
-
84
- if (hasValidCallbackCounts) {
85
- setTokensInResponse(context, { promptTokens, completionTokens, totalTokens: promptTokens + completionTokens })
86
- }
87
- }
88
-
89
- /**
90
- * Calculate the token counts using the provided callback.
91
- * @param {Function} tokenCB - The token count callback function.
92
- * @param {string} model - The model.
93
- * @param {string} content - The content to calculate tokens for, such as prompt or completion response.
94
- * @returns {number|undefined} - The calculated token count or undefined if callback is not a function.
95
- */
96
- function calculateCallbackTokens(tokenCB, model, content) {
97
- if (typeof tokenCB === 'function') {
98
- return tokenCB(model, content)
99
- }
100
- return undefined
101
- }
102
-
103
- module.exports = {
104
- validCallbackTokenCount,
105
- getTotalTokenCount,
106
- setTokensInResponse,
107
- setTokenFromCallback,
108
- setTokenUsageFromCallback,
109
- calculateCallbackTokens
110
- }