newrelic 8.0.0 → 8.1.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.
@@ -0,0 +1,97 @@
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 = [
79
+ 'put',
80
+ 'get',
81
+ 'delete'
82
+ ]
83
+
84
+ const CURSOR_OPS = [
85
+ 'nextObject',
86
+ 'next',
87
+ 'toArray',
88
+ 'count',
89
+ 'explain'
90
+ ]
91
+
92
+ module.exports = {
93
+ COLLECTION_OPS,
94
+ CURSOR_OPS,
95
+ DB_OPS,
96
+ GRID_OPS
97
+ }
@@ -0,0 +1,108 @@
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 {
9
+ captureAttributesOnStarted,
10
+ makeQueryDescFunc
11
+ } = require('./common')
12
+
13
+ /**
14
+ * parser used to grab the collection and operation
15
+ * from a running query
16
+ *
17
+ * @param {Object} operation
18
+ */
19
+ function queryParser(operation) {
20
+ let collection = this.collectionName || 'unknown'
21
+ if (this.ns) {
22
+ collection = this.ns.split(/\./)[1] || collection
23
+ }
24
+
25
+ return {operation, collection}
26
+ }
27
+ /**
28
+ * Registers relevant instrumentation for mongo <= 3.0.6
29
+ * and >= 2. This relies on the built-in "APM" hook points
30
+ * to instrument their provided objects as well as sets
31
+ * up a listener for when commands start to properly
32
+ * add necessary attributes to segments
33
+ *
34
+ * @param {Shim} shim
35
+ * @param {Object} mongodb resolved package
36
+ */
37
+ module.exports = function instrument(shim, mongodb) {
38
+ shim.setParser(queryParser)
39
+
40
+ const recordDesc = {
41
+ 'Gridstore': {isQuery: false, makeDescFunc: function makeGridDesc(opName) {
42
+ return {name:'GridFS-' + opName, callback: shim.LAST}
43
+ }},
44
+ 'OrderedBulkOperation': {isQuery: true, makeDescFunc: makeQueryDescFunc},
45
+ 'UnorderedBulkOperation': {isQuery: true, makeDescFunc: makeQueryDescFunc},
46
+ 'CommandCursor': {isQuery: true, makeDescFunc: makeQueryDescFunc},
47
+ 'AggregationCursor': {isQuery: true, makeDescFunc: makeQueryDescFunc},
48
+ 'Cursor': {isQuery: true, makeDescFunc: makeQueryDescFunc},
49
+ 'Collection': {isQuery: true, makeDescFunc: makeQueryDescFunc},
50
+ 'Db': {isQuery: false, makeDescFunc: function makeDbDesc() {
51
+ return {callback: shim.LAST}
52
+ }}
53
+ }
54
+
55
+ // instrument using the apm api
56
+ const instrumenter = mongodb.instrument(Object.create(null), instrumentModules)
57
+ captureAttributesOnStarted(shim, instrumenter)
58
+
59
+ /**
60
+ * Every module groups instrumentations by their
61
+ * promise, callback, return permutations
62
+ * Iterate over permutations and properly
63
+ * wrap depending on the `recordDesc` above
64
+ * See: https://github.com/mongodb/node-mongodb-native/blob/v3.0.5/lib/collection.js#L384
65
+ */
66
+ function instrumentModules(_, modules) {
67
+ modules.forEach((module) => {
68
+ const { obj, instrumentations, name } = module
69
+ instrumentations.forEach((meta) => {
70
+ applyInstrumentation(name, obj, meta)
71
+ })
72
+ })
73
+ }
74
+
75
+ /**
76
+ * Iterate over methods on object and lookup in `recordDesc` to decide
77
+ * if it needs to be wrapped as an operation or query
78
+ *
79
+ * @param {string} objectName name of class getting instrumented
80
+ * @param {Object} object reference to the class getting instrumented
81
+ * @param {Define} meta describes the methods and if they are callbacks
82
+ * promises, and return values
83
+ */
84
+ function applyInstrumentation(objectName, object, meta) {
85
+ const { methods, options } = meta
86
+ if (options.callback) {
87
+ methods.forEach((method) => {
88
+ const { isQuery, makeDescFunc } = recordDesc[objectName]
89
+ const proto = object.prototype
90
+ if (isQuery) {
91
+ shim.recordQuery(proto, method, makeDescFunc(shim, method))
92
+ } else if (isQuery === false) { // could be unset
93
+ shim.recordOperation(proto, method, makeDescFunc(shim, method))
94
+ } else {
95
+ shim.logger.trace('No wrapping method found for %s', objectName)
96
+ }
97
+ })
98
+ }
99
+
100
+ // the cursor object implements Readable stream and internally calls nextObject on
101
+ // each read, in which case we do not want to record each nextObject() call
102
+ if (/Cursor$/.test(objectName)) {
103
+ shim.recordOperation(object.prototype, 'pipe')
104
+ }
105
+ }
106
+ }
107
+
108
+
@@ -0,0 +1,61 @@
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 {
9
+ captureAttributesOnStarted,
10
+ instrumentCollection,
11
+ instrumentCursor,
12
+ instrumentDb
13
+ } = require('./common')
14
+
15
+ /**
16
+ * parser used to grab the collection and operation
17
+ * on every mongo operation
18
+ *
19
+ * @param {Object} operation
20
+ */
21
+ function queryParser(operation) {
22
+ let collection = this.collectionName || 'unknown'
23
+ // in v3.3.0 aggregate commands added the collection
24
+ // to target
25
+ if (this.operation && this.operation.target) {
26
+ collection = this.operation.target
27
+ } else if (this.ns) {
28
+ collection = this.ns.split(/\./)[1] || collection
29
+ }
30
+ return {operation, collection}
31
+ }
32
+
33
+ /**
34
+ * Registers relevant instrumentation for mongo >= 3.0.6
35
+ * In 3.0.6 they refactored their "APM" module which removed
36
+ * a lot of niceities around instrumentation classes.
37
+ * see: https://github.com/mongodb/node-mongodb-native/pull/1675/files
38
+ * This reverts back to instrumenting pre-canned methods on classes
39
+ * as well as sets up a listener for when commands start to properly
40
+ * add necessary attributes to segments
41
+ *
42
+ * @param {Shim} shim
43
+ * @param {Object} mongodb resolved package
44
+ */
45
+ module.exports = function instrument(shim, mongodb) {
46
+ shim.setParser(queryParser)
47
+ const instrumenter = mongodb.instrument(Object.create(null), () => {})
48
+ captureAttributesOnStarted(shim, instrumenter)
49
+ instrumentCursor(shim, mongodb.Cursor)
50
+ instrumentCursor(shim, shim.require('./lib/aggregation_cursor'))
51
+ instrumentCursor(shim, shim.require('./lib/command_cursor'))
52
+ instrumentCollection(shim, mongodb.Collection)
53
+ instrumentDb(shim, mongodb.Db)
54
+
55
+ // calling instrument sets up listeners for a few events
56
+ // we should restore this on unload to avoid leaking
57
+ // event emitters
58
+ shim.agent.once('unload', function uninstrumentMongo() {
59
+ instrumenter.uninstrument()
60
+ })
61
+ }
@@ -0,0 +1,96 @@
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 {
9
+ instrumentCollection,
10
+ instrumentCursor,
11
+ instrumentDb
12
+ } = require('./common')
13
+
14
+ /**
15
+ * parser used to grab the collection and operation
16
+ * from a running query
17
+ *
18
+ * @param {Object} operation
19
+ */
20
+ function queryParser(operation) {
21
+ let collection = this.collectionName || 'unknown'
22
+
23
+ // cursor methods have collection on namespace.collection
24
+ if (this.namespace && this.namespace.collection) {
25
+ collection = this.namespace.collection
26
+ }
27
+
28
+ return {operation, collection}
29
+ }
30
+
31
+ /**
32
+ * `commandStarted` handler used to
33
+ * update host, port and database_name
34
+ * on segment attributes
35
+ *
36
+ * @param {Shim} shim
37
+ * @param {CommandStartedEvent} evnt
38
+ */
39
+ function cmdStartedHandler(shim, evnt) {
40
+ if (evnt.connectionId) {
41
+ let [host,port] = evnt.address.split(':')
42
+
43
+ // connection via socket get port from client.url
44
+ // which looks like "mongodb://%2Ftmp%2Fmongodb-27017.sock"
45
+ if (['undefined'].includes(host, port)) {
46
+ host = 'localhost'
47
+ // socket path is uri encoded
48
+ // decode it to properly name attrs
49
+ const socketPath = this.s.url.split(':')
50
+ if (socketPath.length && socketPath[1].startsWith('//')) {
51
+ port = decodeURIComponent(socketPath[1].substr(2))
52
+ }
53
+ } else if (host === '127.0.0.1') {
54
+ host = 'localhost'
55
+ }
56
+
57
+ shim.captureInstanceAttributes(host, port, evnt.databaseName)
58
+ }
59
+ }
60
+
61
+ /**
62
+ * function executed when client.connect is called
63
+ * enable APM(monitorCommands) and add the
64
+ * `commandStarted` listener
65
+ *
66
+ * @param {Shim} shim
67
+ */
68
+ function wrapConnect(shim) {
69
+ this.monitorCommands = true
70
+ this.on('commandStarted', cmdStartedHandler.bind(this, shim))
71
+ return { callback: shim.LAST }
72
+ }
73
+
74
+ /**
75
+ * Wraps connect to record as operation but also to add a listener
76
+ * for `commandStarted`. This will be emitted before every command starts
77
+ * so we can properly update the segment attributes with a more accurate
78
+ * host/port/database name
79
+ *
80
+ * @param {Shim} shim
81
+ * @param {MongoClient} MongoClient reference
82
+ */
83
+ function instrumentMongoClient(shim, MongoClient) {
84
+ shim.recordOperation(MongoClient.prototype, 'connect', wrapConnect)
85
+ }
86
+
87
+
88
+ module.exports = function instrument(shim, mongodb) {
89
+ shim.setParser(queryParser)
90
+ instrumentMongoClient(shim, mongodb.MongoClient)
91
+ instrumentCursor(shim, mongodb.AbstractCursor)
92
+ instrumentCursor(shim, mongodb.FindCursor)
93
+ instrumentCursor(shim, mongodb.AggregationCursor)
94
+ instrumentCollection(shim, mongodb.Collection)
95
+ instrumentDb(shim, mongodb.Db)
96
+ }
@@ -6,6 +6,9 @@
6
6
  'use strict'
