newrelic 14.1.2 → 14.2.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.
@@ -1,272 +0,0 @@
1
- /*
2
- * Copyright 2021 New Relic Corporation. All rights reserved.
3
- * SPDX-License-Identifier: Apache-2.0
4
- */
5
-
6
- 'use strict'
7
- const {
8
- QuerySpec,
9
- OperationSpec,
10
- params: { DatastoreParameters }
11
- } = require('../../shim/specs')
12
- const { CURSOR_OPS, COLLECTION_OPS, DB_OPS } = require('./constants')
13
- const common = module.exports
14
-
15
- /**
16
- * Instruments all methods from constants.CURSOR_OPS on a given
17
- * cursor class
18
- *
19
- * @param {Shim} shim instance of shim
20
- * @param {Cursor} Cursor mongodb Cursor prototype
21
- */
22
- common.instrumentCursor = function instrumentCursor(shim, Cursor) {
23
- if (Cursor && Cursor.prototype) {
24
- const proto = Cursor.prototype
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' }))
28
- }
29
- }
30
-
31
- /**
32
- * Instruments all methods from constants.COLLECTION_OPS on
33
- * the Collection class
34
- *
35
- * @param {Shim} shim instance of shim
36
- * @param {Collection} Collection mongodb Collection prototype
37
- */
38
- common.instrumentCollection = function instrumentCollection(shim, Collection) {
39
- if (Collection && Collection.prototype) {
40
- const proto = Collection.prototype
41
- shim.recordQuery(proto, COLLECTION_OPS, common.makeQueryDescFunc)
42
- }
43
- }
44
-
45
- /**
46
- * Instruments the execute method on
47
- * the BulkOperationBase class
48
- *
49
- * @param {Shim} shim instance of shim
50
- * @param {BulkOperationModule} BulkOperationModule operation module, typically from mongodb/lib/bulk/common
51
- */
52
- common.instrumentBulkOperation = function instrumentBulkOperation(shim, BulkOperationModule) {
53
- if (BulkOperationModule?.BulkOperationBase?.prototype) {
54
- const proto = BulkOperationModule.BulkOperationBase.prototype
55
- shim.recordBatchQuery(proto, 'execute', common.makeBulkDescFunc(shim, 'execute'))
56
- }
57
- }
58
-
59
- /**
60
- * Instruments all methods from constants.DB_OPS on
61
- * the Db class.
62
- *
63
- * @param {Shim} shim instance of shim
64
- * @param {Db} Db mongodb Db prototype
65
- */
66
- common.instrumentDb = function instrumentDb(shim, Db) {
67
- if (Db && Db.prototype) {
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)
78
- shim.recordOperation(
79
- Db,
80
- 'connect',
81
- new OperationSpec({ callback: shim.LAST, promise: true, name: 'connect' })
82
- )
83
- }
84
- }
85
-
86
- /**
87
- * Sets up the desc for all instrumented query methods
88
- *
89
- * @param {Shim} shim instance of shim
90
- * @param {Function} _fn function getting instrumented
91
- * @param {string} methodName name of function
92
- * @returns {QuerySpec} query spec
93
- */
94
- common.makeQueryDescFunc = function makeQueryDescFunc(shim, _fn, methodName) {
95
- if (methodName === 'each') {
96
- const parameters = getInstanceAttributeParameters(shim, this)
97
- return new QuerySpec({ query: methodName, parameters, rowCallback: shim.LAST, opaque: true })
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
- })
110
- }
111
-
112
- /**
113
- * Sets up the desc for all instrumented bulk operations
114
- *
115
- * @param {Shim} shim instance of shim
116
- * @returns {object} query spec
117
- */
118
- common.makeBulkDescFunc = function makeBulkDescFunc(shim) {
119
- return function bulkDescFunc() {
120
- const parameters = getInstanceAttributeParameters(shim, this)
121
- return new QuerySpec({
122
- query: this.isOrdered ? 'orderedBulk' : 'unorderedBulk',
123
- parameters,
124
- promise: true,
125
- callback: shim.LAST,
126
- opaque: true
127
- })
128
- }
129
- }
130
-
131
- /**
132
- * Sets up a listener for `started` on instrumenter(mongo APM). This applies to
133
- * mongo <4. The listener adds the following attributes to the active segment:
134
- * host, port_path_or_id, and database_name
135
- *
136
- * @param {Shim} shim instance of shim
137
- * @param {object} instrumenter instance of mongo APM class
138
- * @param {object} [options] provide command names to skip updating host/port as they are unrelated to the active query. This is only in v3 because after every command is runs `endSessions` which runs on the admin database
139
- */
140
- common.captureAttributesOnStarted = function captureAttributesOnStarted(
141
- shim,
142
- instrumenter,
143
- options = { skipCommands: [] }
144
- ) {
145
- instrumenter.on('started', function onMongoEventStarted(evnt) {
146
- if (options.skipCommands.includes(evnt.commandName)) {
147
- return
148
- }
149
- // This assumes that this `started` event is fired _after_ our wrapper
150
- // starts and creates the segment. We perform a check of the segment name
151
- // out of an excess of caution.
152
- const connId = evnt.connectionId
153
-
154
- if (connId) {
155
- // used in v3 when connection is a cluster pool
156
- if (typeof connId === 'number') {
157
- setHostPort(shim, evnt.address, evnt.databaseName)
158
- // used in v3 when connection is to 1 host
159
- } else if (typeof connId === 'string') {
160
- setHostPort(shim, connId, evnt.databaseName)
161
- // v2 remote connection get `host` `port` from respective properties
162
- } else {
163
- shim.captureInstanceAttributes(connId.host, connId.port, evnt.databaseName)
164
- }
165
- }
166
- })
167
- }
168
-
169
- /**
170
- * Extracts the host and port from a connection string
171
- *
172
- * @param {Shim} shim instance of shim
173
- * @param {string} connStr mongo connection string
174
- * @param {string} db database name
175
- */
176
- function setHostPort(shim, connStr, db) {
177
- const parts = common.parseAddress(connStr)
178
- shim.captureInstanceAttributes(parts[0], parts[1], db)
179
- }
180
-
181
- /**
182
- * Get the database_name, host, port_path_or_id
183
- * for the query segment. v4 refactored where the topology is stored.
184
- * You can now get the details via the client obj that's deeply nested
185
- * See: https://github.com/mongodb/node-mongodb-native/pull/2594/files#diff-1d214e57ddda9095d296e5700ebce701333bfefcf417e234c584d14091b2f50dR168
186
- *
187
- * @param {Shim} shim instance of shim
188
- * @param {object} mongo instance of mongo
189
- * @returns {object} db params
190
- */
191
- function getInstanceAttributeParameters(shim, mongo) {
192
- let params
193
- if (mongo?.s?.topology) {
194
- shim.logger.trace('Adding datastore instance attributes from mongo.s.db + mongo.s.topology')
195
- const databaseName = mongo?.s?.db?.databaseName || mongo?.s?.namespace?.db || null
196
- const topology = mongo.s.topology
197
- params = getParametersFromTopology(topology, databaseName)
198
- } else if (mongo?.s?.db?.s?.client?.s?.options?.hosts?.length) {
199
- const databaseName = mongo?.s?.db?.databaseName || null
200
- const hosts = mongo.s.db.s.client.s.options.hosts
201
- params = getParametersFromHosts(hosts, databaseName)
202
- } else if (mongo?.s?.db?.client?.topology) {
203
- const databaseName = mongo?.s?.namespace?.db
204
- const topology = mongo.s.db.client.topology
205
- params = getParametersFromTopology(topology, databaseName)
206
- } else {
207
- shim.logger.trace('Could not find datastore instance attributes.')
208
- params = new DatastoreParameters()
209
- }
210
-
211
- return params
212
- }
213
-
214
- /**
215
- * Extracts the database parameters from the first host.
216
- *
217
- * @param {Array} hosts mongodb connected hosts
218
- * @param {string} database name of database
219
- * @returns {object} db params
220
- */
221
- function getParametersFromHosts(hosts, database) {
222
- const [{ host, port }] = hosts
223
-
224
- return new DatastoreParameters({
225
- host,
226
- port_path_or_id: port,
227
- database_name: database
228
- })
229
- }
230
-
231
- /**
232
- * Extracts the database parameters from the relevant
233
- * topology configuration
234
- *
235
- * @param {object} conf topology configuration
236
- * @param {string} database name of database
237
- * @returns {object} db params
238
- */
239
- function getParametersFromTopology(conf, database) {
240
- // in older versions of 3.x the host/port
241
- // lived directly on the topology
242
- let { host, port } = conf
243
-
244
- // servers is an array but we will always pull the first for consistency
245
- if (conf?.s?.options?.servers?.length) {
246
- ;[{ host, port }] = conf.s.options.servers
247
- }
248
-
249
- // hosts is an array but we will always pull the first for consistency
250
- if (conf?.s?.options?.hosts?.length) {
251
- ;[{ host, port }] = conf.s.options.hosts
252
- }
253
-
254
- return new DatastoreParameters({
255
- host,
256
- port_path_or_id: port,
257
- database_name: database
258
- })
259
- }
260
-
261
- /**
262
- * Parses mongo address that accounts for IPv6
263
- *
264
- * @param {string} address mongo address string
265
- * @returns {Array} host/port of address string
266
- */
267
- common.parseAddress = function parseAddress(address) {
268
- const lastColon = address.lastIndexOf(':')
269
- const host = address.slice(0, lastColon)
270
- const port = address.slice(lastColon + 1)
271
- return [host, port]
272
- }
@@ -1,87 +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 DB_OPS = [
9
- 'addUser',
10
- 'authenticate',
11
- 'collection',
12
- 'collectionNames',
13
- 'collections',
14
- 'command',
15
- 'createCollection',
16
- 'createIndex',
17
- 'cursorInfo',
18
- 'dereference',
19
- 'dropCollection',
20
- 'dropDatabase',
21
- 'dropIndex',
22
- 'ensureIndex',
23
- 'eval',
24
- 'executeDbAdminCommand',
25
- 'indexInformation',
26
- 'logout',
27
- 'open',
28
- 'reIndex',
29
- 'removeUser',
30
- 'renameCollection',
31
- 'stats',
32
- '_executeInsertCommand',
33
- '_executeQueryCommand'
34
- ]
35
-
36
- const COLLECTION_OPS = [
37
- 'aggregate',
38
- 'bulkWrite',
39
- 'count',
40
- 'createIndex',
41
- 'deleteMany',
42
- 'deleteOne',
43
- 'distinct',
44
- 'drop',
45
- 'dropAllIndexes',
46
- 'dropIndex',
47
- 'ensureIndex',
48
- 'findAndModify',
49
- 'findAndRemove',
50
- 'findOne',
51
- 'findOneAndDelete',
52
- 'findOneAndReplace',
53
- 'findOneAndUpdate',
54
- 'geoHaystackSearch',
55
- 'geoNear',
56
- 'group',
57
- 'indexes',
58
- 'indexExists',
59
- 'indexInformation',
60
- 'insert',
61
- 'insertMany',
62
- 'insertOne',
63
- 'isCapped',
64
- 'mapReduce',
65
- 'options',
66
- 'parallelCollectionScan',
67
- 'reIndex',
68
- 'remove',
69
- 'rename',
70
- 'replaceOne',
71
- 'save',
72
- 'stats',
73
- 'update',
74
- 'updateMany',
75
- 'updateOne'
76
- ]
77
-
78
- const GRID_OPS = ['put', 'get', 'delete']
79
-
80
- const CURSOR_OPS = ['nextObject', 'next', 'toArray', 'count', 'explain']
81
-
82
- module.exports = {
83
- COLLECTION_OPS,
84
- CURSOR_OPS,
85
- DB_OPS,
86
- GRID_OPS
87
- }
@@ -1,75 +0,0 @@
1
- /*
2
- * Copyright 2021 New Relic Corporation. All rights reserved.
3
- * SPDX-License-Identifier: Apache-2.0
4
- */
5
-
6
- 'use strict'
7
-
8
- const { OperationSpec } = require('../../shim/specs')
9
- const {
10
- instrumentBulkOperation,
11
- instrumentCollection,
12
- instrumentCursor,
13
- instrumentDb,
14
- parseAddress
15
- } = require('./common')
16
- const queryParser = require('../../db/query-parsers/mongodb')
17
-
18
- /**
19
- * `commandStarted` handler used to
20
- * update host, port and database_name
21
- * on segment attributes
22
- *
23
- * @param {Shim} shim instance of shim
24
- * @param {CommandStartedEvent} evnt mongodb event
25
- */
26
- function cmdStartedHandler(shim, evnt) {
27
- if (evnt.connectionId) {
28
- const address = parseAddress(evnt.address)
29
- let [host] = address
30
- const [, port] = address
31
- if (['127.0.0.1', '::1', '[::1]'].includes(host)) {
32
- host = 'localhost'
33
- }
34
-
35
- shim.captureInstanceAttributes(host, port, evnt.databaseName)
36
- }
37
- }
38
-
39
- /**
40
- * function executed when client.connect is called
41
- * enable APM(monitorCommands) and add the
42
- * `commandStarted` listener
43
- *
44
- * @param {Shim} shim instance of shim
45
- * @returns {OperationSpec} spec to capture connect method
46
- */
47
- function wrapConnect(shim) {
48
- this.monitorCommands = true
49
- this.on('commandStarted', cmdStartedHandler.bind(this, shim))
50
- return new OperationSpec({ callback: shim.LAST, name: 'connect' })
51
- }
52
-
53
- /**
54
- * Wraps connect to record as operation but also to add a listener
55
- * for `commandStarted`. This will be emitted before every command starts
56
- * so we can properly update the segment attributes with a more accurate
57
- * host/port/database name
58
- *
59
- * @param {Shim} shim instance of shim
60
- * @param {MongoClient} MongoClient reference
61
- */
62
- function instrumentMongoClient(shim, MongoClient) {
63
- shim.recordOperation(MongoClient.prototype, 'connect', wrapConnect)
64
- }
65
-
66
- module.exports = function instrument(shim, mongodb) {
67
- shim.setParser(queryParser)
68
- instrumentMongoClient(shim, mongodb.MongoClient)
69
- instrumentCursor(shim, mongodb.AbstractCursor)
70
- instrumentCursor(shim, mongodb.FindCursor)
71
- instrumentCursor(shim, mongodb.AggregationCursor)
72
- instrumentCollection(shim, mongodb.Collection)
73
- instrumentDb(shim, mongodb.Db)
74
- instrumentBulkOperation(shim, shim.require('./lib/bulk/common'))
75
- }
@@ -1,46 +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 semver = require('semver')
9
- const instrumentV4 = require('./mongodb/v4-mongo')
10
-
11
- // XXX: When this instrumentation is modularized, update this thread
12
- // with a cautionary note:
13
- // https://discuss.newrelic.com/t/feature-idea-using-mongoose-cursors-memory-leaking-very-quickly/49270/14
14
- //
15
- // This instrumentation is deep linked against in the mongoose instrumentation
16
- // snippet. The snippet will break once this file is moved from this
17
- // location.
18
-
19
- module.exports = initialize
20
-
21
- /**
22
- * Registers the query parser, and relevant instrumentation
23
- * based on version of mongodb
24
- *
25
- * @param {Agent} agent instance
26
- * @param {object} mongodb resolved package
27
- * @param {string} moduleName name of module
28
- * @param {Shim} shim instance
29
- */
30
- function initialize(agent, mongodb, moduleName, shim) {
31
- if (!mongodb) {
32
- return
33
- }
34
-
35
- const mongoVersion = shim.pkgVersion
36
- if (semver.satisfies(mongoVersion, '<4.0.0')) {
37
- shim.logger.warn(
38
- 'New Relic Node.js agent no longer supports mongodb < 4, current version %s. Please downgrade to v11 for support, if needed',
39
- mongoVersion
40
- )
41
- return
42
- }
43
-
44
- shim.setDatastore(shim.MONGODB)
45
- instrumentV4(shim, mongodb)
46
- }