newrelic 7.5.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.
- package/NEWS.md +67 -0
- package/THIRD_PARTY_NOTICES.md +35 -82
- package/bin/test-naming-rules.js +0 -1
- package/bin/tracetractor +0 -1
- package/index.js +6 -5
- package/lib/agent.js +51 -31
- package/lib/collector/api.js +2 -3
- package/lib/config/index.js +7 -15
- package/lib/feature_flags.js +2 -4
- package/lib/instrumentation/fastify/spec-builders.js +5 -0
- package/lib/instrumentation/fastify.js +5 -0
- package/lib/instrumentation/mongodb/common.js +186 -0
- package/lib/instrumentation/mongodb/constants.js +97 -0
- package/lib/instrumentation/mongodb/v2-mongo.js +108 -0
- package/lib/instrumentation/mongodb/v3-mongo.js +61 -0
- package/lib/instrumentation/mongodb/v4-mongo.js +96 -0
- package/lib/instrumentation/mongodb.js +17 -310
- package/lib/instrumentation/pg.js +35 -16
- package/lib/spans/create-span-event-aggregator.js +23 -70
- package/package.json +26 -19
|
@@ -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, '>=
|
|
124
|
-
|
|
125
|
-
} else if (
|
|
126
|
-
|
|
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
|
-
|
|
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, 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
|
-
}
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
+
const semver = require('semver')
|
|
9
|
+
|
|
8
10
|
function getQuery(shim, original, name, args) {
|
|
9
11
|
var config = args[0]
|
|
10
12
|
var statement
|
|
@@ -20,6 +22,8 @@ function getQuery(shim, original, name, args) {
|
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
module.exports = function initialize(agent, pgsql, moduleName, shim) {
|
|
25
|
+
const pgVersion = shim.require('./package.json').version
|
|
26
|
+
|
|
23
27
|
shim.setDatastore(shim.POSTGRES)
|
|
24
28
|
// allows for native wrapping to not happen if not necessary
|
|
25
29
|
// when env var is true
|
|
@@ -28,6 +32,30 @@ module.exports = function initialize(agent, pgsql, moduleName, shim) {
|
|
|
28
32
|
return instrumentPGNative(pgsql)
|
|
29
33
|
}
|
|
30
34
|
|
|
35
|
+
function wrapJSClientQuery(shim, _, __, queryArgs) {
|
|
36
|
+
// As of pg v7.0.0, Client.query returns a Promise from an async call.
|
|
37
|
+
// pg supports event based Client.query when a Query object is passed in,
|
|
38
|
+
// and works similarly in pg version <7.0.0
|
|
39
|
+
if (semver.satisfies(pgVersion, '>=7.0.0') &&
|
|
40
|
+
typeof queryArgs[0] === 'string') {
|
|
41
|
+
return {
|
|
42
|
+
callback: shim.LAST,
|
|
43
|
+
query: getQuery,
|
|
44
|
+
promise: true,
|
|
45
|
+
parameters: getInstanceParameters(shim, this),
|
|
46
|
+
internal: false
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
callback: shim.LAST,
|
|
52
|
+
query: getQuery,
|
|
53
|
+
stream: 'row',
|
|
54
|
+
parameters: getInstanceParameters(shim, this),
|
|
55
|
+
internal: false
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
31
59
|
// wrapping for native
|
|
32
60
|
function instrumentPGNative(pg) {
|
|
33
61
|
shim.wrapReturn(pg, 'Client', clientFactoryWrapper)
|
|
@@ -56,13 +84,11 @@ module.exports = function initialize(agent, pgsql, moduleName, shim) {
|
|
|
56
84
|
}
|
|
57
85
|
|
|
58
86
|
function clientPostConstructor(shim) {
|
|
59
|
-
shim.recordQuery(
|
|
60
|
-
|
|
61
|
-
query
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
internal: false
|
|
65
|
-
})
|
|
87
|
+
shim.recordQuery(
|
|
88
|
+
this,
|
|
89
|
+
'query',
|
|
90
|
+
wrapJSClientQuery
|
|
91
|
+
)
|
|
66
92
|
|
|
67
93
|
shim.record(this, 'connect', function pgConnectNamer() {
|
|
68
94
|
return {
|
|
@@ -93,18 +119,11 @@ module.exports = function initialize(agent, pgsql, moduleName, shim) {
|
|
|
93
119
|
shim.recordQuery(
|
|
94
120
|
pgsql && pgsql.Client && pgsql.Client.prototype,
|
|
95
121
|
'query',
|
|
96
|
-
|
|
97
|
-
return {
|
|
98
|
-
callback: shim.LAST,
|
|
99
|
-
query: getQuery,
|
|
100
|
-
stream: 'row',
|
|
101
|
-
parameters: getInstanceParameters(shim, this),
|
|
102
|
-
internal: false
|
|
103
|
-
}
|
|
104
|
-
}
|
|
122
|
+
wrapJSClientQuery
|
|
105
123
|
)
|
|
106
124
|
}
|
|
107
125
|
|
|
126
|
+
|
|
108
127
|
function getInstanceParameters(shim, client) {
|
|
109
128
|
return {
|
|
110
129
|
host: client.host || null,
|
|
@@ -5,29 +5,32 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
const psemver = require('../util/process-version')
|
|
9
8
|
const logger = require('../logger')
|
|
10
9
|
const SpanEventAggregator = require('./span-event-aggregator')
|
|
11
10
|
const StreamingSpanEventAggregator = require('./streaming-span-event-aggregator')
|
|
12
11
|
|
|
13
12
|
function createSpanEventAggregator(config, collector, metrics) {
|
|
14
|
-
|
|
15
|
-
if (config.infinite_tracing.trace_observer.host) {
|
|
16
|
-
// TODO: ideally this validation and configuration clearing would happen
|
|
17
|
-
// in the config. Since we don't currently have a way to generate
|
|
18
|
-
// support metrics in the config, keeping this related logic together here.
|
|
19
|
-
// If logic happened prior, could merely check for existence of trace_observer.host.
|
|
20
|
-
shouldCreateStreaming = validateInfiniteTracing(config.infinite_tracing.trace_observer)
|
|
13
|
+
const trace_observer = config.infinite_tracing.trace_observer
|
|
21
14
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
config.infinite_tracing.trace_observer.host = ''
|
|
25
|
-
config.infinite_tracing.trace_observer.port = ''
|
|
26
|
-
}
|
|
27
|
-
}
|
|
15
|
+
if (trace_observer.host) {
|
|
16
|
+
trace_observer.host = trace_observer.host.trim()
|
|
28
17
|
|
|
29
|
-
|
|
30
|
-
|
|
18
|
+
if (typeof trace_observer.port !== 'string') {
|
|
19
|
+
trace_observer.port = String(trace_observer.port)
|
|
20
|
+
}
|
|
21
|
+
trace_observer.port = trace_observer.port.trim()
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
return createStreamingAggregator(config, collector, metrics)
|
|
25
|
+
} catch (err) {
|
|
26
|
+
logger.warn(err, 'Failed to create streaming span event aggregator for infinite tracing. ' +
|
|
27
|
+
'Reverting to standard span event aggregator and disabling infinite tracing')
|
|
28
|
+
config.infinite_tracing.trace_observer = {
|
|
29
|
+
host: '',
|
|
30
|
+
port: ''
|
|
31
|
+
}
|
|
32
|
+
return createStandardAggregator(config, collector, metrics)
|
|
33
|
+
}
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
return createStandardAggregator(config, collector, metrics)
|
|
@@ -35,12 +38,10 @@ function createSpanEventAggregator(config, collector, metrics) {
|
|
|
35
38
|
|
|
36
39
|
function createStreamingAggregator(config, collector, metrics) {
|
|
37
40
|
logger.trace('Creating streaming span event aggregator for infinite tracing.')
|
|
38
|
-
|
|
39
|
-
// loading the class here to ensure its behind a feature flag
|
|
40
|
-
// and won't trigger a grpc load in node 8
|
|
41
41
|
const GrpcConnection = require('../grpc/connection')
|
|
42
|
-
const connection = new GrpcConnection(config.infinite_tracing.trace_observer, metrics)
|
|
43
42
|
const SpanStreamer = require('./span-streamer')
|
|
43
|
+
|
|
44
|
+
const connection = new GrpcConnection(config.infinite_tracing.trace_observer, metrics)
|
|
44
45
|
const spanStreamer = new SpanStreamer(
|
|
45
46
|
config.license_key,
|
|
46
47
|
connection,
|
|
@@ -54,9 +55,7 @@ function createStreamingAggregator(config, collector, metrics) {
|
|
|
54
55
|
span_streamer: spanStreamer
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
return aggregator
|
|
58
|
+
return new StreamingSpanEventAggregator(opts, collector, metrics)
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
function createStandardAggregator(config, collector, metrics) {
|
|
@@ -67,53 +66,7 @@ function createStandardAggregator(config, collector, metrics) {
|
|
|
67
66
|
limit: config.event_harvest_config.harvest_limits.span_event_data
|
|
68
67
|
}
|
|
69
68
|
|
|
70
|
-
|
|
71
|
-
return aggregator
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function validateInfiniteTracing(trace_observer) {
|
|
75
|
-
// TODO: Remove semver check when Node 10 support dropped.
|
|
76
|
-
if (!psemver.satisfies('>=10.10.0')) {
|
|
77
|
-
logger.warn(
|
|
78
|
-
'Infinite tracing disabled: this version of Node is not supported (must be >=10.10.0)'
|
|
79
|
-
)
|
|
80
|
-
return false
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
trace_observer.host = trace_observer.host.trim()
|
|
84
|
-
|
|
85
|
-
if (!validateHostName(trace_observer.host)) {
|
|
86
|
-
logger.warn('Infinite tracing disabled: invalid infinite_tracing.trace_observer.host value')
|
|
87
|
-
|
|
88
|
-
return false
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (typeof trace_observer.port !== 'string') {
|
|
92
|
-
trace_observer.port = String(trace_observer.port)
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
trace_observer.port = trace_observer.port.trim()
|
|
96
|
-
|
|
97
|
-
if (!validatePortValue(trace_observer.port)) {
|
|
98
|
-
logger.warn('Infinite tracing disabled: invalid infinite_tracing.trace_observer.port value')
|
|
99
|
-
|
|
100
|
-
return false
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return true
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function validateHostName(host) {
|
|
107
|
-
// Regular expression for validating a hostname
|
|
108
|
-
const hostReg = /(?=^.{4,253}$)(^((?!-)[a-zA-Z0-9-]{0,62}[a-zA-Z0-9]\.)+[a-zA-Z]{2,63}$)/
|
|
109
|
-
|
|
110
|
-
return hostReg.test(host)
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function validatePortValue(port) {
|
|
114
|
-
if (port.length === 0) return false
|
|
115
|
-
|
|
116
|
-
return !isNaN(port)
|
|
69
|
+
return new SpanEventAggregator(opts, collector, metrics)
|
|
117
70
|
}
|
|
118
71
|
|
|
119
72
|
module.exports = createSpanEventAggregator
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "newrelic",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.1.0",
|
|
4
4
|
"author": "New Relic Node.js agent team <nodejs@newrelic.com>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"contributors": [
|
|
@@ -98,6 +98,11 @@
|
|
|
98
98
|
"name": "Nick Tzaperas",
|
|
99
99
|
"email": "ntzaperas@newrelic.com",
|
|
100
100
|
"web": "https://newrelic.com"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"name": "Bob Evans",
|
|
104
|
+
"email": "revans@newrelic.com",
|
|
105
|
+
"web": "https://newrelic.com"
|
|
101
106
|
}
|
|
102
107
|
],
|
|
103
108
|
"description": "New Relic agent",
|
|
@@ -109,10 +114,10 @@
|
|
|
109
114
|
"debugging",
|
|
110
115
|
"profiling"
|
|
111
116
|
],
|
|
112
|
-
"homepage": "
|
|
117
|
+
"homepage": "https://github.com/newrelic/node-newrelic",
|
|
113
118
|
"engines": {
|
|
114
|
-
"node": ">=
|
|
115
|
-
"npm": ">=
|
|
119
|
+
"node": ">=12.0.0",
|
|
120
|
+
"npm": ">=6.0.0"
|
|
116
121
|
},
|
|
117
122
|
"directories": {
|
|
118
123
|
"lib": "lib"
|
|
@@ -120,24 +125,25 @@
|
|
|
120
125
|
"scripts": {
|
|
121
126
|
"bench": "node ./bin/run-bench.js",
|
|
122
127
|
"ca-gen": "./bin/update-ca-bundle.sh",
|
|
123
|
-
"clean": "./bin/clean.sh",
|
|
124
128
|
"docker-env": "./bin/docker-env-vars.sh",
|
|
125
129
|
"docs": "npm ci && jsdoc -c ./jsdoc-conf.json --private -r .",
|
|
126
|
-
"integration": "npm run prepare-test && npm run sub-install && time tap
|
|
127
|
-
"prepare-test": "npm
|
|
130
|
+
"integration": "npm run prepare-test && npm run sub-install && time tap test/integration/**/**/*.tap.js --timeout=180 --no-coverage --reporter classic",
|
|
131
|
+
"prepare-test": "npm run ca-gen && npm run ssl && npm run docker-env",
|
|
128
132
|
"lint": "eslint ./*.js lib test bin",
|
|
129
133
|
"public-docs": "npm ci && jsdoc -c ./jsdoc-conf.json --tutorials examples/shim api.js lib/shim/ lib/transaction/handle.js && cp examples/shim/*.png out/",
|
|
130
134
|
"publish-docs": "./bin/publish-docs.sh",
|
|
131
135
|
"services": "./bin/docker-services.sh",
|
|
132
|
-
"smoke": "npm run
|
|
136
|
+
"smoke": "npm run ssl && time tap test/smoke/**/**/*.tap.js --timeout=180 --no-coverage",
|
|
133
137
|
"ssl": "./bin/ssl.sh",
|
|
134
138
|
"sub-install": "node test/bin/install_sub_deps",
|
|
135
139
|
"test": "npm run integration && npm run unit",
|
|
136
|
-
"unit": "rm -f newrelic_agent.log && time tap --test-regex='(\\/|^test\\/unit\\/.*\\.test\\.js)$' --timeout=180 --no-coverage",
|
|
140
|
+
"unit": "rm -f newrelic_agent.log && time tap --test-regex='(\\/|^test\\/unit\\/.*\\.test\\.js)$' --timeout=180 --no-coverage --reporter classic",
|
|
137
141
|
"update-cross-agent-tests": "./bin/update-cats.sh",
|
|
138
142
|
"versioned-tests": "./bin/run-versioned-tests.sh",
|
|
139
143
|
"update-changelog-version": "node ./bin/update-changelog-version",
|
|
140
|
-
"versioned": "npm run
|
|
144
|
+
"versioned": "npm run versioned:npm7",
|
|
145
|
+
"versioned:npm6": "npm run prepare-test && time ./bin/run-versioned-tests.sh",
|
|
146
|
+
"versioned:npm7": "npm run prepare-test && NPM7=1 time ./bin/run-versioned-tests.sh",
|
|
141
147
|
"prepare": "husky install"
|
|
142
148
|
},
|
|
143
149
|
"bin": {
|
|
@@ -146,31 +152,31 @@
|
|
|
146
152
|
"dependencies": {
|
|
147
153
|
"@grpc/grpc-js": "^1.2.11",
|
|
148
154
|
"@grpc/proto-loader": "^0.5.6",
|
|
149
|
-
"@newrelic/aws-sdk": "^
|
|
150
|
-
"@newrelic/koa": "^
|
|
151
|
-
"@newrelic/superagent": "^
|
|
155
|
+
"@newrelic/aws-sdk": "^4.0.1",
|
|
156
|
+
"@newrelic/koa": "^6.0.1",
|
|
157
|
+
"@newrelic/superagent": "^5.0.1",
|
|
152
158
|
"@tyriar/fibonacci-heap": "^2.0.7",
|
|
153
159
|
"async": "^3.2.0",
|
|
154
160
|
"concat-stream": "^2.0.0",
|
|
155
|
-
"https-proxy-agent": "^
|
|
161
|
+
"https-proxy-agent": "^5.0.0",
|
|
156
162
|
"json-stringify-safe": "^5.0.0",
|
|
157
163
|
"readable-stream": "^3.6.0",
|
|
158
164
|
"semver": "^5.3.0"
|
|
159
165
|
},
|
|
160
166
|
"optionalDependencies": {
|
|
161
|
-
"@newrelic/native-metrics": "^
|
|
167
|
+
"@newrelic/native-metrics": "^7.0.1"
|
|
162
168
|
},
|
|
163
169
|
"devDependencies": {
|
|
164
170
|
"@newrelic/proxy": "^2.0.0",
|
|
165
|
-
"@newrelic/test-utilities": "^
|
|
171
|
+
"@newrelic/test-utilities": "^6.0.0",
|
|
166
172
|
"@octokit/rest": "^18.0.15",
|
|
167
|
-
"JSV": "~4.0.2",
|
|
168
173
|
"architect": "*",
|
|
169
174
|
"benchmark": "^2.1.4",
|
|
170
175
|
"bluebird": "^3.4.7",
|
|
171
176
|
"chai": "^4.1.2",
|
|
172
177
|
"commander": "^7.0.0",
|
|
173
|
-
"eslint": "^
|
|
178
|
+
"eslint": "^7.32.0",
|
|
179
|
+
"eslint-plugin-header": "^3.1.1",
|
|
174
180
|
"express": "*",
|
|
175
181
|
"fastify": "^2.15.3",
|
|
176
182
|
"generic-pool": "^3.6.1",
|
|
@@ -179,6 +185,7 @@
|
|
|
179
185
|
"http-errors": "^1.7.3",
|
|
180
186
|
"husky": "^6.0.0",
|
|
181
187
|
"jsdoc": "^3.6.3",
|
|
188
|
+
"JSV": "~4.0.2",
|
|
182
189
|
"lint-staged": "^11.0.0",
|
|
183
190
|
"memcached": ">=0.2.8",
|
|
184
191
|
"minami": "^1.1.1",
|
|
@@ -193,7 +200,7 @@
|
|
|
193
200
|
"rimraf": "^2.6.3",
|
|
194
201
|
"should": "*",
|
|
195
202
|
"sinon": "^4.5.0",
|
|
196
|
-
"tap": "^
|
|
203
|
+
"tap": "^15.0.9",
|
|
197
204
|
"temp": "^0.8.1",
|
|
198
205
|
"through": "^2.3.6",
|
|
199
206
|
"when": "*"
|