7
7
 
8
8
  const semver = require('semver')
9
+ const instrument = require('./mongodb/v2-mongo')
10
+ const instrumentV3 = require('./mongodb/v3-mongo')
11
+ const instrumentV4 = require('./mongodb/v4-mongo')
9
12
 
10
13
  // XXX: When this instrumentation is modularized, update this thread
11
14
  // with a cautionary note:
@@ -15,325 +18,29 @@ const semver = require('semver')
15
18
  // snippet. The snippet will break once this file is moved from this
16
19
  // location.
17
20
 
18
- // legacy endpoint enumerations
19
- const DB_OPS = [
20
- 'addUser',
21
- 'authenticate',
22
- 'collection',
23
- 'collectionNames',
24
- 'collections',
25
- 'command',
26
- 'createCollection',
27
- 'createIndex',
28
- 'cursorInfo',
29
- 'dereference',
30
- 'dropCollection',
31
- 'dropDatabase',
32
- 'dropIndex',
33
- 'ensureIndex',
34
- 'eval',
35
- 'executeDbAdminCommand',
36
- 'indexInformation',
37
- 'logout',
38
- 'open',
39
- 'reIndex',
40
- 'removeUser',
41
- 'renameCollection',
42
- 'stats',
43
- '_executeInsertCommand',
44
- '_executeQueryCommand'
45
- ]
46
-
47
- const COLLECTION_OPS = [
48
- 'aggregate',
49
- 'bulkWrite',
50
- 'count',
51
- 'createIndex',
52
- 'deleteMany',
53
- 'deleteOne',
54
- 'distinct',
55
- 'drop',
56
- 'dropAllIndexes',
57
- 'dropIndex',
58
- 'ensureIndex',
59
- 'findAndModify',
60
- 'findAndRemove',
61
- 'findOne',
62
- 'findOneAndDelete',
63
- 'findOneAndReplace',
64
- 'findOneAndUpdate',
65
- 'geoHaystackSearch',
66
- 'geoNear',
67
- 'group',
68
- 'indexes',
69
- 'indexExists',
70
- 'indexInformation',
71
- 'insert',
72
- 'insertMany',
73
- 'insertOne',
74
- 'isCapped',
75
- 'mapReduce',
76
- 'options',
77
- 'parallelCollectionScan',
78
- 'reIndex',
79
- 'remove',
80
- 'rename',
81
- 'replaceOne',
82
- 'save',
83
- 'stats',
84
- 'update',
85
- 'updateMany',
86
- 'updateOne'
87
- ]
88
-
89
- const GRID_OPS = [
90
- 'put',
91
- 'get',
92
- 'delete'
93
- ]
94
-
95
- const CURSOR_OPS = [
96
- 'nextObject',
97
- 'next',
98
- 'toArray',
99
- 'count',
100
- 'explain'
101
- ]
102
-
103
21
  module.exports = initialize
