newrelic 11.14.0 → 11.15.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 CHANGED
@@ -1,3 +1,35 @@
1
+ ### v11.15.0 (2024-04-09)
2
+
3
+ #### Bug fixes
4
+
5
+ * Fixed instrumenting the same module installed in different locations ([#2104](https://github.com/newrelic/node-newrelic/pull/2104)) ([88bdace](https://github.com/newrelic/node-newrelic/commit/88bdace6489c7d258ed3200f1550367f35824bc1))
6
+
7
+ #### Code refactoring
8
+
9
+ * **mongodb:** Removed instrumentation that handles connecting via unix domain socket. ([#2129](https://github.com/newrelic/node-newrelic/pull/2129)) ([808323f](https://github.com/newrelic/node-newrelic/commit/808323f0832952870fd1e94474b3fd3e0ab1b8c4))
10
+ * Updated shim classes to no longer construct specs. ([#2096](https://github.com/newrelic/node-newrelic/pull/2096)) ([158c295](https://github.com/newrelic/node-newrelic/commit/158c29566f6a5993ec77f84aeaa266ceab0bf4f0))
11
+
12
+ #### Miscellaneous chores
13
+
14
+ * **deps-dev:** Bumped express from 4.18.2 to 4.19.2 ([#2101](https://github.com/newrelic/node-newrelic/pull/2101)) ([639cb78](https://github.com/newrelic/node-newrelic/commit/639cb785dff7568ad227091512013c2dfb81e5f9))
15
+ * **deps:** Updated @newrelic/security-agent to v1.1.1 ([#2092](https://github.com/newrelic/node-newrelic/pull/2092)) ([3272aa3](https://github.com/newrelic/node-newrelic/commit/3272aa3da2260ce18c71c24608ffdda512ca6817))
16
+ * Fixed incorrect pinning of @elastic/transport ([#2120](https://github.com/newrelic/node-newrelic/pull/2120)) ([7b5bdaa](https://github.com/newrelic/node-newrelic/commit/7b5bdaac1b1081636636cd7ca7c6b484f5251f76))
17
+ * Removed scrollbar styling in generated API docs ([#2091](https://github.com/newrelic/node-newrelic/pull/2091)) ([cb0fa11](https://github.com/newrelic/node-newrelic/commit/cb0fa11c81290bb93cb30e974fdb1ece82a1e80e))
18
+ * Removed transaction_id and legacy token count attributes from llm events for openai and langchain ([#2093](https://github.com/newrelic/node-newrelic/pull/2093)) ([df2a0fd](https://github.com/newrelic/node-newrelic/commit/df2a0fd7c99a7bbf024c1e33c7fdff512b45c970))
19
+
20
+ #### Tests
21
+
22
+ * Updated test/integration/core/dns reverse test to remove flakiness ([#2121](https://github.com/newrelic/node-newrelic/pull/2121)) ([c32cb27](https://github.com/newrelic/node-newrelic/commit/c32cb2739ece3adcf5bd42e646071b3f59e691ba))
23
+ * Updated elastic tests to skip broken version ([#2119](https://github.com/newrelic/node-newrelic/pull/2119)) ([5d0d1bb](https://github.com/newrelic/node-newrelic/commit/5d0d1bb4994b41d43ab9b4eb110fea036ac307bc))
24
+
25
+ #### Continuous integration
26
+
27
+ * Removed usage of `use_new_release` from prepare release workflow ([#2124](https://github.com/newrelic/node-newrelic/pull/2124)) ([007ddb4](https://github.com/newrelic/node-newrelic/commit/007ddb4dce6cf5ab463a1868fe4cfa203d3e9ff2))
28
+ * Updated `prepare-release.js` to not require changelog.json ([#2106](https://github.com/newrelic/node-newrelic/pull/2106)) ([328a570](https://github.com/newrelic/node-newrelic/commit/328a570bbe9f359d23a21317ccd8a8bc52b473b4))
29
+ * Updated prepare release to provide a drop down for release type ([#2133](https://github.com/newrelic/node-newrelic/pull/2133)) ([846269b](https://github.com/newrelic/node-newrelic/commit/846269bb256f287c5fb9be32bdb62e9786e3cfe4))
30
+ * Updated versioned security agent workflow ([#2100](https://github.com/newrelic/node-newrelic/pull/2100)) ([f787b15](https://github.com/newrelic/node-newrelic/commit/f787b15f94c416d547af1ab4b2d7c31665b417b7))
31
+ * Fixed typo in constant name for prepare release script ([#2094](https://github.com/newrelic/node-newrelic/pull/2094)) ([3b887d9](https://github.com/newrelic/node-newrelic/commit/3b887d96c70a2cc5e3833cdc8b65de99b643f7a1))
32
+
1
33
  ### v11.14.0 (2024-03-20)
2
34
 
3
35
  #### Features
@@ -712,7 +712,7 @@ This product includes source derived from [@newrelic/aws-sdk](https://github.com
712
712
 
713
713
  ### @newrelic/koa
714
714
 
715
- This product includes source derived from [@newrelic/koa](https://github.com/newrelic/node-newrelic-koa) ([v9.0.0](https://github.com/newrelic/node-newrelic-koa/tree/v9.0.0)), distributed under the [Apache-2.0 License](https://github.com/newrelic/node-newrelic-koa/blob/v9.0.0/LICENSE):
715
+ This product includes source derived from [@newrelic/koa](https://github.com/newrelic/node-newrelic-koa) ([v9.1.0](https://github.com/newrelic/node-newrelic-koa/tree/v9.1.0)), distributed under the [Apache-2.0 License](https://github.com/newrelic/node-newrelic-koa/blob/v9.1.0/LICENSE):
716
716
 
717
717
  ```
718
718
  Apache License
@@ -951,7 +951,7 @@ SOFTWARE.
951
951
 
952
952
  ### @newrelic/security-agent
953
953
 
954
- This product includes source derived from [@newrelic/security-agent](https://github.com/newrelic/csec-node-agent) ([v1.0.1](https://github.com/newrelic/csec-node-agent/tree/v1.0.1)), distributed under the [UNKNOWN License](https://github.com/newrelic/csec-node-agent/blob/v1.0.1/LICENSE):
954
+ This product includes source derived from [@newrelic/security-agent](https://github.com/newrelic/csec-node-agent) ([v1.1.1](https://github.com/newrelic/csec-node-agent/tree/v1.1.1)), distributed under the [UNKNOWN License](https://github.com/newrelic/csec-node-agent/blob/v1.1.1/LICENSE):
955
955
 
956
956
  ```
957
957
  ## New Relic Software License v1.0
package/api.js CHANGED
@@ -26,7 +26,7 @@ const {
26
26
  const LlmFeedbackMessage = require('./lib/llm-events/feedback-message')
27
27
 
28
28
  const ATTR_DEST = require('./lib/config/attribute-filter').DESTINATIONS
29
- const MODULE_TYPE = require('./lib/shim/constants').MODULE_TYPE
29
+ const MODULE_TYPE = require('./lib/instrumentation-descriptor').TYPES
30
30
  const NAMES = require('./lib/metrics/names')
31
31
  const obfuscate = require('./lib/util/sql/obfuscate')
32
32
  const { DESTINATIONS } = require('./lib/config/attribute-filter')
@@ -28,7 +28,9 @@ module.exports = function initialize(_agent, cassandra, _moduleName, shim) {
28
28
  shim.recordOperation(
29
29
  ClientProto,
30
30
  ['connect', 'shutdown'],
31
- new OperationSpec({ callback: shim.LAST })
31
+ function operationSpec(shim, _fn, name) {
32
+ return new OperationSpec({ callback: shim.LAST, name })
33
+ }
32
34
  )
33
35
 
34
36
  if (semver.satisfies(cassandraVersion, '>=4.4.0')) {
@@ -11,7 +11,6 @@ const {
11
11
  } = require('../../shim/specs')
12
12
  const { CURSOR_OPS, COLLECTION_OPS, DB_OPS } = require('./constants')
13
13
  const common = module.exports
14
- common.NR_ATTRS = Symbol('NR_ATTRS')
15
14
 
16
15
  /**
17
16
  * Instruments all methods from constants.CURSOR_OPS on a given
@@ -23,12 +22,9 @@ common.NR_ATTRS = Symbol('NR_ATTRS')
23
22
  common.instrumentCursor = function instrumentCursor(shim, Cursor) {
24
23
  if (Cursor && Cursor.prototype) {
25
24
  const proto = Cursor.prototype
26
- for (let i = 0; i < CURSOR_OPS.length; i++) {
27
- shim.recordQuery(proto, CURSOR_OPS[i], common.makeQueryDescFunc(shim, CURSOR_OPS[i]))
28
- }
29
-
30
- shim.recordQuery(proto, 'each', common.makeQueryDescFunc(shim, 'each'))
31
- shim.recordOperation(proto, 'pipe', new OperationSpec({ opaque: true }))
25
+ shim.recordQuery(proto, CURSOR_OPS, common.makeQueryDescFunc)
26
+ shim.recordQuery(proto, 'each', common.makeQueryDescFunc)
27
+ shim.recordOperation(proto, 'pipe', new OperationSpec({ opaque: true, name: 'pipe' }))
32
28
  }
33
29
  }
34
30
 
@@ -42,9 +38,7 @@ common.instrumentCursor = function instrumentCursor(shim, Cursor) {
42
38
  common.instrumentCollection = function instrumentCollection(shim, Collection) {
43
39
  if (Collection && Collection.prototype) {
44
40
  const proto = Collection.prototype
45
- for (let i = 0; i < COLLECTION_OPS.length; i++) {
46
- shim.recordQuery(proto, COLLECTION_OPS[i], common.makeQueryDescFunc(shim, COLLECTION_OPS[i]))
47
- }
41
+ shim.recordQuery(proto, COLLECTION_OPS, common.makeQueryDescFunc)
48
42
  }
49
43
  }
50
44
 
@@ -72,13 +66,20 @@ common.instrumentBulkOperation = function instrumentBulkOperation(shim, BulkOper
72
66
  common.instrumentDb = function instrumentDb(shim, Db) {
73
67
  if (Db && Db.prototype) {
74
68
  const proto = Db.prototype
69
+ shim.recordOperation(proto, DB_OPS, function makeOperationDescFunc(shim, _fn, methodName) {
70
+ return new OperationSpec({
71
+ callback: shim.LAST,
72
+ opaque: true,
73
+ promise: true,
74
+ name: methodName
75
+ })
76
+ })
77
+ // link to client.connect(removed in v4.0)
75
78
  shim.recordOperation(
76
- proto,
77
- DB_OPS,
78
- new OperationSpec({ callback: shim.LAST, opaque: true, promise: true })
79
+ Db,
80
+ 'connect',
81
+ new OperationSpec({ callback: shim.LAST, promise: true, name: 'connect' })
79
82
  )
80
- // link to client.connect(removed in v4.0)
81
- shim.recordOperation(Db, 'connect', new OperationSpec({ callback: shim.LAST, promise: true }))
82
83
  }
83
84
  }
84
85
 
@@ -86,29 +87,26 @@ common.instrumentDb = function instrumentDb(shim, Db) {
86
87
  * Sets up the desc for all instrumented query methods
87
88
  *
88
89
  * @param {Shim} shim instance of shim
89
- * @param {string} methodName name of method getting executed
90
- * @returns {object} query spec
90
+ * @param {Function} _fn function getting instrumented
91
+ * @param {string} methodName name of function
92
+ * @returns {QuerySpec} query spec
91
93
  */
92
- common.makeQueryDescFunc = function makeQueryDescFunc(shim, methodName) {
94
+ common.makeQueryDescFunc = function makeQueryDescFunc(shim, _fn, methodName) {
93
95
  if (methodName === 'each') {
94
- return function eachDescFunc() {
95
- const parameters = getInstanceAttributeParameters(shim, this)
96
- return new QuerySpec({ query: methodName, parameters, rowCallback: shim.LAST, opaque: true })
97
- }
98
- }
99
-
100
- return function queryDescFunc() {
101
- // segment name does not actually use query string
102
- // method name is set as query so the query parser has access to the op name
103
96
  const parameters = getInstanceAttributeParameters(shim, this)
104
- return new QuerySpec({
105
- query: methodName,
106
- parameters,
107
- promise: true,
108
- callback: shim.LAST,
109
- opaque: true
110
- })
97
+ return new QuerySpec({ query: methodName, parameters, rowCallback: shim.LAST, opaque: true })
111
98
  }
99
+
100
+ // segment name does not actually use query string
101
+ // method name is set as query so the query parser has access to the op name
102
+ const parameters = getInstanceAttributeParameters(shim, this)
103
+ return new QuerySpec({
104
+ query: methodName,
105
+ parameters,
106
+ promise: true,
107
+ callback: shim.LAST,
108
+ opaque: true
109
+ })
112
110
  }
113
111
 
114
112
  /**
@@ -156,13 +154,10 @@ common.captureAttributesOnStarted = function captureAttributesOnStarted(
156
154
  if (connId) {
157
155
  // used in v3 when connection is a cluster pool
158
156
  if (typeof connId === 'number') {
159
- setHostPort(shim, evnt.address, evnt.databaseName, this.$MongoClient)
157
+ setHostPort(shim, evnt.address, evnt.databaseName)
160
158
  // used in v3 when connection is to 1 host
161
159
  } else if (typeof connId === 'string') {
162
160
  setHostPort(shim, connId, evnt.databaseName)
163
- // v2 contains `domainSocket`, get socket connection from `host`
164
- } else if (connId.domainSocket) {
165
- shim.captureInstanceAttributes('localhost', connId.host, evnt.databaseName)
166
161
  // v2 remote connection get `host` `port` from respective properties
167
162
  } else {
168
163
  shim.captureInstanceAttributes(connId.host, connId.port, evnt.databaseName)
@@ -173,37 +168,14 @@ common.captureAttributesOnStarted = function captureAttributesOnStarted(
173
168
 
174
169
  /**
175
170
  * Extracts the host and port from a connection string
176
- * This also handles if connection string is a domain socket
177
- * Mongo sticks the path to the domain socket in the "host" slot, but we
178
- * want it in the "port", so if we have a domain socket we need to change
179
- * the order of our parameters.
180
171
  *
181
172
  * @param {Shim} shim instance of shim
182
173
  * @param {string} connStr mongo connection string
183
174
  * @param {string} db database name
184
- * @param {object} client mongo client instance
185
175
  */
186
- function setHostPort(shim, connStr, db, client) {
176
+ function setHostPort(shim, connStr, db) {
187
177
  const parts = common.parseAddress(connStr)
188
- // in v3 when running with a cluster of socket connections
189
- // the address is `undefined:undefined`. we will instead attempt
190
- // to get connection details from the client symbol NR_ATTRS
191
- // added in `lib/instrumentation/mongodb/v3-mongo` when a client connects
192
- // with a URL string
193
- if (parts.includes('undefined')) {
194
- try {
195
- const attrs = client[common.NR_ATTRS]
196
- const socket = decodeURIComponent(attrs.split(',')[0].split('mongodb://')[1])
197
- shim.captureInstanceAttributes('localhost', socket, db)
198
- } catch (err) {
199
- shim.logger.debug(err, 'Could not extract host/port from mongo command')
200
- }
201
- // connected using domain socket but the "host"(e.g: /path/to/mongo-socket-port.sock)
202
- } else if (parts.length && parts[0][0] === '/') {
203
- shim.captureInstanceAttributes('localhost', parts[0], db)
204
- } else {
205
- shim.captureInstanceAttributes(parts[0], parts[1], db)
206
- }
178
+ shim.captureInstanceAttributes(parts[0], parts[1], db)
207
179
  }
208
180
 
209
181
  /**
@@ -247,13 +219,8 @@ function getInstanceAttributeParameters(shim, mongo) {
247
219
  * @returns {object} db params
248
220
  */
249
221
  function getParametersFromHosts(hosts, database) {
250
- let [{ host, port }] = hosts
251
- const [{ socketPath }] = hosts
222
+ const [{ host, port }] = hosts
252
223
 
253
- if (socketPath) {
254
- port = socketPath
255
- host = 'localhost'
256
- }
257
224
  return new DatastoreParameters({
258
225
  host,
259
226
  port_path_or_id: port,
@@ -284,13 +251,6 @@ function getParametersFromTopology(conf, database) {
284
251
  ;[{ host, port }] = conf.s.options.hosts
285
252
  }
286
253
 
287
- // host is a domain socket. set host as localhost and use the domain
288
- // socket host as the port
289
- if (host && host.endsWith('.sock')) {
290
- port = host
291
- host = 'localhost'
292
- }
293
-
294
254
  return new DatastoreParameters({
295
255
  host,
296
256
  port_path_or_id: port,
@@ -38,7 +38,7 @@ module.exports = function instrument(shim, mongodb) {
38
38
  const recordDesc = {
39
39
  Gridstore: {
40
40
  isQuery: false,
41
- makeDescFunc: function makeGridDesc(opName) {
41
+ makeDescFunc: function makeGridDesc(shim, fn, opName) {
42
42
  return new OperationSpec({ name: 'GridFS-' + opName, callback: shim.LAST })
43
43
  }
44
44
  },
@@ -50,8 +50,8 @@ module.exports = function instrument(shim, mongodb) {
50
50
  Collection: { isQuery: true, makeDescFunc: makeQueryDescFunc },
51
51
  Db: {
52
52
  isQuery: false,
53
- makeDescFunc: function makeDbDesc() {
54
- return new OperationSpec({ callback: shim.LAST })
53
+ makeDescFunc: function makeDbDesc(shim, fn, method) {
54
+ return new OperationSpec({ callback: shim.LAST, name: method })
55
55
  }
56
56
  }
57
57
  }
@@ -95,10 +95,10 @@ module.exports = function instrument(shim, mongodb) {
95
95
  const { isQuery, makeDescFunc } = recordDesc[objectName]
96
96
  const proto = object.prototype
97
97
  if (isQuery) {
98
- shim.recordQuery(proto, method, makeDescFunc(shim, method))
98
+ shim.recordQuery(proto, method, makeDescFunc)
99
99
  } else if (isQuery === false) {
100
100
  // could be unset
101
- shim.recordOperation(proto, method, makeDescFunc(shim, method))
101
+ shim.recordOperation(proto, method, makeDescFunc)
102
102
  } else {
103
103
  shim.logger.trace('No wrapping method found for %s', objectName)
104
104
  }
@@ -108,7 +108,11 @@ module.exports = function instrument(shim, mongodb) {
108
108
  // the cursor object implements Readable stream and internally calls nextObject on
109
109
  // each read, in which case we do not want to record each nextObject() call
110
110
  if (/Cursor$/.test(objectName)) {
111
- shim.recordOperation(object.prototype, 'pipe', new OperationSpec({ opaque: true }))
111
+ shim.recordOperation(
112
+ object.prototype,
113
+ 'pipe',
114
+ new OperationSpec({ opaque: true, name: 'pipe' })
115
+ )
112
116
  }
113
117
  }
114
118
  }
@@ -11,15 +11,15 @@ const {
11
11
  instrumentBulkOperation,
12
12
  instrumentCollection,
13
13
  instrumentCursor,
14
- instrumentDb,
15
- NR_ATTRS
14
+ instrumentDb
16
15
  } = require('./common')
17
16
 
18
17
  /**
19
18
  * parser used to grab the collection and operation
20
19
  * on every mongo operation
21
20
  *
22
- * @param {object} operation
21
+ * @param {object} operation mongodb operation
22
+ * @returns {object} { operation, collection } parsed operation and collection
23
23
  */
24
24
  function queryParser(operation) {
25
25
  let collection = this.collectionName || 'unknown'
@@ -40,15 +40,12 @@ function queryParser(operation) {
40
40
  * to a Symbol on the MongoClient to be used later to extract the host/port in cases where the topology
41
41
  * is a cluster of domain sockets
42
42
  *
43
- * @param {Shim} shim
43
+ * @param {Shim} shim instance of shim
44
44
  * @param {object} mongodb resolved package
45
45
  */
46
46
  function instrumentClient(shim, mongodb) {
47
- shim.recordOperation(mongodb.MongoClient, 'connect', function wrappedConnect(shim, _, __, args) {
48
- // Add the connection url to the MongoClient to retrieve later in the `lib/instrumentation/mongo/common`
49
- // captureAttributesOnStarted listener
50
- this[NR_ATTRS] = args[0]
51
- return new RecorderSpec({ callback: shim.LAST })
47
+ shim.recordOperation(mongodb.MongoClient, 'connect', function wrappedConnect(shim) {
48
+ return new RecorderSpec({ callback: shim.LAST, name: 'connect' })
52
49
  })
53
50
  }
54
51
 
@@ -61,7 +58,7 @@ function instrumentClient(shim, mongodb) {
61
58
  * as well as sets up a listener for when commands start to properly
62
59
  * add necessary attributes to segments
63
60
  *
64
- * @param {Shim} shim
61
+ * @param {Shim} shim instance of shim
65
62
  * @param {object} mongodb resolved package
66
63
  */
67
64
  module.exports = function instrument(shim, mongodb) {
@@ -18,7 +18,8 @@ const {
18
18
  * parser used to grab the collection and operation
19
19
  * from a running query
20
20
  *
21
- * @param {object} operation
21
+ * @param {object} operation mongodb operation
22
+ * @returns {object} { operation, collection } parsed operation and collection
22
23
  */
23
24
  function queryParser(operation) {
24
25
  let collection = this.collectionName || 'unknown'
@@ -39,23 +40,15 @@ function queryParser(operation) {
39
40
  * update host, port and database_name
40
41
  * on segment attributes
41
42
  *
42
- * @param {Shim} shim
43
- * @param {CommandStartedEvent} evnt
43
+ * @param {Shim} shim instance of shim
44
+ * @param {CommandStartedEvent} evnt mongodb event
44
45
  */
45
46
  function cmdStartedHandler(shim, evnt) {
46
47
  if (evnt.connectionId) {
47
- let [host, port] = parseAddress(evnt.address)
48
-
49
- // connection via socket get port from 1st host
50
- // socketPath property
51
- // which looks like mongodb:///tmp/mongodb-27017.sock"
52
- if (['undefined'].includes(host, port)) {
53
- host = 'localhost'
54
- const hosts = this.s.options.hosts
55
- if (hosts && hosts.length && hosts[0].socketPath) {
56
- port = hosts[0].socketPath
57
- }
58
- } else if (['127.0.0.1', '::1', '[::1]'].includes(host)) {
48
+ const address = parseAddress(evnt.address)
49
+ let [host] = address
50
+ const [, port] = address
51
+ if (['127.0.0.1', '::1', '[::1]'].includes(host)) {
59
52
  host = 'localhost'
60
53
  }
61
54
 
@@ -68,12 +61,13 @@ function cmdStartedHandler(shim, evnt) {
68
61
  * enable APM(monitorCommands) and add the
69
62
  * `commandStarted` listener
70
63
  *
71
- * @param {Shim} shim
64
+ * @param {Shim} shim instance of shim
65
+ * @returns {OperationSpec} spec to capture connect method
72
66
  */
73
67
  function wrapConnect(shim) {
74
68
  this.monitorCommands = true
75
69
  this.on('commandStarted', cmdStartedHandler.bind(this, shim))
76
- return new OperationSpec({ callback: shim.LAST })
70
+ return new OperationSpec({ callback: shim.LAST, name: 'connect' })
77
71
  }
78
72
 
79
73
  /**
@@ -82,7 +76,7 @@ function wrapConnect(shim) {
82
76
  * so we can properly update the segment attributes with a more accurate
83
77
  * host/port/database name
84
78
  *
85
- * @param {Shim} shim
79
+ * @param {Shim} shim instance of shim
86
80
  * @param {MongoClient} MongoClient reference
87
81
  */
88
82
  function instrumentMongoClient(shim, MongoClient) {
@@ -6,7 +6,7 @@
6
6
  'use strict'
7
7
 
8
8
  const { nrEsmProxy } = require('../symbols')
9
- const { RecorderSpec, QuerySpec } = require('../shim/specs')
9
+ const { RecorderSpec, QuerySpec, ClassWrapSpec } = require('../shim/specs')
10
10
  const DatastoreParameters = require('../shim/specs/params/datastore')
11
11
 
12
12
  function getQuery(shim, original, name, args) {
@@ -58,12 +58,12 @@ module.exports = function initialize(agent, pgsql, moduleName, shim) {
58
58
  // wrapping for native
59
59
  function instrumentPGNative(pg) {
60
60
  shim.wrapReturn(pg, 'Client', clientFactoryWrapper)
61
- shim.wrapClass(pg, 'Pool', { post: poolPostConstructor, es6: true })
61
+ shim.wrapClass(pg, 'Pool', new ClassWrapSpec({ post: poolPostConstructor, es6: true }))
62
62
  }
63
63
 
64
64
  function poolPostConstructor(shim) {
65
65
  if (!shim.isWrapped(this.Client)) {
66
- shim.wrapClass(this, 'Client', clientPostConstructor)
66
+ shim.wrapClass(this, 'Client', new ClassWrapSpec({ post: clientPostConstructor }))
67
67
  }
68
68
  }
69
69
 
@@ -30,6 +30,7 @@ const idGen = new IdGen()
30
30
  * @property {string} absolutePath
31
31
  * @property {string} module
32
32
  * @property {string} moduleName
33
+ * @property {string} shimName
33
34
  * @property {InstrumentationOnError} onError
34
35
  * @property {InstrumentationOnRequire} onRequire
35
36
  * @property {string} resolvedName
@@ -117,6 +118,14 @@ class InstrumentationDescriptor {
117
118
  */
118
119
  moduleName
119
120
 
121
+ /**
122
+ * Used when instrumenting a module to determine if a module has already
123
+ * been wrapped by a specific shim instance. It is used in conjunction with
124
+ * the `shim.id` value.
125
+ * @type {string}
126
+ */
127
+ shimName
128
+
120
129
  /**
121
130
  * The absolute path to the module to instrument. This should only be set
122
131
  * when the module being instrumented does not reside in a `node_modules`
@@ -163,6 +172,7 @@ class InstrumentationDescriptor {
163
172
  this.absolutePath = params.absolutePath
164
173
  this.module = params.module
165
174
  this.moduleName = params.moduleName
175
+ this.shimName = params.shimName
166
176
  this.onError = params.onError
167
177
  this.onRequire = params.onRequire
168
178
  this.resolvedName = params.resolvedName
@@ -184,3 +194,22 @@ class InstrumentationDescriptor {
184
194
  }
185
195
 
186
196
  module.exports = InstrumentationDescriptor
197
+
198
+ // This export is for backward compatibility in the public API. The
199
+ // public API object simply re-exports this object that was originally
200
+ // in a `constants.js` file prior to the creation of the
201
+ // `InstrumentationDescriptor`.
202
+ module.exports.TYPES = {
203
+ GENERIC: InstrumentationDescriptor.TYPE_GENERIC,
204
+
205
+ DATASTORE: InstrumentationDescriptor.TYPE_DATASTORE,
206
+ MESSAGE: InstrumentationDescriptor.TYPE_MESSAGE,
207
+ PROMISE: InstrumentationDescriptor.TYPE_PROMISE,
208
+
209
+ WEB_FRAMEWORK: InstrumentationDescriptor.TYPE_WEB_FRAMEWORK,
210
+ TRACKING: InstrumentationDescriptor.TYPE_TRACKING,
211
+ /** @private */
212
+ CONGLOMERATE: InstrumentationDescriptor.TYPE_CONGLOMERATE,
213
+ /** @private */
214
+ TRANSACTION: InstrumentationDescriptor.TYPE_TRANSACTION
215
+ }
@@ -5,44 +5,44 @@
5
5
 
6
6
  'use strict'
7
7
 
8
- const MODULE_TYPE = require('./shim/constants').MODULE_TYPE
8
+ const InstrumentationDescriptor = require('./instrumentation-descriptor')
9
9
 
10
10
  // Return a new copy of this array every time we're called
11
11
  module.exports = function instrumentations() {
12
12
  return {
13
13
  'aws-sdk': { module: '@newrelic/aws-sdk' },
14
14
  'amqplib': { module: './instrumentation/amqplib' },
15
- 'cassandra-driver': { type: MODULE_TYPE.DATASTORE },
16
- 'connect': { type: MODULE_TYPE.WEB_FRAMEWORK },
17
- 'bluebird': { type: MODULE_TYPE.PROMISE },
18
- 'bunyan': { type: MODULE_TYPE.GENERIC },
19
- 'director': { type: MODULE_TYPE.WEB_FRAMEWORK },
20
- '@elastic/elasticsearch': { type: MODULE_TYPE.DATASTORE },
21
- 'express': { type: MODULE_TYPE.WEB_FRAMEWORK },
22
- 'fastify': { type: MODULE_TYPE.WEB_FRAMEWORK },
23
- 'generic-pool': { type: MODULE_TYPE.GENERIC },
15
+ 'cassandra-driver': { type: InstrumentationDescriptor.TYPE_DATASTORE },
16
+ 'connect': { type: InstrumentationDescriptor.TYPE_WEB_FRAMEWORK },
17
+ 'bluebird': { type: InstrumentationDescriptor.TYPE_PROMISE },
18
+ 'bunyan': { type: InstrumentationDescriptor.TYPE_GENERIC },
19
+ 'director': { type: InstrumentationDescriptor.TYPE_WEB_FRAMEWORK },
20
+ '@elastic/elasticsearch': { type: InstrumentationDescriptor.TYPE_DATASTORE },
21
+ 'express': { type: InstrumentationDescriptor.TYPE_WEB_FRAMEWORK },
22
+ 'fastify': { type: InstrumentationDescriptor.TYPE_WEB_FRAMEWORK },
23
+ 'generic-pool': { type: InstrumentationDescriptor.TYPE_GENERIC },
24
24
  '@grpc/grpc-js': { module: './instrumentation/grpc-js' },
25
- '@hapi/hapi': { type: MODULE_TYPE.WEB_FRAMEWORK },
26
- 'ioredis': { type: MODULE_TYPE.DATASTORE },
25
+ '@hapi/hapi': { type: InstrumentationDescriptor.TYPE_WEB_FRAMEWORK },
26
+ 'ioredis': { type: InstrumentationDescriptor.TYPE_DATASTORE },
27
27
  'koa': { module: '@newrelic/koa' },
28
28
  'langchain': { module: './instrumentation/langchain' },
29
- 'memcached': { type: MODULE_TYPE.DATASTORE },
30
- 'mongodb': { type: MODULE_TYPE.DATASTORE },
29
+ 'memcached': { type: InstrumentationDescriptor.TYPE_DATASTORE },
30
+ 'mongodb': { type: InstrumentationDescriptor.TYPE_DATASTORE },
31
31
  'mysql': { module: './instrumentation/mysql' },
32
- 'openai': { type: MODULE_TYPE.GENERIC },
33
- '@nestjs/core': { type: MODULE_TYPE.WEB_FRAMEWORK },
34
- '@prisma/client': { type: MODULE_TYPE.DATASTORE },
32
+ 'openai': { type: InstrumentationDescriptor.TYPE_GENERIC },
33
+ '@nestjs/core': { type: InstrumentationDescriptor.TYPE_WEB_FRAMEWORK },
34
+ '@prisma/client': { type: InstrumentationDescriptor.TYPE_DATASTORE },
35
35
  'pino': { module: './instrumentation/pino' },
36
- 'pg': { type: MODULE_TYPE.DATASTORE },
36
+ 'pg': { type: InstrumentationDescriptor.TYPE_DATASTORE },
37
37
  'q': { type: null },
38
- 'redis': { type: MODULE_TYPE.DATASTORE },
39
- '@node-redis/client': { type: MODULE_TYPE.DATASTORE },
40
- '@redis/client': { type: MODULE_TYPE.DATASTORE },
41
- 'restify': { type: MODULE_TYPE.WEB_FRAMEWORK },
38
+ 'redis': { type: InstrumentationDescriptor.TYPE_DATASTORE },
39
+ '@node-redis/client': { type: InstrumentationDescriptor.TYPE_DATASTORE },
40
+ '@redis/client': { type: InstrumentationDescriptor.TYPE_DATASTORE },
41
+ 'restify': { type: InstrumentationDescriptor.TYPE_WEB_FRAMEWORK },
42
42
  'superagent': { module: '@newrelic/superagent' },
43
- '@hapi/vision': { type: MODULE_TYPE.WEB_FRAMEWORK },
43
+ '@hapi/vision': { type: InstrumentationDescriptor.TYPE_WEB_FRAMEWORK },
44
44
  'when': { module: './instrumentation/when' },
45
- 'winston': { type: MODULE_TYPE.GENERIC },
45
+ 'winston': { type: InstrumentationDescriptor.TYPE_GENERIC },
46
46
  /**
47
47
  * The modules below are listed here purely to take
48
48
  * advantage of the Supportability/Features/onRequire/<module>
@@ -52,11 +52,11 @@ module.exports = function instrumentations() {
52
52
  * Libraries that have OpenTelemetry instrumentation we want to register
53
53
  * or have already registered.
54
54
  */
55
- 'loglevel': { type: MODULE_TYPE.TRACKING },
56
- 'npmlog': { type: MODULE_TYPE.TRACKING },
57
- 'fancy-log': { type: MODULE_TYPE.TRACKING },
58
- 'knex': { type: MODULE_TYPE.TRACKING },
59
- '@azure/openai': { type: MODULE_TYPE.TRACKING },
60
- '@langchain/community/llms/bedrock': { type: MODULE_TYPE.TRACKING }
55
+ 'loglevel': { type: InstrumentationDescriptor.TYPE_TRACKING },
56
+ 'npmlog': { type: InstrumentationDescriptor.TYPE_TRACKING },
57
+ 'fancy-log': { type: InstrumentationDescriptor.TYPE_TRACKING },
58
+ 'knex': { type: InstrumentationDescriptor.TYPE_TRACKING },
59
+ '@azure/openai': { type: InstrumentationDescriptor.TYPE_TRACKING },
60
+ '@langchain/community/llms/bedrock': { type: InstrumentationDescriptor.TYPE_TRACKING }
61
61
  }
62
62
  }
@@ -46,7 +46,6 @@ class LangChainEvent extends BaseEvent {
46
46
  appName
47
47
  span_id
48
48
  request_id
49
- transaction_id
50
49
  trace_id
51
50
  ingest_source = 'Node'
52
51
  vendor = 'langchain'
@@ -60,7 +59,6 @@ class LangChainEvent extends BaseEvent {
60
59
  this.appName = agent.config.applications()[0]
61
60
  this.span_id = segment?.id
62
61
  this.request_id = params.runId
63
- this.transaction_id = segment?.transaction?.id
64
62
  this.trace_id = segment?.transaction?.traceId
65
63
  this.langchainMeta = params.metadata
66
64
  this.metadata = agent
@@ -13,7 +13,6 @@ module.exports = class LlmChatCompletionSummary extends LlmEvent {
13
13
  this['request.max_tokens'] = request.max_tokens
14
14
  this['request.temperature'] = request.temperature
15
15
  this['response.number_of_messages'] = request?.messages?.length + response?.choices?.length
16
- this['response.usage.completion_tokens'] = response?.usage?.completion_tokens
17
16
  this['response.choices.finish_reason'] = response?.choices?.[0]?.finish_reason
18
17
  }
19
18
  }
@@ -17,7 +17,6 @@ module.exports = class LlmEvent extends BaseEvent {
17
17
  this.request_id = response?.headers?.['x-request-id']
18
18
  this.trace_id = segment?.transaction?.traceId
19
19
  this.span_id = segment?.id
20
- this.transaction_id = segment?.transaction?.id
21
20
  this['response.model'] = response.model
22
21
  this.vendor = 'openai'
23
22
  this.ingest_source = 'Node'
@@ -38,8 +37,6 @@ module.exports = class LlmEvent extends BaseEvent {
38
37
 
39
38
  responseAttrs(response) {
40
39
  this['response.organization'] = response?.headers?.['openai-organization']
41
- this['response.usage.total_tokens'] = response?.usage?.total_tokens
42
- this['response.usage.prompt_tokens'] = response?.usage?.prompt_tokens
43
40
  this['response.headers.llmVersion'] = response?.headers?.['openai-version']
44
41
  this['response.headers.ratelimitLimitRequests'] =
45
42
  response?.headers?.['x-ratelimit-limit-requests']