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 +32 -0
- package/THIRD_PARTY_NOTICES.md +2 -2
- package/api.js +1 -1
- package/lib/instrumentation/cassandra-driver.js +3 -1
- package/lib/instrumentation/mongodb/common.js +36 -76
- package/lib/instrumentation/mongodb/v2-mongo.js +10 -6
- package/lib/instrumentation/mongodb/v3-mongo.js +7 -10
- package/lib/instrumentation/mongodb/v4-mongo.js +12 -18
- package/lib/instrumentation/pg.js +3 -3
- package/lib/instrumentation-descriptor.js +29 -0
- package/lib/instrumentations.js +30 -30
- package/lib/llm-events/langchain/event.js +0 -2
- package/lib/llm-events/openai/chat-completion-summary.js +0 -1
- package/lib/llm-events/openai/event.js +0 -3
- package/lib/shim/conglomerate-shim.js +15 -14
- package/lib/shim/datastore-shim.js +18 -15
- package/lib/shim/index.js +8 -10
- package/lib/shim/message-shim/consume.js +1 -2
- package/lib/shim/message-shim/index.js +19 -39
- package/lib/shim/message-shim/subscribe-consume.js +3 -4
- package/lib/shim/promise-shim.js +32 -27
- package/lib/shim/shim.js +10 -16
- package/lib/shim/specs/wrap.js +2 -10
- package/lib/shim/webframework-shim/common.js +0 -20
- package/lib/shim/webframework-shim/index.js +18 -44
- package/lib/shim/webframework-shim/middleware-mounter.js +1 -9
- package/lib/shim/webframework-shim/middleware.js +7 -6
- package/lib/shimmer.js +83 -67
- package/lib/symbols.js +0 -2
- package/package.json +6 -6
- package/lib/shim/constants.js +0 -42
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
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -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.
|
|
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.
|
|
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/
|
|
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
|
-
|
|
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
|
-
|
|
27
|
-
|
|
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
|
-
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
new OperationSpec({ callback: shim.LAST,
|
|
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 {
|
|
90
|
-
* @
|
|
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
|
|
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
|
|
176
|
+
function setHostPort(shim, connStr, db) {
|
|
187
177
|
const parts = common.parseAddress(connStr)
|
|
188
|
-
|
|
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
|
-
|
|
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
|
|
98
|
+
shim.recordQuery(proto, method, makeDescFunc)
|
|
99
99
|
} else if (isQuery === false) {
|
|
100
100
|
// could be unset
|
|
101
|
-
shim.recordOperation(proto, method, makeDescFunc
|
|
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(
|
|
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
|
|
48
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
+
}
|
package/lib/instrumentations.js
CHANGED
|
@@ -5,44 +5,44 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
const
|
|
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:
|
|
16
|
-
'connect': { type:
|
|
17
|
-
'bluebird': { type:
|
|
18
|
-
'bunyan': { type:
|
|
19
|
-
'director': { type:
|
|
20
|
-
'@elastic/elasticsearch': { type:
|
|
21
|
-
'express': { type:
|
|
22
|
-
'fastify': { type:
|
|
23
|
-
'generic-pool': { type:
|
|
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:
|
|
26
|
-
'ioredis': { type:
|
|
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:
|
|
30
|
-
'mongodb': { type:
|
|
29
|
+
'memcached': { type: InstrumentationDescriptor.TYPE_DATASTORE },
|
|
30
|
+
'mongodb': { type: InstrumentationDescriptor.TYPE_DATASTORE },
|
|
31
31
|
'mysql': { module: './instrumentation/mysql' },
|
|
32
|
-
'openai': { type:
|
|
33
|
-
'@nestjs/core': { type:
|
|
34
|
-
'@prisma/client': { type:
|
|
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:
|
|
36
|
+
'pg': { type: InstrumentationDescriptor.TYPE_DATASTORE },
|
|
37
37
|
'q': { type: null },
|
|
38
|
-
'redis': { type:
|
|
39
|
-
'@node-redis/client': { type:
|
|
40
|
-
'@redis/client': { type:
|
|
41
|
-
'restify': { type:
|
|
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:
|
|
43
|
+
'@hapi/vision': { type: InstrumentationDescriptor.TYPE_WEB_FRAMEWORK },
|
|
44
44
|
'when': { module: './instrumentation/when' },
|
|
45
|
-
'winston': { type:
|
|
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:
|
|
56
|
-
'npmlog': { type:
|
|
57
|
-
'fancy-log': { type:
|
|
58
|
-
'knex': { type:
|
|
59
|
-
'@azure/openai': { type:
|
|
60
|
-
'@langchain/community/llms/bedrock': { type:
|
|
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']
|