104
22
 
23
+ /**
24
+ * Registers the query parser, and relevant instrumentation
25
+ * based on version of mongodb
26
+ *
27
+ * @param {Agent} agent
28
+ * @param {Object} mongodb resolved package
29
+ * @param {string} moduleName name of module
30
+ * @param {Shim} shim
31
+ */
105
32
  function initialize(agent, mongodb, moduleName, shim) {
106
33
  if (!mongodb) return
107
34
 
108
35
  shim.setDatastore(shim.MONGODB)
109
- shim.setParser(function mongoQueryParser(operation) {
110
- let collection = this.collectionName || 'unknown'
111
- if (this.collection && this.collection.collectionName) {
112
- collection = this.collection.collectionName
113
- } else if (this.s && this.s.name) {
114
- collection = this.s.name
115
- } else if (this.ns) {
116
- collection = this.ns.split(/\./)[1] || collection
117
- }
118
-
119
- return {operation, collection}
120
- })
121
36
 
122
37
  const mongoVersion = shim.require('./package.json').version
123
- if (semver.satisfies(mongoVersion, '>=3.0.6') && mongodb.instrument) {
124
- instrument306(shim, mongodb)
125
- } else if (mongodb.instrument) {
126
- instrumentInstrument(shim, mongodb)
38
+ if (semver.satisfies(mongoVersion, '>=4.0.0')) {
39
+ instrumentV4(shim, mongodb)
40
+ } else if (semver.satisfies(mongoVersion, '>=3.0.6')) {
41
+ instrumentV3(shim, mongodb)
127
42
  } else {
128
- instrumentLegacy(shim, mongodb)
129
- }
130
- }
131
-
132
- function instrument306(shim, mongodb) {
133
- const instrumenter = mongodb.instrument(Object.create(null), () => {})
134
- captureAttributesOnStarted(shim, instrumenter)
135
- instrumentLegacy(shim, mongodb)
136
-
137
- if (shim.isFunction(instrumenter.uninstrument)) {
138
- shim.agent.once('unload', function uninstrumentMongo() {
139
- instrumenter.uninstrument()
140
- })
141
- }
142
- }
143
-
144
- function instrumentInstrument(shim, mongodb) {
145
- const recordDesc = {
146
- 'Gridstore': {isQuery: false, makeDesc: function makeGridDesc(opName) {
147
- return {name:'GridFS-' + opName, callback: shim.LAST}
148
- }},
149
- 'OrderedBulkOperation': {isQuery: true, makeDesc: makeQueryDescFunc},
150
- 'UnorderedBulkOperation': {isQuery: true, makeDesc: makeQueryDescFunc},
151
- 'CommandCursor': {isQuery: true, makeDesc: makeQueryDescFunc},
152
- 'AggregationCursor': {isQuery: true, makeDesc: makeQueryDescFunc},
153
- 'Cursor': {isQuery: true, makeDesc: makeQueryDescFunc},
154
- 'Collection': {isQuery: true, makeDesc: makeQueryDescFunc},
155
- 'Db': {isQuery: false, makeDesc: function makeDbDesc() {
156
- return {callback: shim.LAST}
157
- }}
158
- }
159
-
160
- // instrument using the apm api
161
- const instrumenter = mongodb.instrument(Object.create(null), instrumentModules)
162
- captureAttributesOnStarted(shim, instrumenter)
163
-
164
- function instrumentModules(err, instrumentations) {
165
- if (err) {
166
- shim.logger
167
- .trace('Unable to instrument mongo using the apm api due to error: %s', err)
168
- // fallback to legacy instrumentation?
169
- return
170
- }
171
- instrumentations.forEach(instrumentModule)
172
- }
173
-
174
- function instrumentModule(module) {
175
- var object = module.obj
176
- var instrumentations = module.instrumentations
177
- for (var i = 0; i < instrumentations.length; i++) {
178
- applyInstrumentation(module.name, object, instrumentations[i])
179
- }
180
- }
181
-
182
- function applyInstrumentation(objectName, object, instrumentation) {
183
- var methods = instrumentation.methods
184
- var methodOptions = instrumentation.options
185
- if (methodOptions.callback) {
186
- for (var j = 0; j < methods.length; j++) {
187
- var method = methods[j]
188
-
189
- var isQuery = recordDesc[objectName].isQuery
190
- var makeDescFunc = recordDesc[objectName].makeDesc
191
- var proto = object.prototype
192
- if (isQuery) {
193
- shim.recordQuery(proto, method, makeDescFunc(shim, method))
194
- } else if (isQuery === false) { // could be unset
195
- shim.recordOperation(proto, method, makeDescFunc(shim, method))
196
- } else {
197
- shim.logger.trace('No wrapping method found for %s', objectName)
198
- }
199
- }
200
- }
201
-
202
- // the cursor object implements Readable stream and internally calls nextObject on
203
- // each read, in which case we do not want to record each nextObject() call
204
- if (/Cursor$/.test(objectName)) {
205
- shim.recordOperation(object.prototype, 'pipe')
206
- }
207
- }
208
- }
209
-
210
- function captureAttributesOnStarted(shim, instrumenter) {
211
- instrumenter.on('started', function onMongoEventStarted(evnt) {
212
- // This assumes that this `started` event is fired _after_ our wrapper
213
- // starts and creates the segment. We perform a check of the segment name
214
- // out of an excess of caution.
215
- const connId = evnt.connectionId
216
- if (connId) {
217
- // Mongo sticks the path to the domain socket in the "host" slot, but we
218
- // want it in the "port", so if we have a domain socket we need to change
219
- // the order of our parameters.
220
- if (typeof connId === 'string') {
221
- const parts = connId.split(':')
222
- if (parts.length && parts[0][0] === '/') {
223
- shim.captureInstanceAttributes('localhost', parts[0], evnt.databaseName)
224
- } else {
225
- shim.captureInstanceAttributes(parts[0], parts[1], evnt.databaseName)
226
- }
227
- } else if (connId.domainSocket) {
228
- shim.captureInstanceAttributes('localhost', connId.host, evnt.databaseName)
229
- } else {
230
- shim.captureInstanceAttributes(connId.host, connId.port, evnt.databaseName)
231
- }
232
- }
233
- })
234
- }
235
-
236
- function instrumentLegacy(shim, mongodb) {
237
- instrumentCursor(mongodb.Cursor)
238
- instrumentCursor(shim.require('./lib/aggregation_cursor'))
239
- instrumentCursor(shim.require('./lib/command_cursor'))
240
-
241
- if (mongodb.Collection && mongodb.Collection.prototype) {
242
- const proto = mongodb.Collection.prototype
243
- for (let i = 0; i < COLLECTION_OPS.length; i++) {
244
- shim.recordQuery(
245
- proto,
246
- COLLECTION_OPS[i],
247
- makeQueryDescFunc(shim, COLLECTION_OPS[i])
248
- )
249
- }
250
- }
251
-
252
- if (mongodb.Grid && mongodb.Grid.prototype) {
253
- const proto = mongodb.Grid.prototype
254
- for (let i = 0; i < CURSOR_OPS.length; i++) {
255
- shim.recordOperation(proto, GRID_OPS[i],
256
- {name:'GridFS-' + GRID_OPS[i], callback: shim.LAST})
257
- }
258
- }
259
-
260
- if (mongodb.Db && mongodb.Db.prototype) {
261
- const proto = mongodb.Db.prototype
262
- shim.recordOperation(proto, DB_OPS, {callback: shim.LAST})
263
- shim.recordOperation(mongodb.Db, 'connect', {callback: shim.LAST})
264
- }
265
-
266
- function instrumentCursor(Cursor) {
267
- if (Cursor && Cursor.prototype) {
268
- const proto = Cursor.prototype
269
- for (let i = 0; i < CURSOR_OPS.length; i++) {
270
- shim.recordQuery(proto, CURSOR_OPS[i], makeQueryDescFunc(shim, CURSOR_OPS[i]))
271
- }
272
-
273
- shim.recordQuery(proto, 'each', makeQueryDescFunc(shim, 'each'))
274
- shim.recordOperation(proto, 'pipe')
275
- }
276
- }
277
- }
278
-
279
- function makeQueryDescFunc(shim, methodName) {
280
- if (methodName === 'each') {
281
- return function eachDescFunc() {
282
- const parameters = getInstanceAttributeParameters(shim, this)
283
- return {query: methodName, parameters, rowCallback: shim.LAST}
284
- }
285
- }
286
-
287
- return function queryDescFunc() {
288
- // segment name does not actually use query string
289
- // method name is set as query so the query parser has access to the op name
290
- const parameters = getInstanceAttributeParameters(shim, this)
291
- return {query: methodName, parameters, promise: true, callback: shim.LAST}
43
+ instrument(shim, mongodb)
292
44
  }
293
45
  }
294
46
 
295
- function getInstanceAttributeParameters(shim, obj) {
296
- if (obj.db && obj.db.serverConfig) {
297
- shim.logger.trace('Adding datastore instance attributes from obj.db.serverConfig')
298
- const serverConfig = obj.db.serverConfig
299
- const db = serverConfig.db || serverConfig.dbInstance
300
- return doCapture(serverConfig, db && db.databaseName)
301
- } else if (obj.s && obj.s.db && obj.s.topology) {
302
- shim.logger.trace(
303
- 'Adding datastore instance attributes from obj.s.db + obj.s.topology'
304
- )
305
- const databaseName = obj.s.db.databaseName || null
306
- const topology = obj.s.topology
307
- if (topology.s && topology.s.options) {
308
- return doCapture(topology.s.options, databaseName)
309
- }
310
- }
311
-
312
- shim.logger.trace('Could not find datastore instance attributes.')
313
- return {
314
- host: null,
315
- port_path_or_id: null,
316
- database_name: null
317
- }
318
-
319
- function doCapture(conf, database) {
320
- let host = conf.host
321
- let port = conf.port
322
-
323
- // If using a domain socket, mongo stores the path as the host name, but we
324
- // pass it through the port value.
325
- if (
326
- (conf.socketOptions && conf.socketOptions.domainSocket) ||
327
- /\.sock$/.test(host)
328
- ) {
329
- port = host
330
- host = 'localhost'
331
- }
332
-
333
- return {
334
- host: host,
335
- port_path_or_id: port,
336
- database_name: database
337
- }
338
- }
339
- }