newrelic 11.10.2 → 11.10.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.
package/NEWS.md CHANGED
@@ -1,3 +1,27 @@
1
+ ### v11.10.3 (2024-02-07)
2
+
3
+ #### Features
4
+
5
+ * Added feature flag for LangChain instrumentation ([#1990](https://github.com/newrelic/node-newrelic/pull/1990)) ([ab04e7a](https://github.com/newrelic/node-newrelic/commit/ab04e7a80b3aa7d669786d469ba256d009a195e6))
6
+ * Added message entities for LangChain ([#1983](https://github.com/newrelic/node-newrelic/pull/1983)) ([6b44a3a](https://github.com/newrelic/node-newrelic/commit/6b44a3ab84690acce71ade9364cb3634b7d42614))
7
+ * Added vectorsearch entities ([#1992](https://github.com/newrelic/node-newrelic/pull/1992)) ([ef74b2e](https://github.com/newrelic/node-newrelic/commit/ef74b2e4426c625e43cadcb4a84e4c389ae06577))
8
+
9
+ #### Bug fixes
10
+
11
+ * Updated grpc-js instrumentation to properly track errors and end transactions ([#2001](https://github.com/newrelic/node-newrelic/pull/2001)) ([fda1346](https://github.com/newrelic/node-newrelic/commit/fda134623522e9fde9dccb7606d4a2da89adf511))
12
+
13
+ #### Documentation
14
+
15
+ * Removed documentation around aws_bedrock_instrumentation as feature flag has been removed ([#1991](https://github.com/newrelic/node-newrelic/pull/1991)) ([f414564](https://github.com/newrelic/node-newrelic/commit/f414564738ab3ad8df207f96a857f27309d01f0b))
16
+
17
+ #### Miscellaneous chores
18
+
19
+ * Fixed third party notices and package-lock as they were out of sync. ([#1999](https://github.com/newrelic/node-newrelic/pull/1999)) ([a89def8](https://github.com/newrelic/node-newrelic/commit/a89def89f5cd7fec29c6466e15740f0f157da9b5))
20
+
21
+ #### Tests
22
+
23
+ * Updated prisma versioned test range to skip 5.9.0 as it was broken ([#1993](https://github.com/newrelic/node-newrelic/pull/1993)) ([d885286](https://github.com/newrelic/node-newrelic/commit/d8852867282dc79ea495cac8c414485ee91e7cd1))
24
+
1
25
  ### v11.10.2 (2024-01-31)
2
26
 
3
27
  #### Bug fixes
@@ -86,7 +86,7 @@ code, the source code can be found at [https://github.com/newrelic/node-newrelic
86
86
 
87
87
  ### @grpc/grpc-js
88
88
 
89
- This product includes source derived from [@grpc/grpc-js](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js) ([v1.9.14](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js/tree/v1.9.14)), distributed under the [Apache-2.0 License](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js/blob/v1.9.14/LICENSE):
89
+ This product includes source derived from [@grpc/grpc-js](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js) ([v1.10.0](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js/tree/v1.10.0)), distributed under the [Apache-2.0 License](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js/blob/v1.10.0/LICENSE):
90
90
 
91
91
  ```
92
92
  Apache License
@@ -1443,7 +1443,7 @@ SOFTWARE.
1443
1443
 
1444
1444
  ### semver
1445
1445
 
1446
- This product includes source derived from [semver](https://github.com/npm/node-semver) ([v7.5.4](https://github.com/npm/node-semver/tree/v7.5.4)), distributed under the [ISC License](https://github.com/npm/node-semver/blob/v7.5.4/LICENSE):
1446
+ This product includes source derived from [semver](https://github.com/npm/node-semver) ([v7.6.0](https://github.com/npm/node-semver/tree/v7.6.0)), distributed under the [ISC License](https://github.com/npm/node-semver/blob/v7.6.0/LICENSE):
1447
1447
 
1448
1448
  ```
1449
1449
  The ISC License
@@ -1466,7 +1466,7 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1466
1466
 
1467
1467
  ### winston-transport
1468
1468
 
1469
- This product includes source derived from [winston-transport](https://github.com/winstonjs/winston-transport) ([v4.6.0](https://github.com/winstonjs/winston-transport/tree/v4.6.0)), distributed under the [MIT License](https://github.com/winstonjs/winston-transport/blob/v4.6.0/LICENSE):
1469
+ This product includes source derived from [winston-transport](https://github.com/winstonjs/winston-transport) ([v4.7.0](https://github.com/winstonjs/winston-transport/tree/v4.7.0)), distributed under the [MIT License](https://github.com/winstonjs/winston-transport/blob/v4.7.0/LICENSE):
1470
1470
 
1471
1471
  ```
1472
1472
  The MIT License (MIT)
@@ -1916,7 +1916,7 @@ This product includes source derived from [@newrelic/newrelic-oss-cli](https://g
1916
1916
 
1917
1917
  ### @newrelic/test-utilities
1918
1918
 
1919
- This product includes source derived from [@newrelic/test-utilities](https://github.com/newrelic/node-test-utilities) ([v8.1.0](https://github.com/newrelic/node-test-utilities/tree/v8.1.0)), distributed under the [Apache-2.0 License](https://github.com/newrelic/node-test-utilities/blob/v8.1.0/LICENSE):
1919
+ This product includes source derived from [@newrelic/test-utilities](https://github.com/newrelic/node-test-utilities) ([v8.2.0](https://github.com/newrelic/node-test-utilities/tree/v8.2.0)), distributed under the [Apache-2.0 License](https://github.com/newrelic/node-test-utilities/blob/v8.2.0/LICENSE):
1920
1920
 
1921
1921
  ```
1922
1922
  Apache License
@@ -12,7 +12,8 @@ exports.prerelease = {
12
12
  reverse_naming_rules: false,
13
13
  undici_async_tracking: true,
14
14
  unresolved_promise_cleanup: true,
15
- legacy_context_manager: false
15
+ legacy_context_manager: false,
16
+ langchain_instrumentation: false
16
17
  }
17
18
 
18
19
  // flags that are no longer used for released features
@@ -153,7 +153,11 @@ function wrapRegister(shim, original) {
153
153
  function instrumentedHandler(stream) {
154
154
  const { transaction, segment } = createTransaction()
155
155
  acceptDTHeaders(stream, transaction)
156
- instrumentEventListeners(stream, transaction)
156
+ if (semver.gte(shim.pkgVersion, '1.10.0')) {
157
+ instrumentInterceptors(stream, transaction)
158
+ } else {
159
+ instrumentEventListeners(stream, transaction)
160
+ }
157
161
  return shim.applySegment(handler, segment, true, this, arguments)
158
162
  }
159
163
 
@@ -194,9 +198,48 @@ function wrapRegister(shim, original) {
194
198
  transaction.acceptDistributedTraceHeaders('HTTP', headers)
195
199
  }
196
200
 
201
+ /**
202
+ * Wraps the onCallEnd to add the response.status to trace, log an error,
203
+ * and end transaction.
204
+ *
205
+ * @param {object} stream the http2 server stream
206
+ * @param {object} transaction active transaction
207
+ */
208
+ function instrumentInterceptors(stream, transaction) {
209
+ const agent = shim.agent
210
+ const config = agent.config
211
+ if (!shim.isWrapped(stream.call.callEventTracker, 'onCallEnd')) {
212
+ shim.wrap(stream.call.callEventTracker, 'onCallEnd', function onCallEnd(shim, orig) {
213
+ return function wrappedOnCallEnd() {
214
+ const args = shim.argsToArray.apply(shim, arguments)
215
+ const [{ code: statusCode }] = args
216
+ transaction.trace.attributes.addAttribute(DESTINATION, 'response.status', statusCode)
217
+ if (shouldTrackError(statusCode, config)) {
218
+ const status = constants.Status[statusCode]
219
+ const error = new Error(`gRPC status code ${statusCode}: ${status}`)
220
+ agent.errors.add(transaction, error)
221
+ }
222
+ transaction.end()
223
+ return orig.apply(this, arguments)
224
+ }
225
+ })
226
+ }
227
+ }
228
+
229
+ /**
230
+ * Registers event listeners for callEnd and streamEnd to add the response.status to trace, log an error,
231
+ * and end transaction.
232
+ *
233
+ * Note: two listeners are registered as callEnd is emitted before streamEnd. Unlike the instrumentInterceptors
234
+ * case above where onCallEnd is called last.
235
+ *
236
+ * @param {object} stream the http2 server stream
237
+ * @param {object} transaction active transaction
238
+ */
197
239
  function instrumentEventListeners(stream, transaction) {
198
240
  const agent = shim.agent
199
241
  const config = agent.config
242
+
200
243
  stream.call.once('callEnd', (statusCode) => {
201
244
  transaction.trace.attributes.addAttribute(DESTINATION, 'response.status', statusCode)
202
245
  if (shouldTrackError(statusCode, config)) {
@@ -0,0 +1,18 @@
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 { DESTINATIONS } = require('../config/attribute-filter')
9
+
10
+ class BaseLlmEvent {
11
+ conversationId(agent) {
12
+ const transaction = agent.tracer.getTransaction()
13
+ const attrs = transaction?.trace?.custom.get(DESTINATIONS.TRANS_SCOPE)
14
+ return attrs?.['llm.conversation_id']
15
+ }
16
+ }
17
+
18
+ module.exports = BaseLlmEvent
@@ -0,0 +1,52 @@
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 LangChainEvent = require('./event')
9
+ const { makeId } = require('../../util/hashes')
10
+
11
+ /**
12
+ * @typedef {object} LangChainCompletionMessageParams
13
+ * @augments LangChainEventParams
14
+ * @property {string} content The text of the response received from LangChain.
15
+ * @property {string} role The role of the message, e.g. "human."
16
+ * @property {number} [sequence=0] The order of the message in the response.
17
+ * @property {string} [completionId] An identifier for the message.
18
+ */
19
+ /**
20
+ * @type {LangChainCompletionMessageParams}
21
+ */
22
+ const defaultParams = {
23
+ content: '',
24
+ role: undefined,
25
+ sequence: 0,
26
+ completionId: makeId(36)
27
+ }
28
+
29
+ class LangChainCompletionMesssage extends LangChainEvent {
30
+ content
31
+ role
32
+ sequence
33
+ completion_id
34
+
35
+ constructor(params = defaultParams) {
36
+ params = Object.assign({}, defaultParams, params)
37
+ super(params)
38
+
39
+ if (params.runId) {
40
+ this.id = `${params.runId}-${params.sequence}`
41
+ } else {
42
+ this.id = `${this.id}-${params.sequence}`
43
+ }
44
+
45
+ this.content = params.content
46
+ this.role = params.role
47
+ this.sequence = params.sequence
48
+ this.completion_id = params.completionId
49
+ }
50
+ }
51
+
52
+ module.exports = LangChainCompletionMesssage
@@ -0,0 +1,56 @@
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 LangChainEvent = require('./event')
9
+
10
+ /**
11
+ * @typedef {object} LangChainCompletionSummaryParams
12
+ * @augments LangChainEventParams
13
+ * @property {string[]|string} [tags] A set of tags applied to the LangChain
14
+ * event. If provided as a simple string, it should be a comma separated value
15
+ * string.
16
+ * @property {object[]} messages The set of messages that were returned as the
17
+ * LangChain result.
18
+ */
19
+ /**
20
+ * @type {LangChainCompletionSummaryParams}
21
+ */
22
+ const defaultParams = {
23
+ tags: [],
24
+ messages: []
25
+ }
26
+
27
+ class LangChainCompletionSummary extends LangChainEvent {
28
+ duration;
29
+ ['response.number_of_messages'] = 0
30
+
31
+ #tags
32
+
33
+ constructor(params = defaultParams) {
34
+ params = Object.assign({}, defaultParams, params)
35
+ super(params)
36
+ const { segment } = params
37
+
38
+ this.tags = params.tags
39
+ this.duration = segment?.getDurationInMillis()
40
+ this['response.number_of_messages'] = params.messages?.length
41
+ }
42
+
43
+ get tags() {
44
+ return this.#tags
45
+ }
46
+
47
+ set tags(value) {
48
+ if (Array.isArray(value)) {
49
+ this.#tags = value.join(',')
50
+ } else if (typeof value === 'string') {
51
+ this.#tags = value
52
+ }
53
+ }
54
+ }
55
+
56
+ module.exports = LangChainCompletionSummary
@@ -0,0 +1,83 @@
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 BaseEvent = require('../event')
9
+ const { makeId } = require('../../util/hashes')
10
+ const { isSimpleObject } = require('../../util/objects')
11
+
12
+ /**
13
+ * @typedef {object} LangChainEventParams
14
+ * @property {object} agent A New Relic agent instance.
15
+ * @property {object} segment A New Relic segment instance.
16
+ * @property {string} runId The identifier LangChain has assigned to the "run."
17
+ * @property {Object<string, string>} metadata The metadata, if any, associated with the
18
+ * LangChain run.
19
+ * @property {boolean|undefined} [virtual=true] Indicates that this event is a
20
+ * LangChain specific event (`true`). LangChain is not itself an LLM, but an
21
+ * interface to many LLMs. Any LLMs LangChain interacts with that we have
22
+ * instrumented will have their own traces that are not "virtual."
23
+ */
24
+ /**
25
+ * @type {LangChainEventParams}
26
+ */
27
+ const defaultParams = {
28
+ agent: {},
29
+ segment: {
30
+ transaction: {}
31
+ },
32
+ runId: '',
33
+ metadata: {},
34
+ virtual: undefined
35
+ }
36
+
37
+ /**
38
+ * Baseline object representing an event in a LangChain conversation.
39
+ */
40
+ class LangChainEvent extends BaseEvent {
41
+ id = makeId(36)
42
+ appName
43
+ conversation_id
44
+ span_id
45
+ request_id
46
+ transaction_id
47
+ trace_id
48
+ ingest_source = 'Node'
49
+ vendor = 'langchain'
50
+ virtual_llm = true
51
+
52
+ constructor(params = defaultParams) {
53
+ params = Object.assign({}, defaultParams, params)
54
+ super(params)
55
+ const { agent, segment } = params
56
+
57
+ this.appName = agent.config.applications()[0]
58
+ this.conversation_id = this.conversationId(agent)
59
+ this.span_id = segment?.id
60
+ this.request_id = params.runId
61
+ this.transaction_id = segment?.transaction?.id
62
+ this.trace_id = segment?.transaction?.traceId
63
+ this.metadata = params.metadata
64
+
65
+ if (params.virtual !== undefined) {
66
+ if (params.virtual !== true && params.virtual !== false) {
67
+ throw Error('params.virtual must be a primitive boolean')
68
+ }
69
+ this.virtual_llm = params.virtual
70
+ }
71
+ }
72
+
73
+ set metadata(value) {
74
+ if (isSimpleObject(value) === false) {
75
+ return
76
+ }
77
+ for (const [key, val] of Object.entries(value)) {
78
+ this[`metadata.${key}`] = val
79
+ }
80
+ }
81
+ }
82
+
83
+ module.exports = LangChainEvent
@@ -0,0 +1,14 @@
1
+ /*
2
+ * Copyright 2024 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ 'use strict'
7
+
8
+ module.exports = {
9
+ LangChainEvent: require('./event'),
10
+ LangChainCompletionMessage: require('./chat-completion-message'),
11
+ LangChainCompletionSummary: require('./chat-completion-summary'),
12
+ LangChainVectorSearch: require('./vector-search'),
13
+ LangChainVectorSearchResult: require('./vector-search-result')
14
+ }
@@ -0,0 +1,37 @@
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 LangChainEvent = require('./event')
9
+ const crypto = require('crypto')
10
+
11
+ /**
12
+ * @typedef {object} LangChainVectorSearchResultParams
13
+ * @augments LangChainEventParams
14
+ * @property {string} pageContent The stringified contents of the pageContent attribute on each returned search result document.
15
+ * @property {number} [sequence=0] The index of the document in the search result documents list.
16
+ */
17
+ /**
18
+ * @type {LangChainVectorSearchResultParams}
19
+ */
20
+ const defaultParams = {
21
+ pageContent: '',
22
+ sequence: 0
23
+ }
24
+
25
+ class LangChainVectorSearchResult extends LangChainEvent {
26
+ search_id = crypto.randomUUID()
27
+
28
+ constructor(params) {
29
+ params = Object.assign({}, defaultParams, params)
30
+ super(params)
31
+
32
+ this.page_content = params.pageContent
33
+ this.sequence = params.sequence
34
+ }
35
+ }
36
+
37
+ module.exports = LangChainVectorSearchResult
@@ -0,0 +1,40 @@
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 LangChainEvent = require('./event')
9
+
10
+ /**
11
+ * @typedef {object} LangChainVectorSearchParams
12
+ * @augments LangChainEventParams
13
+ * @property {string} query First parameter of similaritySearch method.
14
+ * @property {number} k Second parameter of similaritySearch method.
15
+ * @property {object} documents The set of documents returned in a response.
16
+ */
17
+ /**
18
+ * @type {LangChainVectorSearchParams}
19
+ */
20
+ const defaultParams = {
21
+ documents: []
22
+ }
23
+
24
+ class LangChainVectorSearch extends LangChainEvent {
25
+ duration;
26
+ ['response.number_of_documents'] = 0
27
+
28
+ constructor(params) {
29
+ params = Object.assign({}, defaultParams, params)
30
+ super(params)
31
+ const { segment } = params
32
+
33
+ this.duration = segment?.getDurationInMillis()
34
+ this['request.query'] = params.query
35
+ this['request.k'] = params.k
36
+ this['response.number_of_documents'] = params.documents?.length
37
+ }
38
+ }
39
+
40
+ module.exports = LangChainVectorSearch
@@ -4,11 +4,14 @@
4
4
  */
5
5
 
6
6
  'use strict'
7
+
8
+ const BaseEvent = require('../event')
7
9
  const { makeId } = require('../../util/hashes')
8
- const { DESTINATIONS } = require('../../../lib/config/attribute-filter')
9
10
 
10
- module.exports = class LlmEvent {
11
+ module.exports = class LlmEvent extends BaseEvent {
11
12
  constructor({ agent, segment, request, response, responseAttrs = false }) {
13
+ super()
14
+
12
15
  this.id = makeId(36)
13
16
  this.appName = agent.config.applications()[0]
14
17
  this.request_id = response?.headers?.['x-request-id']
@@ -47,10 +50,4 @@ module.exports = class LlmEvent {
47
50
  this['response.headers.ratelimitRemainingRequests'] =
48
51
  response?.headers?.['x-ratelimit-remaining-requests']
49
52
  }
50
-
51
- conversationId(agent) {
52
- const transaction = agent.tracer.getTransaction()
53
- const attrs = transaction?.trace?.custom.get(DESTINATIONS.TRANS_SCOPE)
54
- return attrs?.['llm.conversation_id']
55
- }
56
53
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "newrelic",
3
- "version": "11.10.2",
3
+ "version": "11.10.3",
4
4
  "author": "New Relic Node.js agent team <nodejs@newrelic.com>",
5
5
  "license": "Apache-2.0",
6
6
  "contributors": [