newrelic 4.5.0 → 4.8.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 +153 -1
- package/api.js +8 -1
- package/bin/compare-bench-results.js +159 -0
- package/bin/run-bench.js +87 -44
- package/index.js +16 -8
- package/lib/agent.js +1 -1
- package/lib/collector/remote-method.js +12 -0
- package/lib/config/default.js +17 -0
- package/lib/config/env.js +4 -0
- package/lib/config/index.js +3 -0
- package/lib/db/tracer.js +15 -6
- package/lib/environment.js +1 -1
- package/lib/errors/index.js +1 -1
- package/lib/feature_flags.js +0 -1
- package/lib/harvest.js +36 -18
- package/lib/instrumentation/core/crypto.js +2 -1
- package/lib/instrumentation/core/fs.js +7 -2
- package/lib/instrumentation/core/globals.js +17 -1
- package/lib/instrumentation/core/http-outbound.js +102 -3
- package/lib/instrumentation/core/http.js +6 -96
- package/lib/instrumentation/mongodb.js +158 -115
- package/lib/metrics/recorders/http.js +1 -1
- package/lib/metrics/recorders/other.js +1 -1
- package/lib/priority-queue.js +5 -2
- package/lib/shim/message-shim.js +5 -4
- package/lib/shim/shim.js +14 -3
- package/lib/shim/specs/index.js +1 -0
- package/lib/shim/transaction-shim.js +3 -3
- package/lib/shimmer.js +3 -0
- package/lib/transaction/dt-payload.js +16 -0
- package/lib/transaction/handle.js +1 -1
- package/lib/transaction/index.js +8 -4
- package/lib/transaction/trace/index.js +31 -38
- package/package.json +3 -2
- package/.npmignore +0 -4
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const semver = require('semver')
|
|
4
|
+
|
|
3
5
|
// XXX: When this instrumentation is modularized, update this thread
|
|
4
6
|
// with a cautionary note:
|
|
5
7
|
// https://discuss.newrelic.com/t/feature-idea-using-mongoose-cursors-memory-leaking-very-quickly/49270/14
|
|
@@ -9,7 +11,7 @@
|
|
|
9
11
|
// location.
|
|
10
12
|
|
|
11
13
|
// legacy endpoint enumerations
|
|
12
|
-
|
|
14
|
+
const DB_OPS = [
|
|
13
15
|
'addUser',
|
|
14
16
|
'authenticate',
|
|
15
17
|
'collection',
|
|
@@ -37,7 +39,7 @@ var DB_OPS = [
|
|
|
37
39
|
'_executeQueryCommand'
|
|
38
40
|
]
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
const COLLECTION_OPS = [
|
|
41
43
|
'aggregate',
|
|
42
44
|
'bulkWrite',
|
|
43
45
|
'count',
|
|
@@ -79,13 +81,13 @@ var COLLECTION_OPS = [
|
|
|
79
81
|
'updateOne'
|
|
80
82
|
]
|
|
81
83
|
|
|
82
|
-
|
|
84
|
+
const GRID_OPS = [
|
|
83
85
|
'put',
|
|
84
86
|
'get',
|
|
85
87
|
'delete'
|
|
86
88
|
]
|
|
87
89
|
|
|
88
|
-
|
|
90
|
+
const CURSOR_OPS = [
|
|
89
91
|
'nextObject',
|
|
90
92
|
'next',
|
|
91
93
|
'toArray',
|
|
@@ -97,24 +99,10 @@ module.exports = initialize
|
|
|
97
99
|
|
|
98
100
|
function initialize(agent, mongodb, moduleName, shim) {
|
|
99
101
|
if (!mongodb) return
|
|
100
|
-
var recordDesc = {
|
|
101
|
-
'Gridstore': {isQuery: false, makeDesc: function makeGridDesc(opName) {
|
|
102
|
-
return {name:'GridFS-' + opName, callback: shim.LAST}
|
|
103
|
-
}},
|
|
104
|
-
'OrderedBulkOperation': {isQuery: true, makeDesc: makeQueryDescFunc},
|
|
105
|
-
'UnorderedBulkOperation': {isQuery: true, makeDesc: makeQueryDescFunc},
|
|
106
|
-
'CommandCursor': {isQuery: true, makeDesc: makeQueryDescFunc},
|
|
107
|
-
'AggregationCursor': {isQuery: true, makeDesc: makeQueryDescFunc},
|
|
108
|
-
'Cursor': {isQuery: true, makeDesc: makeQueryDescFunc},
|
|
109
|
-
'Collection': {isQuery: true, makeDesc: makeQueryDescFunc},
|
|
110
|
-
'Db': {isQuery: false, makeDesc: function makeDbDesc() {
|
|
111
|
-
return {callback: shim.LAST}
|
|
112
|
-
}}
|
|
113
|
-
}
|
|
114
102
|
|
|
115
103
|
shim.setDatastore(shim.MONGODB)
|
|
116
104
|
shim.setParser(function mongoQueryParser(operation) {
|
|
117
|
-
|
|
105
|
+
let collection = this.collectionName || 'unknown'
|
|
118
106
|
if (this.collection && this.collection.collectionName) {
|
|
119
107
|
collection = this.collection.collectionName
|
|
120
108
|
} else if (this.s && this.s.name) {
|
|
@@ -123,36 +111,51 @@ function initialize(agent, mongodb, moduleName, shim) {
|
|
|
123
111
|
collection = this.ns.split(/\./)[1] || collection
|
|
124
112
|
}
|
|
125
113
|
|
|
126
|
-
return {
|
|
127
|
-
operation: operation,
|
|
128
|
-
collection: collection
|
|
129
|
-
}
|
|
114
|
+
return {operation, collection}
|
|
130
115
|
})
|
|
131
116
|
|
|
132
|
-
|
|
133
|
-
if (mongodb.instrument) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
// starts and creates the segment. We perform a check of the segment name
|
|
138
|
-
// out of an excess of caution.
|
|
139
|
-
var connId = evnt.connectionId
|
|
140
|
-
if (connId) {
|
|
141
|
-
// Mongo sticks the path to the domain socket in the "host" slot, but we
|
|
142
|
-
// want it in the "port", so if we have a domain socket we need to change
|
|
143
|
-
// the order of our parameters.
|
|
144
|
-
if (connId.domainSocket) {
|
|
145
|
-
shim.captureInstanceAttributes('localhost', connId.host, evnt.databaseName)
|
|
146
|
-
} else {
|
|
147
|
-
shim.captureInstanceAttributes(connId.host, connId.port, evnt.databaseName)
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
})
|
|
117
|
+
const mongoVersion = shim.require('./package.json').version
|
|
118
|
+
if (semver.satisfies(mongoVersion, '>=3.0.6') && mongodb.instrument) {
|
|
119
|
+
instrument306(shim, mongodb)
|
|
120
|
+
} else if (mongodb.instrument) {
|
|
121
|
+
instrumentInstrument(shim, mongodb)
|
|
151
122
|
} else {
|
|
152
|
-
|
|
153
|
-
|
|
123
|
+
instrumentLegacy(shim, mongodb)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function instrument306(shim, mongodb) {
|
|
128
|
+
const instrumenter = mongodb.instrument(Object.create(null), () => {})
|
|
129
|
+
captureAttributesOnStarted(shim, instrumenter)
|
|
130
|
+
instrumentLegacy(shim, mongodb)
|
|
131
|
+
|
|
132
|
+
if (shim.isFunction(instrumenter.uninstrument)) {
|
|
133
|
+
shim.agent.once('unload', function uninstrumentMongo() {
|
|
134
|
+
instrumenter.uninstrument()
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function instrumentInstrument(shim, mongodb) {
|
|
140
|
+
const recordDesc = {
|
|
141
|
+
'Gridstore': {isQuery: false, makeDesc: function makeGridDesc(opName) {
|
|
142
|
+
return {name:'GridFS-' + opName, callback: shim.LAST}
|
|
143
|
+
}},
|
|
144
|
+
'OrderedBulkOperation': {isQuery: true, makeDesc: makeQueryDescFunc},
|
|
145
|
+
'UnorderedBulkOperation': {isQuery: true, makeDesc: makeQueryDescFunc},
|
|
146
|
+
'CommandCursor': {isQuery: true, makeDesc: makeQueryDescFunc},
|
|
147
|
+
'AggregationCursor': {isQuery: true, makeDesc: makeQueryDescFunc},
|
|
148
|
+
'Cursor': {isQuery: true, makeDesc: makeQueryDescFunc},
|
|
149
|
+
'Collection': {isQuery: true, makeDesc: makeQueryDescFunc},
|
|
150
|
+
'Db': {isQuery: false, makeDesc: function makeDbDesc() {
|
|
151
|
+
return {callback: shim.LAST}
|
|
152
|
+
}}
|
|
154
153
|
}
|
|
155
154
|
|
|
155
|
+
// instrument using the apm api
|
|
156
|
+
const instrumenter = mongodb.instrument(Object.create(null), instrumentModules)
|
|
157
|
+
captureAttributesOnStarted(shim, instrumenter)
|
|
158
|
+
|
|
156
159
|
function instrumentModules(err, instrumentations) {
|
|
157
160
|
if (err) {
|
|
158
161
|
shim.logger
|
|
@@ -182,9 +185,9 @@ function initialize(agent, mongodb, moduleName, shim) {
|
|
|
182
185
|
var makeDescFunc = recordDesc[objectName].makeDesc
|
|
183
186
|
var proto = object.prototype
|
|
184
187
|
if (isQuery) {
|
|
185
|
-
shim.recordQuery(proto, method, makeDescFunc(method))
|
|
188
|
+
shim.recordQuery(proto, method, makeDescFunc(shim, method))
|
|
186
189
|
} else if (isQuery === false) { // could be unset
|
|
187
|
-
shim.recordOperation(proto, method, makeDescFunc(method))
|
|
190
|
+
shim.recordOperation(proto, method, makeDescFunc(shim, method))
|
|
188
191
|
} else {
|
|
189
192
|
shim.logger.trace('No wrapping method found for %s', objectName)
|
|
190
193
|
}
|
|
@@ -197,95 +200,135 @@ function initialize(agent, mongodb, moduleName, shim) {
|
|
|
197
200
|
shim.recordOperation(object.prototype, 'pipe')
|
|
198
201
|
}
|
|
199
202
|
}
|
|
203
|
+
}
|
|
200
204
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
205
|
+
function captureAttributesOnStarted(shim, instrumenter) {
|
|
206
|
+
instrumenter.on('started', function onMongoEventStarted(evnt) {
|
|
207
|
+
// This assumes that this `started` event is fired _after_ our wrapper
|
|
208
|
+
// starts and creates the segment. We perform a check of the segment name
|
|
209
|
+
// out of an excess of caution.
|
|
210
|
+
const connId = evnt.connectionId
|
|
211
|
+
if (connId) {
|
|
212
|
+
// Mongo sticks the path to the domain socket in the "host" slot, but we
|
|
213
|
+
// want it in the "port", so if we have a domain socket we need to change
|
|
214
|
+
// the order of our parameters.
|
|
215
|
+
if (typeof connId === 'string') {
|
|
216
|
+
const parts = connId.split(':')
|
|
217
|
+
if (parts.length && parts[0][0] === '/') {
|
|
218
|
+
shim.captureInstanceAttributes('localhost', parts[0], evnt.databaseName)
|
|
219
|
+
} else {
|
|
220
|
+
shim.captureInstanceAttributes(parts[0], parts[1], evnt.databaseName)
|
|
221
|
+
}
|
|
222
|
+
} else if (connId.domainSocket) {
|
|
223
|
+
shim.captureInstanceAttributes('localhost', connId.host, evnt.databaseName)
|
|
224
|
+
} else {
|
|
225
|
+
shim.captureInstanceAttributes(connId.host, connId.port, evnt.databaseName)
|
|
207
226
|
}
|
|
208
|
-
|
|
209
|
-
// segment name does not actually use query string
|
|
210
|
-
// method name is set as query so the query parser has access to the op name
|
|
211
|
-
return {query: methodName, callback: callback, parameters: parameters}
|
|
212
227
|
}
|
|
213
|
-
}
|
|
228
|
+
})
|
|
229
|
+
}
|
|
214
230
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
231
|
+
function instrumentLegacy(shim, mongodb) {
|
|
232
|
+
instrumentCursor(mongodb.Cursor)
|
|
233
|
+
instrumentCursor(shim.require('./lib/aggregation_cursor'))
|
|
234
|
+
instrumentCursor(shim.require('./lib/command_cursor'))
|
|
235
|
+
|
|
236
|
+
if (mongodb.Collection && mongodb.Collection.prototype) {
|
|
237
|
+
const proto = mongodb.Collection.prototype
|
|
238
|
+
for (let i = 0; i < COLLECTION_OPS.length; i++) {
|
|
239
|
+
shim.recordQuery(
|
|
240
|
+
proto,
|
|
241
|
+
COLLECTION_OPS[i],
|
|
242
|
+
makeQueryDescFunc(shim, COLLECTION_OPS[i])
|
|
224
243
|
)
|
|
225
|
-
var databaseName = obj.s.db.databaseName || null
|
|
226
|
-
var topology = obj.s.topology
|
|
227
|
-
if (topology.s && topology.s.options) {
|
|
228
|
-
return doCapture(topology.s.options, databaseName)
|
|
229
|
-
}
|
|
230
244
|
}
|
|
245
|
+
}
|
|
231
246
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
247
|
+
if (mongodb.Grid && mongodb.Grid.prototype) {
|
|
248
|
+
const proto = mongodb.Grid.prototype
|
|
249
|
+
for (let i = 0; i < CURSOR_OPS.length; i++) {
|
|
250
|
+
shim.recordOperation(proto, GRID_OPS[i],
|
|
251
|
+
{name:'GridFS-' + GRID_OPS[i], callback: shim.LAST})
|
|
237
252
|
}
|
|
253
|
+
}
|
|
238
254
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
// pass it through the port value.
|
|
245
|
-
if (
|
|
246
|
-
(conf.socketOptions && conf.socketOptions.domainSocket) || /\.sock$/.test(host)
|
|
247
|
-
) {
|
|
248
|
-
port = host
|
|
249
|
-
host = 'localhost'
|
|
250
|
-
}
|
|
255
|
+
if (mongodb.Db && mongodb.Db.prototype) {
|
|
256
|
+
const proto = mongodb.Db.prototype
|
|
257
|
+
shim.recordOperation(proto, DB_OPS, {callback: shim.LAST})
|
|
258
|
+
shim.recordOperation(mongodb.Db, 'connect', {callback: shim.LAST})
|
|
259
|
+
}
|
|
251
260
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
261
|
+
function instrumentCursor(Cursor) {
|
|
262
|
+
if (Cursor && Cursor.prototype) {
|
|
263
|
+
const proto = Cursor.prototype
|
|
264
|
+
for (let i = 0; i < CURSOR_OPS.length; i++) {
|
|
265
|
+
shim.recordQuery(proto, CURSOR_OPS[i], makeQueryDescFunc(shim, CURSOR_OPS[i]))
|
|
256
266
|
}
|
|
267
|
+
|
|
268
|
+
shim.recordQuery(proto, 'each', makeQueryDescFunc(shim, 'each'))
|
|
269
|
+
shim.recordOperation(proto, 'pipe')
|
|
257
270
|
}
|
|
258
271
|
}
|
|
272
|
+
}
|
|
259
273
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
shim.recordQuery(proto, 'each', makeQueryDescFunc('each'))
|
|
274
|
+
function makeQueryDescFunc(shim, methodName) {
|
|
275
|
+
if (methodName === 'each') {
|
|
276
|
+
return function eachDescFunc() {
|
|
277
|
+
const parameters = getInstanceAttributeParameters(shim, this)
|
|
278
|
+
return {query: methodName, parameters, rowCallback: shim.LAST}
|
|
268
279
|
}
|
|
280
|
+
}
|
|
269
281
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
282
|
+
return function queryDescFunc() {
|
|
283
|
+
// segment name does not actually use query string
|
|
284
|
+
// method name is set as query so the query parser has access to the op name
|
|
285
|
+
const parameters = getInstanceAttributeParameters(shim, this)
|
|
286
|
+
return {query: methodName, parameters, callback: shim.LAST}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function getInstanceAttributeParameters(shim, obj) {
|
|
291
|
+
if (obj.db && obj.db.serverConfig) {
|
|
292
|
+
shim.logger.trace('Adding datastore instance attributes from obj.db.serverConfig')
|
|
293
|
+
const serverConfig = obj.db.serverConfig
|
|
294
|
+
const db = serverConfig.db || serverConfig.dbInstance
|
|
295
|
+
return doCapture(serverConfig, db && db.databaseName)
|
|
296
|
+
} else if (obj.s && obj.s.db && obj.s.topology) {
|
|
297
|
+
shim.logger.trace(
|
|
298
|
+
'Adding datastore instance attributes from obj.s.db + obj.s.topology'
|
|
299
|
+
)
|
|
300
|
+
const databaseName = obj.s.db.databaseName || null
|
|
301
|
+
const topology = obj.s.topology
|
|
302
|
+
if (topology.s && topology.s.options) {
|
|
303
|
+
return doCapture(topology.s.options, databaseName)
|
|
275
304
|
}
|
|
305
|
+
}
|
|
276
306
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
307
|
+
shim.logger.trace('Could not find datastore instance attributes.')
|
|
308
|
+
return {
|
|
309
|
+
host: null,
|
|
310
|
+
port_path_or_id: null,
|
|
311
|
+
database_name: null
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function doCapture(conf, database) {
|
|
315
|
+
let host = conf.host
|
|
316
|
+
let port = conf.port
|
|
317
|
+
|
|
318
|
+
// If using a domain socket, mongo stores the path as the host name, but we
|
|
319
|
+
// pass it through the port value.
|
|
320
|
+
if (
|
|
321
|
+
(conf.socketOptions && conf.socketOptions.domainSocket) ||
|
|
322
|
+
/\.sock$/.test(host)
|
|
323
|
+
) {
|
|
324
|
+
port = host
|
|
325
|
+
host = 'localhost'
|
|
283
326
|
}
|
|
284
327
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
328
|
+
return {
|
|
329
|
+
host: host,
|
|
330
|
+
port_path_or_id: port,
|
|
331
|
+
database_name: database
|
|
289
332
|
}
|
|
290
333
|
}
|
|
291
334
|
}
|
|
@@ -33,7 +33,7 @@ function recordWeb(segment, scope) {
|
|
|
33
33
|
tx.measure(NAMES.QUEUETIME, null, tx.queueTime)
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
if (config.
|
|
36
|
+
if (config.distributed_tracing.enabled) {
|
|
37
37
|
recordDistributedTrace(tx, 'Web', duration, exclusive)
|
|
38
38
|
} else if (tx.incomingCatId) {
|
|
39
39
|
tx.measure(
|
|
@@ -34,7 +34,7 @@ function recordBackground(segment, scope) {
|
|
|
34
34
|
)
|
|
35
35
|
tx.measure(NAMES.OTHER_TRANSACTION.TOTAL_TIME, null, totalTime, exclusive)
|
|
36
36
|
|
|
37
|
-
if (tx.agent.config.
|
|
37
|
+
if (tx.agent.config.distributed_tracing.enabled) {
|
|
38
38
|
recordDistributedTrace(tx, 'Other', duration, exclusive)
|
|
39
39
|
}
|
|
40
40
|
}
|
package/lib/priority-queue.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
var Heap = require('@tyriar/fibonacci-heap').FibonacciHeap
|
|
4
4
|
|
|
5
5
|
function PriorityQueue(limit) {
|
|
6
|
-
this.limit = limit
|
|
6
|
+
this.limit = limit == null ? 10 : limit
|
|
7
7
|
this.seen = 0
|
|
8
8
|
this._data = new Heap()
|
|
9
9
|
|
|
@@ -24,8 +24,11 @@ PriorityQueue.prototype.getMinimumPriority = function getMinimumPriority() {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
PriorityQueue.prototype.add = function add(value, priority) {
|
|
27
|
-
priority = priority || Math.random()
|
|
28
27
|
this.seen++
|
|
28
|
+
if (this.limit <= 0) {
|
|
29
|
+
return false
|
|
30
|
+
}
|
|
31
|
+
priority = priority || Math.random()
|
|
29
32
|
if (this.length === this.limit) {
|
|
30
33
|
return this._replace(value, priority)
|
|
31
34
|
}
|
package/lib/shim/message-shim.js
CHANGED
|
@@ -333,10 +333,6 @@ function recordProduce(nodule, properties, recordNamer) {
|
|
|
333
333
|
}
|
|
334
334
|
|
|
335
335
|
var name = _nameMessageSegment(shim, msgDesc, shim._metrics.PRODUCE)
|
|
336
|
-
if (msgDesc.headers) {
|
|
337
|
-
shim.insertCATRequestHeaders(msgDesc.headers, true)
|
|
338
|
-
}
|
|
339
|
-
|
|
340
336
|
if (!shim.agent.config.message_tracer.segment_parameters.enabled) {
|
|
341
337
|
delete msgDesc.parameters
|
|
342
338
|
} else if (msgDesc.routingKey) {
|
|
@@ -350,6 +346,11 @@ function recordProduce(nodule, properties, recordNamer) {
|
|
|
350
346
|
promise: msgDesc.promise || false,
|
|
351
347
|
callback: msgDesc.callback || null,
|
|
352
348
|
recorder: genericRecorder,
|
|
349
|
+
inContext: function generateCATHeaders() {
|
|
350
|
+
if (msgDesc.headers) {
|
|
351
|
+
shim.insertCATRequestHeaders(msgDesc.headers, true)
|
|
352
|
+
}
|
|
353
|
+
},
|
|
353
354
|
parameters: msgDesc.parameters || null
|
|
354
355
|
}
|
|
355
356
|
})
|
package/lib/shim/shim.js
CHANGED
|
@@ -946,7 +946,7 @@ function record(nodule, properties, recordNamer) {
|
|
|
946
946
|
var promised = false
|
|
947
947
|
var ret
|
|
948
948
|
try {
|
|
949
|
-
ret = shim.applySegment(fn, segment, true, ctx, args)
|
|
949
|
+
ret = shim.applySegment(fn, segment, true, ctx, args, segDesc.inContext)
|
|
950
950
|
if (segDesc.after && segDesc.promise && shim.isPromise(ret)) {
|
|
951
951
|
promised = true
|
|
952
952
|
return ret.then(function onThen(val) {
|
|
@@ -1286,7 +1286,7 @@ function storeSegment(obj, segment) {
|
|
|
1286
1286
|
* Sets the given segment as the active one for the duration of the function's
|
|
1287
1287
|
* execution.
|
|
1288
1288
|
*
|
|
1289
|
-
* - `applySegment(func, segment, full, context, args)`
|
|
1289
|
+
* - `applySegment(func, segment, full, context, args[, inContextCB])`
|
|
1290
1290
|
*
|
|
1291
1291
|
* @memberof Shim.prototype
|
|
1292
1292
|
*
|
|
@@ -1305,9 +1305,15 @@ function storeSegment(obj, segment) {
|
|
|
1305
1305
|
* @param {Array.<*>} args
|
|
1306
1306
|
* The arguments to be passed into the function.
|
|
1307
1307
|
*
|
|
1308
|
+
* @param {Function} [inContextCB]
|
|
1309
|
+
* The function used to do more instrumentation work. This function is
|
|
1310
|
+
* guaranteed to be executed with the segment associated with.
|
|
1311
|
+
*
|
|
1312
|
+
*
|
|
1308
1313
|
* @return {*} Whatever value `func` returned.
|
|
1309
1314
|
*/
|
|
1310
|
-
|
|
1315
|
+
/* eslint-disable max-params */
|
|
1316
|
+
function applySegment(func, segment, full, context, args, inContextCB) {
|
|
1311
1317
|
// Exist fast for bad arguments.
|
|
1312
1318
|
if (!this.isFunction(func)) {
|
|
1313
1319
|
return
|
|
@@ -1327,6 +1333,10 @@ function applySegment(func, segment, full, context, args) {
|
|
|
1327
1333
|
segment.start()
|
|
1328
1334
|
}
|
|
1329
1335
|
|
|
1336
|
+
if (typeof inContextCB === 'function') {
|
|
1337
|
+
inContextCB()
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1330
1340
|
// Execute the function and then return the tracer segment to the old one.
|
|
1331
1341
|
try {
|
|
1332
1342
|
return func.apply(context, args)
|
|
@@ -1337,6 +1347,7 @@ function applySegment(func, segment, full, context, args) {
|
|
|
1337
1347
|
tracer.segment = prevSegment
|
|
1338
1348
|
}
|
|
1339
1349
|
}
|
|
1350
|
+
/* eslint-enable max-params */
|
|
1340
1351
|
|
|
1341
1352
|
/**
|
|
1342
1353
|
* Creates a new segment.
|
package/lib/shim/specs/index.js
CHANGED
|
@@ -45,6 +45,7 @@ function WrapSpec(spec) {
|
|
|
45
45
|
function SegmentSpec(spec) {
|
|
46
46
|
this.name = hasOwnProperty(spec, 'name') ? spec.name : null
|
|
47
47
|
this.recorder = hasOwnProperty(spec, 'recorder') ? spec.recorder : null
|
|
48
|
+
this.inContext = hasOwnProperty(spec, 'inContext') ? spec.inContext : null
|
|
48
49
|
this.parent = hasOwnProperty(spec, 'parent') ? spec.parent : null
|
|
49
50
|
this.parameters = hasOwnProperty(spec, 'parameters') ? spec.parameters : null
|
|
50
51
|
this.internal = hasOwnProperty(spec, 'internal') ? spec.internal : false
|
|
@@ -287,7 +287,7 @@ function handleCATHeaders(headers, segment, transportType) {
|
|
|
287
287
|
transportType = Transaction.TRANSPORT_TYPES.UNKNOWN
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
-
if (this.agent.config.
|
|
290
|
+
if (this.agent.config.distributed_tracing.enabled) {
|
|
291
291
|
const payload = headers[DISTRIBUTED_TRACE_HEADER]
|
|
292
292
|
if (payload) {
|
|
293
293
|
tx.acceptDistributedTracePayload(payload, transportType)
|
|
@@ -351,7 +351,7 @@ function insertCATRequestHeaders(headers, useAlternateHeaderNames) {
|
|
|
351
351
|
this.logger.trace('CAT disabled, not adding headers.')
|
|
352
352
|
return
|
|
353
353
|
}
|
|
354
|
-
var usingDistributedTracing = this.agent.config.
|
|
354
|
+
var usingDistributedTracing = this.agent.config.distributed_tracing.enabled
|
|
355
355
|
if (!this.agent.config.encoding_key && !usingDistributedTracing) {
|
|
356
356
|
this.logger.warn('Missing encoding key, not adding CAT headers!')
|
|
357
357
|
return
|
|
@@ -433,7 +433,7 @@ function insertCATReplyHeader(headers, useAlternateHeaderNames) {
|
|
|
433
433
|
if (!config.cross_application_tracer.enabled) {
|
|
434
434
|
this.logger.trace('CAT disabled, not adding reply header.')
|
|
435
435
|
return
|
|
436
|
-
} else if (config.
|
|
436
|
+
} else if (config.distributed_tracing.enabled) {
|
|
437
437
|
this.logger.warn('CAT disabled, distributed tracing is enabled')
|
|
438
438
|
return
|
|
439
439
|
} else if (!config.encoding_key) {
|
package/lib/shimmer.js
CHANGED
|
@@ -205,6 +205,9 @@ var shimmer = module.exports = {
|
|
|
205
205
|
if (original.__NR_unwrap) return logger.debug("%s already wrapped by agent.", fqmn)
|
|
206
206
|
|
|
207
207
|
var wrapped = wrapper(original, method)
|
|
208
|
+
Object.keys(original).forEach((key) => {
|
|
209
|
+
wrapped[key] = original[key]
|
|
210
|
+
})
|
|
208
211
|
wrapped.__NR_original = original
|
|
209
212
|
wrapped.__NR_unwrap = function __NR_unwrap() {
|
|
210
213
|
nodule[method] = original
|
|
@@ -7,6 +7,12 @@ const DT_VERSION_MAJOR = 0
|
|
|
7
7
|
const DT_VERSION_MINOR = 1
|
|
8
8
|
|
|
9
9
|
module.exports = class DistributedTracePayload {
|
|
10
|
+
/**
|
|
11
|
+
* The class reponsible for producing distributed trace payloads.
|
|
12
|
+
* Created by calling {@link TransactionHandle#createDistributedTracePayload}.
|
|
13
|
+
*
|
|
14
|
+
* @constructor
|
|
15
|
+
*/
|
|
10
16
|
constructor(payload) {
|
|
11
17
|
logger.trace('DistributedTracePayload created with %s', payload)
|
|
12
18
|
this.plainTextPayload = JSON.stringify({
|
|
@@ -16,11 +22,21 @@ module.exports = class DistributedTracePayload {
|
|
|
16
22
|
this.base64Payload = null
|
|
17
23
|
}
|
|
18
24
|
|
|
25
|
+
/**
|
|
26
|
+
* @returns {String} The base64 encoded JSON representation of the
|
|
27
|
+
* distributed trace payload.
|
|
28
|
+
*/
|
|
19
29
|
text() {
|
|
20
30
|
logger.trace('DistributedTracePayload text: %s', this.plainTextPayload)
|
|
21
31
|
return this.plainTextPayload
|
|
22
32
|
}
|
|
23
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Construct a payload suitable for HTTP transport.
|
|
36
|
+
*
|
|
37
|
+
* @returns {String} The base64 encoded JSON representation of the
|
|
38
|
+
* distributed trace payload.
|
|
39
|
+
*/
|
|
24
40
|
httpSafe() {
|
|
25
41
|
if (!this.base64Payload) {
|
|
26
42
|
this.base64Payload = makeBuffer(this.plainTextPayload, 'utf-8').toString('base64')
|
|
@@ -33,7 +33,7 @@ module.exports = class TransactionHandle {
|
|
|
33
33
|
*
|
|
34
34
|
* Proxy method for Transaction#createDistrubtedTracePayload.
|
|
35
35
|
*
|
|
36
|
-
* @returns {DistributedTracePayload} The created payload.
|
|
36
|
+
* @returns {DistributedTracePayload} The created payload object.
|
|
37
37
|
*
|
|
38
38
|
*/
|
|
39
39
|
createDistributedTracePayload() {
|
package/lib/transaction/index.js
CHANGED
|
@@ -193,6 +193,10 @@ Transaction.prototype.end = function end(done) {
|
|
|
193
193
|
transaction.record()
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
// This is function currently must be called after all recorders have been fired due
|
|
197
|
+
// to some of the recorders (namely the db recorders) add parameters to the segments.
|
|
198
|
+
transaction.trace.generateSpanEvents()
|
|
199
|
+
|
|
196
200
|
transaction.agent.emit('transactionFinished', transaction)
|
|
197
201
|
if (typeof done === 'function') {
|
|
198
202
|
done(transaction)
|
|
@@ -688,7 +692,7 @@ Transaction.prototype.getIntrinsicAttributes = function getIntrinsicAttributes()
|
|
|
688
692
|
|
|
689
693
|
// If CAT is enabled, extract the path hashes and referring transaction info.
|
|
690
694
|
if (config.cross_application_tracer.enabled) {
|
|
691
|
-
if (config.
|
|
695
|
+
if (config.distributed_tracing.enabled) {
|
|
692
696
|
this.addDistributedTraceIntrinsics(this._intrinsicAttributes)
|
|
693
697
|
} else {
|
|
694
698
|
this._intrinsicAttributes.path_hash = hashes.calculatePathHash(
|
|
@@ -750,7 +754,7 @@ function acceptDistributedTracePayload(payload, transport) {
|
|
|
750
754
|
}
|
|
751
755
|
|
|
752
756
|
const config = this.agent.config
|
|
753
|
-
const distTraceEnabled = config.
|
|
757
|
+
const distTraceEnabled = config.distributed_tracing.enabled
|
|
754
758
|
const catEnabled = config.cross_application_tracer.enabled
|
|
755
759
|
const trustedAccount = config.trusted_account_key || config.account_id
|
|
756
760
|
|
|
@@ -895,7 +899,7 @@ function createDistributedTracePayload() {
|
|
|
895
899
|
const config = this.agent.config
|
|
896
900
|
const accountId = config.account_id
|
|
897
901
|
const appId = config.application_id
|
|
898
|
-
const distTraceEnabled = config.
|
|
902
|
+
const distTraceEnabled = config.distributed_tracing.enabled
|
|
899
903
|
const catEnabled = config.cross_application_tracer.enabled
|
|
900
904
|
|
|
901
905
|
if (!accountId || !appId || !distTraceEnabled || !catEnabled) {
|
|
@@ -920,7 +924,7 @@ function createDistributedTracePayload() {
|
|
|
920
924
|
ti: Date.now()
|
|
921
925
|
}
|
|
922
926
|
|
|
923
|
-
if (this.agent.config.span_events.enabled && currSegment) {
|
|
927
|
+
if (this.agent.config.span_events.enabled && this.sampled && currSegment) {
|
|
924
928
|
data.id = currSegment.id
|
|
925
929
|
}
|
|
926
930
|
|