@newrelic/security-agent 0.0.1
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/CHANGELOG.md +0 -0
- package/CONTRIBUTING.md +23 -0
- package/LICENSE +43 -0
- package/README.md +98 -0
- package/THIRD_PARTY_NOTICES.md +2909 -0
- package/index.js +24 -0
- package/lib/instrumentation-security/core/constants.js +66 -0
- package/lib/instrumentation-security/core/event-constants.js +49 -0
- package/lib/instrumentation-security/core/request-manager.js +73 -0
- package/lib/instrumentation-security/core/route-manager.js +30 -0
- package/lib/instrumentation-security/core/sec-trace.js +134 -0
- package/lib/instrumentation-security/core/sec-utils.js +212 -0
- package/lib/instrumentation-security/core/security-metadata.js +34 -0
- package/lib/instrumentation-security/core/stack-trace.js +156 -0
- package/lib/instrumentation-security/hooks/director/nr-director.js +98 -0
- package/lib/instrumentation-security/hooks/express/nr-express.js +106 -0
- package/lib/instrumentation-security/hooks/fastify/nr-fastify.js +155 -0
- package/lib/instrumentation-security/hooks/fs/nr-fs.js +391 -0
- package/lib/instrumentation-security/hooks/hapi/nr-hapi.js +131 -0
- package/lib/instrumentation-security/hooks/http/nr-http.js +461 -0
- package/lib/instrumentation-security/hooks/koa/@koa/nr-@koa-router.js +110 -0
- package/lib/instrumentation-security/hooks/ldap/nr-ldap.js +81 -0
- package/lib/instrumentation-security/hooks/mongodb/common.js +239 -0
- package/lib/instrumentation-security/hooks/mongodb/constants.js +91 -0
- package/lib/instrumentation-security/hooks/mongodb/nr-mongodb.js +49 -0
- package/lib/instrumentation-security/hooks/mongodb/v2-mongo.js +91 -0
- package/lib/instrumentation-security/hooks/mongodb/v3-mongo.js +36 -0
- package/lib/instrumentation-security/hooks/mongodb/v4-mongo.js +17 -0
- package/lib/instrumentation-security/hooks/mysql/nr-mysql.js +232 -0
- package/lib/instrumentation-security/hooks/native/nr-childProcess.js +131 -0
- package/lib/instrumentation-security/hooks/postgres/nr-postgres.js +131 -0
- package/lib/instrumentation-security/hooks/require/nr-require.js +93 -0
- package/lib/instrumentation-security/hooks/restify/nr-restify.js +104 -0
- package/lib/instrumentation-security/hooks/xpath/nr-xpath.js +91 -0
- package/lib/instrumentation-security/index.js +171 -0
- package/lib/nr-security-agent/index.js +170 -0
- package/lib/nr-security-agent/lib/core/Auth-headers.js +58 -0
- package/lib/nr-security-agent/lib/core/ContainerProperties.js +42 -0
- package/lib/nr-security-agent/lib/core/ECSProperties.js +34 -0
- package/lib/nr-security-agent/lib/core/FuzzFailEvent.js +27 -0
- package/lib/nr-security-agent/lib/core/LinkingMetadata.js +21 -0
- package/lib/nr-security-agent/lib/core/LogMessage.js +47 -0
- package/lib/nr-security-agent/lib/core/PodProperties.js +36 -0
- package/lib/nr-security-agent/lib/core/Policy.js +105 -0
- package/lib/nr-security-agent/lib/core/agent-status.js +56 -0
- package/lib/nr-security-agent/lib/core/agent.js +146 -0
- package/lib/nr-security-agent/lib/core/applicationinfo.js +634 -0
- package/lib/nr-security-agent/lib/core/commonUtils.js +411 -0
- package/lib/nr-security-agent/lib/core/connections/aws-lambda-client.js +55 -0
- package/lib/nr-security-agent/lib/core/connections/restclient.js +20 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/index.js +25 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/collecotor-policy-error-handler.js +18 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/collector-policy-handler.js +20 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/fuzz-request-handler.js +171 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/index.js +47 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/no-op-handler.js +12 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/startup-handshake-handler.js +27 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/unsupported-agent-handler.js +18 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/ws-reconnect.js +14 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/websocket.js +443 -0
- package/lib/nr-security-agent/lib/core/event.js +186 -0
- package/lib/nr-security-agent/lib/core/health-check.js +159 -0
- package/lib/nr-security-agent/lib/core/json-file-handler.js +66 -0
- package/lib/nr-security-agent/lib/core/jsonValidator.js +149 -0
- package/lib/nr-security-agent/lib/core/lambda-delegated-task-service.js +90 -0
- package/lib/nr-security-agent/lib/core/logging.js +176 -0
- package/lib/nr-security-agent/lib/core/sec-agent-constants.js +173 -0
- package/lib/nr-security-agent/lib/core/sec-util.js +166 -0
- package/lib/nr-security-agent/lib/core/sha-size-util.js +338 -0
- package/lib/nr-security-agent/lib/core/sha_worker.js +24 -0
- package/lib/nr-security-agent/lib/core/startup-config.js +29 -0
- package/lib/nr-security-agent/lib/core/statusUtils.js +157 -0
- package/lib/nr-security-agent/lib/core/timeunit.js +44 -0
- package/lib/nr-security-agent/lib/core/websocket-client.js +335 -0
- package/lib/nr-security-agent/lib/core/worker-entities.js +82 -0
- package/lib/nr-security-agent/lib/core/worker.js +148 -0
- package/lib/nr-security-agent/lib/core/xss-utils.js +297 -0
- package/lib/nr-security-agent/lib/models/lambda-delegated-task/constants.js +12 -0
- package/lib/nr-security-agent/lib/models/lambda-delegated-task/index.js +15 -0
- package/lib/nr-security-agent/lib/models/lambda-delegated-task/lambda-delegated-sha-calculation.js +37 -0
- package/lib/nr-security-agent/lib/models/lambda-delegated-task/lambda-delegated-task-base.js +50 -0
- package/lib/nr-security-agent/lib/models/lambda-delegated-task/lambda-delegated-task-type.js +17 -0
- package/lib/nr-security-agent/resources/cert.pem +31 -0
- package/lib/nr-security-agent/resources/config.js +19 -0
- package/lib/nr-security-agent/resources/default-policy.yaml +36 -0
- package/lib/nr-security-api/index.js +111 -0
- package/package.json +95 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
"use strict";
|
|
7
|
+
|
|
8
|
+
/* eslint sonarjs/cognitive-complexity: ["error", 18] -- TODO: https://issues.newrelic.com/browse/NEWRELIC-5252 */
|
|
9
|
+
|
|
10
|
+
const { CURSOR_OPS, COLLECTION_OPS, DB_OPS } = require("./constants");
|
|
11
|
+
const common = module.exports;
|
|
12
|
+
const requestManager = require("../../core/request-manager");
|
|
13
|
+
const async_hooks = require("async_hooks");
|
|
14
|
+
const secUtils = require("../../core/sec-utils");
|
|
15
|
+
const API = require("../../../nr-security-api");
|
|
16
|
+
const securityMetaData = require('../../core/security-metadata');
|
|
17
|
+
const { EVENT_TYPE, EVENT_CATEGORY } = require('../../core/event-constants');
|
|
18
|
+
const { NR_CSEC_FUZZ_REQUEST_ID } = require('../../core/constants');
|
|
19
|
+
const logger = API.getLogger();
|
|
20
|
+
|
|
21
|
+
function methodChecker(data) {
|
|
22
|
+
data = data.toLowerCase();
|
|
23
|
+
if (data.includes("delete")) {
|
|
24
|
+
return "delete";
|
|
25
|
+
} else if (data.includes("update") || data.includes("replace")) {
|
|
26
|
+
return "update";
|
|
27
|
+
} else if (data.includes("insert") || data.includes("write")) {
|
|
28
|
+
return "insert";
|
|
29
|
+
} else if (data.includes("find")) {
|
|
30
|
+
return "find";
|
|
31
|
+
} else {
|
|
32
|
+
return "Unknown";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function payloadType(obj) {
|
|
37
|
+
if (obj) {
|
|
38
|
+
if (obj.insert) {
|
|
39
|
+
return "insert";
|
|
40
|
+
} else if (obj.update) {
|
|
41
|
+
return "update";
|
|
42
|
+
} else if (obj.delete) {
|
|
43
|
+
return "delete";
|
|
44
|
+
} else if (obj.find) {
|
|
45
|
+
return "find";
|
|
46
|
+
} else {
|
|
47
|
+
return "Unknown";
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else{
|
|
51
|
+
return "Unknown";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function queryHook(shim, mod, method) {
|
|
57
|
+
shim.wrap(mod, method, function makeQueryWrapper(shim, fn) {
|
|
58
|
+
return function queryWrapper() {
|
|
59
|
+
const request = requestManager.getRequest(shim);
|
|
60
|
+
if (CURSOR_OPS.includes(method)) {
|
|
61
|
+
if (!this.mongo_sec_hooked && this.operation && this.operation.cmd) {
|
|
62
|
+
const pType = payloadType(this.operation.cmd);
|
|
63
|
+
const payloadData = {
|
|
64
|
+
payloadType: pType,
|
|
65
|
+
payload: this.operation.cmd,
|
|
66
|
+
};
|
|
67
|
+
shim.interceptedArgs = payloadData;
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
this.mongo_sec_hooked = true;
|
|
71
|
+
|
|
72
|
+
const pType = methodChecker(method);
|
|
73
|
+
const payloadData = {
|
|
74
|
+
payloadType: pType,
|
|
75
|
+
payload: arguments,
|
|
76
|
+
};
|
|
77
|
+
shim.interceptedArgs = payloadData;
|
|
78
|
+
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
if (request) {
|
|
83
|
+
//generate event here
|
|
84
|
+
const traceObject = secUtils.getTraceObject(shim);
|
|
85
|
+
const secMetadata = securityMetaData.getSecurityMetaData(request, JSON.parse(JSON.stringify(shim.interceptedArgs)), traceObject, secUtils.getExecutionId(), EVENT_TYPE.NOSQL_DB_COMMAND, EVENT_CATEGORY.MONGO)
|
|
86
|
+
const secEvent = API.generateSecEvent(secMetadata);
|
|
87
|
+
API.sendEvent(secEvent);
|
|
88
|
+
if (request.headers[NR_CSEC_FUZZ_REQUEST_ID]) {
|
|
89
|
+
callbackHook(shim, arguments, arguments.length - 1, secEvent);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
} catch (error) {
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
return fn.apply(this, arguments);
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Instruments all methods from constants.CURSOR_OPS on a given
|
|
103
|
+
* cursor class
|
|
104
|
+
*
|
|
105
|
+
* @param {Shim} shim
|
|
106
|
+
* @param {Cursor} Cursor
|
|
107
|
+
*/
|
|
108
|
+
common.instrumentCursor = function instrumentCursor(shim, Cursor) {
|
|
109
|
+
if (Cursor && Cursor.prototype) {
|
|
110
|
+
const proto = Cursor.prototype;
|
|
111
|
+
for (let i = 0; i < CURSOR_OPS.length; i++) {
|
|
112
|
+
queryHook(shim, proto, CURSOR_OPS[i]);
|
|
113
|
+
}
|
|
114
|
+
queryHook(shim, proto, "each");
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Instruments all methods from constants.COLLECTION_OPS on
|
|
120
|
+
* the Collection class
|
|
121
|
+
*
|
|
122
|
+
* @param {Shim} shim
|
|
123
|
+
* @param {Collection} Collection
|
|
124
|
+
*/
|
|
125
|
+
common.instrumentCollection = function instrumentCollection(shim, Collection) {
|
|
126
|
+
if (Collection && Collection.prototype) {
|
|
127
|
+
const proto = Collection.prototype;
|
|
128
|
+
for (let i = 0; i < COLLECTION_OPS.length; i++) {
|
|
129
|
+
queryHook(shim, proto, COLLECTION_OPS[i]);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Instruments the execute method on
|
|
136
|
+
* the BulkOperationBase class
|
|
137
|
+
*
|
|
138
|
+
* @param {Shim} shim
|
|
139
|
+
* @param {BulkOperationModule} bulk operation module, typically from mongodb/lib/bulk/common
|
|
140
|
+
* @param BulkOperationModule
|
|
141
|
+
*/
|
|
142
|
+
common.instrumentBulkOperation = function instrumentBulkOperation(
|
|
143
|
+
shim,
|
|
144
|
+
BulkOperationModule
|
|
145
|
+
) {
|
|
146
|
+
const BulkOperationBase =
|
|
147
|
+
BulkOperationModule && BulkOperationModule.BulkOperationBase;
|
|
148
|
+
|
|
149
|
+
if (BulkOperationBase && BulkOperationBase.prototype) {
|
|
150
|
+
const proto = BulkOperationBase.prototype;
|
|
151
|
+
queryHook(shim, proto, "execute");
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Instruments all methods from constants.DB_OPS on
|
|
157
|
+
* the Db class.
|
|
158
|
+
*
|
|
159
|
+
* @param {object} params
|
|
160
|
+
* @param {Shim} params.shim
|
|
161
|
+
* @param {Db} params.Db
|
|
162
|
+
* @param shim
|
|
163
|
+
* @param Db
|
|
164
|
+
*/
|
|
165
|
+
common.instrumentDb = function instrumentDb(shim, Db) {
|
|
166
|
+
if (Db && Db.prototype) {
|
|
167
|
+
const proto = Db.prototype;
|
|
168
|
+
}
|
|
169
|
+
//here need to add hooks for DB ops
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Callback hook to generate exit event
|
|
174
|
+
* @param {*} shim
|
|
175
|
+
* @param {*} mod
|
|
176
|
+
* @param {*} fun
|
|
177
|
+
* @param {*} secEvent
|
|
178
|
+
*/
|
|
179
|
+
function callbackHook(shim, mod, fun, secEvent) {
|
|
180
|
+
shim.secEvent = secEvent;
|
|
181
|
+
shim.wrap(mod, fun, function callbackWrapper(shim, fn) {
|
|
182
|
+
if (!shim.isFunction(fn)) {
|
|
183
|
+
return fn;
|
|
184
|
+
}
|
|
185
|
+
return function wrapper() {
|
|
186
|
+
if ((arguments[0] === null || arguments[0] === undefined) && shim.secEvent) {
|
|
187
|
+
API.generateExitEvent(shim.secEvent);
|
|
188
|
+
delete shim.secEvent;
|
|
189
|
+
}
|
|
190
|
+
return fn.apply(this, arguments);
|
|
191
|
+
}
|
|
192
|
+
})
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
common.queryHookV2 = function queryHookV2(shim, mod, method) {
|
|
196
|
+
shim.wrap(mod, method, function makeQueryWrapper(shim, fn) {
|
|
197
|
+
return function queryWrapper() {
|
|
198
|
+
const request = requestManager.getRequest(shim);
|
|
199
|
+
if (CURSOR_OPS.includes(method)) {
|
|
200
|
+
if (!this.mongo_sec_hooked && this.cmd) {
|
|
201
|
+
const pType = payloadType(this.cmd);
|
|
202
|
+
const payloadData = {
|
|
203
|
+
payloadType: pType,
|
|
204
|
+
payload: this.cmd,
|
|
205
|
+
};
|
|
206
|
+
shim.interceptedArgs = payloadData;
|
|
207
|
+
}
|
|
208
|
+
} else {
|
|
209
|
+
this.mongo_sec_hooked = true;
|
|
210
|
+
|
|
211
|
+
const pType = methodChecker(method);
|
|
212
|
+
const payloadData = {
|
|
213
|
+
payloadType: pType,
|
|
214
|
+
payload: arguments,
|
|
215
|
+
};
|
|
216
|
+
shim.interceptedArgs = payloadData;
|
|
217
|
+
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (request && shim.interceptedArgs) {
|
|
221
|
+
//generate event here
|
|
222
|
+
const traceObject = secUtils.getTraceObject(shim);
|
|
223
|
+
const secMetadata = securityMetaData.getSecurityMetaData(request, JSON.parse(JSON.stringify(shim.interceptedArgs)), traceObject, secUtils.getExecutionId(), EVENT_TYPE.NOSQL_DB_COMMAND, EVENT_CATEGORY.MONGO)
|
|
224
|
+
const secEvent = API.generateSecEvent(secMetadata);
|
|
225
|
+
if (this.sec_executionId != secMetadata.executionId) {
|
|
226
|
+
API.sendEvent(secEvent);
|
|
227
|
+
this.sec_executionId = secMetadata.executionId;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (request.headers[NR_CSEC_FUZZ_REQUEST_ID]) {
|
|
231
|
+
callbackHook(shim, arguments, arguments.length - 1, secEvent);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return fn.apply(this, arguments);
|
|
235
|
+
};
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
'use strict'
|
|
8
|
+
|
|
9
|
+
const DB_OPS = [
|
|
10
|
+
'addUser',
|
|
11
|
+
'authenticate',
|
|
12
|
+
'collection',
|
|
13
|
+
'collectionNames',
|
|
14
|
+
'collections',
|
|
15
|
+
'command',
|
|
16
|
+
'createCollection',
|
|
17
|
+
'createIndex',
|
|
18
|
+
'cursorInfo',
|
|
19
|
+
'dereference',
|
|
20
|
+
'dropCollection',
|
|
21
|
+
'dropDatabase',
|
|
22
|
+
'dropIndex',
|
|
23
|
+
'ensureIndex',
|
|
24
|
+
'eval',
|
|
25
|
+
'executeDbAdminCommand',
|
|
26
|
+
'indexInformation',
|
|
27
|
+
'logout',
|
|
28
|
+
'open',
|
|
29
|
+
'reIndex',
|
|
30
|
+
'removeUser',
|
|
31
|
+
'renameCollection',
|
|
32
|
+
'stats',
|
|
33
|
+
'_executeInsertCommand',
|
|
34
|
+
'_executeQueryCommand'
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
const COLLECTION_OPS = [
|
|
38
|
+
'aggregate',
|
|
39
|
+
'bulkWrite',
|
|
40
|
+
'count',
|
|
41
|
+
'countDocuments',
|
|
42
|
+
'createIndex',
|
|
43
|
+
'deleteMany',
|
|
44
|
+
'deleteOne',
|
|
45
|
+
'distinct',
|
|
46
|
+
'drop',
|
|
47
|
+
'dropAllIndexes',
|
|
48
|
+
'dropIndex',
|
|
49
|
+
'ensureIndex',
|
|
50
|
+
// 'find',
|
|
51
|
+
'findAndModify',
|
|
52
|
+
'findAndRemove',
|
|
53
|
+
// 'findOne',
|
|
54
|
+
'findOneAndDelete',
|
|
55
|
+
'findOneAndReplace',
|
|
56
|
+
'findOneAndUpdate',
|
|
57
|
+
// 'findOneAndRemove',
|
|
58
|
+
'geoHaystackSearch',
|
|
59
|
+
'geoNear',
|
|
60
|
+
'group',
|
|
61
|
+
'indexes',
|
|
62
|
+
'indexExists',
|
|
63
|
+
'indexInformation',
|
|
64
|
+
'insert',
|
|
65
|
+
'insertMany',
|
|
66
|
+
'insertOne',
|
|
67
|
+
'isCapped',
|
|
68
|
+
'mapReduce',
|
|
69
|
+
'options',
|
|
70
|
+
'parallelCollectionScan',
|
|
71
|
+
'reIndex',
|
|
72
|
+
'remove',
|
|
73
|
+
'rename',
|
|
74
|
+
'replaceOne',
|
|
75
|
+
'save',
|
|
76
|
+
'stats',
|
|
77
|
+
'update',
|
|
78
|
+
'updateMany',
|
|
79
|
+
'updateOne'
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
const GRID_OPS = ['put', 'get', 'delete']
|
|
83
|
+
|
|
84
|
+
const CURSOR_OPS = ['nextObject', 'next', 'toArray', 'count', 'explain']
|
|
85
|
+
|
|
86
|
+
module.exports = {
|
|
87
|
+
COLLECTION_OPS,
|
|
88
|
+
CURSOR_OPS,
|
|
89
|
+
DB_OPS,
|
|
90
|
+
GRID_OPS
|
|
91
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 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 instrument = require("./v2-mongo")
|
|
10
|
+
const instrumentV3 = require("./v3-mongo");
|
|
11
|
+
const instrumentV4 = require("./v4-mongo");
|
|
12
|
+
const API = require("../../../nr-security-api");
|
|
13
|
+
const logger = API.getLogger();
|
|
14
|
+
|
|
15
|
+
// XXX: When this instrumentation is modularized, update this thread
|
|
16
|
+
// with a cautionary note:
|
|
17
|
+
// https://discuss.newrelic.com/t/feature-idea-using-mongoose-cursors-memory-leaking-very-quickly/49270/14
|
|
18
|
+
//
|
|
19
|
+
// This instrumentation is deep linked against in the mongoose instrumentation
|
|
20
|
+
// snippet. The snippet will break once this file is moved from this
|
|
21
|
+
// location.
|
|
22
|
+
|
|
23
|
+
module.exports = initialize;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Registers the query parser, and relevant instrumentation
|
|
27
|
+
* based on version of mongodb
|
|
28
|
+
*
|
|
29
|
+
* @param {Agent} agent
|
|
30
|
+
* @param {object} mongodb resolved package
|
|
31
|
+
* @param {string} moduleName name of module
|
|
32
|
+
* @param {Shim} shim
|
|
33
|
+
*/
|
|
34
|
+
function initialize(shim, mongodb, moduleName) {
|
|
35
|
+
logger.info("Instrumenting Mongodb");
|
|
36
|
+
if (!mongodb) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const mongoVersion = shim.require("./package.json").version;
|
|
41
|
+
logger.debug("mongoVersion:", mongoVersion);
|
|
42
|
+
if (semver.satisfies(mongoVersion, ">=4.0.0")) {
|
|
43
|
+
instrumentV4(shim, mongodb);
|
|
44
|
+
} else if (semver.satisfies(mongoVersion, ">=3.0.6")) {
|
|
45
|
+
instrumentV3(shim, mongodb);
|
|
46
|
+
}else {
|
|
47
|
+
instrument(shim, mongodb)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
'use strict'
|
|
8
|
+
|
|
9
|
+
const { captureAttributesOnStarted, makeQueryDescFunc, queryHookV2 } = require('./common')
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Registers relevant instrumentation for mongo <= 3.0.6
|
|
13
|
+
* and >= 2. This relies on the built-in "APM" hook points
|
|
14
|
+
* to instrument their provided objects as well as sets
|
|
15
|
+
* up a listener for when commands start to properly
|
|
16
|
+
* add necessary attributes to segments
|
|
17
|
+
*
|
|
18
|
+
* @param {Shim} shim
|
|
19
|
+
* @param {object} mongodb resolved package
|
|
20
|
+
*/
|
|
21
|
+
module.exports = function instrument(shim, mongodb) {
|
|
22
|
+
|
|
23
|
+
const recordDesc = {
|
|
24
|
+
Gridstore: {
|
|
25
|
+
isQuery: false,
|
|
26
|
+
makeDescFunc: function makeGridDesc(opName) {
|
|
27
|
+
return { name: 'GridFS-' + opName, callback: shim.LAST }
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
OrderedBulkOperation: { isQuery: true, makeDescFunc: makeQueryDescFunc },
|
|
31
|
+
UnorderedBulkOperation: { isQuery: true, makeDescFunc: makeQueryDescFunc },
|
|
32
|
+
CommandCursor: { isQuery: true, makeDescFunc: makeQueryDescFunc },
|
|
33
|
+
AggregationCursor: { isQuery: true, makeDescFunc: makeQueryDescFunc },
|
|
34
|
+
Cursor: { isQuery: true, makeDescFunc: makeQueryDescFunc },
|
|
35
|
+
Collection: { isQuery: true, makeDescFunc: makeQueryDescFunc },
|
|
36
|
+
Db: {
|
|
37
|
+
isQuery: false,
|
|
38
|
+
makeDescFunc: function makeDbDesc() {
|
|
39
|
+
return { callback: shim.LAST }
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// instrument using the apm api
|
|
45
|
+
const instrumenter = mongodb.instrument(Object.create(null), instrumentModules)
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Every module groups instrumentations by their
|
|
49
|
+
* promise, callback, return permutations
|
|
50
|
+
* Iterate over permutations and properly
|
|
51
|
+
* wrap depending on the `recordDesc` above
|
|
52
|
+
* See: https://github.com/mongodb/node-mongodb-native/blob/v3.0.5/lib/collection.js#L384
|
|
53
|
+
*
|
|
54
|
+
* @param _
|
|
55
|
+
* @param modules
|
|
56
|
+
*/
|
|
57
|
+
function instrumentModules(_, modules) {
|
|
58
|
+
modules.forEach((module) => {
|
|
59
|
+
const { obj, instrumentations, name } = module
|
|
60
|
+
instrumentations.forEach((meta) => {
|
|
61
|
+
applyInstrumentation(name, obj, meta)
|
|
62
|
+
})
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Iterate over methods on object and lookup in `recordDesc` to decide
|
|
68
|
+
* if it needs to be wrapped as an operation or query
|
|
69
|
+
*
|
|
70
|
+
* @param {string} objectName name of class getting instrumented
|
|
71
|
+
* @param {object} object reference to the class getting instrumented
|
|
72
|
+
* @param {Define} meta describes the methods and if they are callbacks
|
|
73
|
+
* promises, and return values
|
|
74
|
+
*/
|
|
75
|
+
function applyInstrumentation(objectName, object, meta) {
|
|
76
|
+
const { methods, options } = meta
|
|
77
|
+
if (options.callback) {
|
|
78
|
+
methods.forEach((method) => {
|
|
79
|
+
const { isQuery, makeDescFunc } = recordDesc[objectName]
|
|
80
|
+
const proto = object.prototype
|
|
81
|
+
if (isQuery && method!='execute') {
|
|
82
|
+
queryHookV2(shim, proto, method);
|
|
83
|
+
} else if (isQuery === false) {
|
|
84
|
+
// could be unset
|
|
85
|
+
// shim.recordOperation(proto, method, makeDescFunc(shim, method))
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
"use strict";
|
|
8
|
+
|
|
9
|
+
const {
|
|
10
|
+
instrumentBulkOperation,
|
|
11
|
+
instrumentCollection,
|
|
12
|
+
instrumentCursor,
|
|
13
|
+
instrumentDb,
|
|
14
|
+
} = require("./common");
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Registers relevant instrumentation for mongo >= 3.0.6
|
|
18
|
+
* In 3.0.6 they refactored their "APM" module which removed
|
|
19
|
+
* a lot of niceities around instrumentation classes.
|
|
20
|
+
* see: https://github.com/mongodb/node-mongodb-native/pull/1675/files
|
|
21
|
+
* This reverts back to instrumenting pre-canned methods on classes
|
|
22
|
+
* as well as sets up a listener for when commands start to properly
|
|
23
|
+
* add necessary attributes to segments
|
|
24
|
+
*
|
|
25
|
+
* @param {Shim} shim
|
|
26
|
+
* @param {object} mongodb resolved package
|
|
27
|
+
*/
|
|
28
|
+
module.exports = function instrument(shim, mongodb) {
|
|
29
|
+
|
|
30
|
+
instrumentCursor(shim, mongodb.Cursor);
|
|
31
|
+
instrumentCursor(shim, shim.require("./lib/aggregation_cursor"));
|
|
32
|
+
instrumentCursor(shim, shim.require("./lib/command_cursor"));
|
|
33
|
+
instrumentBulkOperation(shim, shim.require("./lib/bulk/common"));
|
|
34
|
+
instrumentCollection(shim, mongodb.Collection);
|
|
35
|
+
instrumentDb(shim, mongodb.Db);
|
|
36
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
'use strict'
|
|
8
|
+
|
|
9
|
+
const { instrumentCollection, instrumentCursor, instrumentDb } = require('./common')
|
|
10
|
+
|
|
11
|
+
module.exports = function instrument(shim, mongodb) {
|
|
12
|
+
instrumentCursor(shim, mongodb.AbstractCursor)
|
|
13
|
+
instrumentCursor(shim, mongodb.FindCursor)
|
|
14
|
+
instrumentCursor(shim, mongodb.AggregationCursor)
|
|
15
|
+
instrumentCollection(shim, mongodb.Collection)
|
|
16
|
+
instrumentDb(shim, mongodb.Db)
|
|
17
|
+
}
|