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.
@@ -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
- var DB_OPS = [
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
- var COLLECTION_OPS = [
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
- var GRID_OPS = [
84
+ const GRID_OPS = [
83
85
  'put',
84
86
  'get',
85
87
  'delete'
86
88
  ]
87
89
 
88
- var CURSOR_OPS = [
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
- var collection = this.collectionName || 'unknown'
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
- // instrument using the apm api
133
- if (mongodb.instrument) {
134
- var instrumenter = mongodb.instrument(Object.create(null), instrumentModules)
135
- instrumenter.on('started', function onMongoEventStarted(evnt) {
136
- // This assumes that this `started` event is fired _after_ our wrapper
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
- // fallback to legacy enumerations
153
- legacyInstrumentation()
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
- function makeQueryDescFunc(methodName) {
202
- return function queryDescFunc() {
203
- var parameters = getInstanceAttributeParameters(this)
204
- var callback = shim.LAST
205
- if (methodName === 'each') {
206
- return {query: methodName, parameters: parameters, rowCallback: callback}
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
- function getInstanceAttributeParameters(obj) {
216
- if (obj.db && obj.db.serverConfig) {
217
- shim.logger.trace('Adding datastore instance attributes from obj.db.serverConfig')
218
- var serverConfig = obj.db.serverConfig
219
- var db = serverConfig.db || serverConfig.dbInstance
220
- return doCapture(serverConfig, db && db.databaseName)
221
- } else if (obj.s && obj.s.db && obj.s.topology) {
222
- shim.logger.trace(
223
- 'Adding datastore instance attributes from obj.s.db + obj.s.topology'
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
- shim.logger.trace('Could not find datastore instance attributes.')
233
- return {
234
- host: null,
235
- port_path_or_id: null,
236
- database_name: null
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
- function doCapture(conf, database) {
240
- var host = conf.host
241
- var port = conf.port
242
-
243
- // If using a domain socket, mongo stores the path as the host name, but we
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
- return {
253
- host: host,
254
- port_path_or_id: port,
255
- database_name: database
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
- function legacyInstrumentation() {
261
- if (mongodb.Cursor && mongodb.Cursor.prototype) {
262
- var proto = mongodb.Cursor.prototype
263
- for (var i = 0; i < CURSOR_OPS.length; i++) {
264
- shim.recordQuery(proto, CURSOR_OPS[i], makeQueryDescFunc(CURSOR_OPS[i]))
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
- if (mongodb.Collection && mongodb.Collection.prototype) {
271
- var proto = mongodb.Collection.prototype
272
- for (var i = 0; i < COLLECTION_OPS.length; i++) {
273
- shim.recordQuery(proto, COLLECTION_OPS[i], makeQueryDescFunc(COLLECTION_OPS[i]))
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
- if (mongodb.Grid && mongodb.Grid.prototype) {
278
- var proto = mongodb.Grid.prototype
279
- for (var i = 0; i < CURSOR_OPS.length; i++) {
280
- shim.recordOperation(proto, GRID_OPS[i],
281
- {name:'GridFS-' + GRID_OPS[i], callback: shim.LAST})
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
- if (mongodb.Db && mongodb.Db.prototype) {
286
- var proto = mongodb.Db.prototype
287
- shim.recordOperation(proto, DB_OPS, {callback: shim.LAST})
288
- shim.recordOperation(mongodb.Db, 'connect', {callback: shim.LAST})
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.feature_flag.distributed_tracing) {
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.feature_flag.distributed_tracing) {
37
+ if (tx.agent.config.distributed_tracing.enabled) {
38
38
  recordDistributedTrace(tx, 'Other', duration, exclusive)
39
39
  }
40
40
  }
@@ -3,7 +3,7 @@
3
3
  var Heap = require('@tyriar/fibonacci-heap').FibonacciHeap
4
4
 
5
5
  function PriorityQueue(limit) {
6
- this.limit = limit || 10
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
  }
@@ -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
- function applySegment(func, segment, full, context, args) {
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.
@@ -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.feature_flag.distributed_tracing) {
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.feature_flag.distributed_tracing
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.feature_flag.distributed_tracing) {
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() {
@@ -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.feature_flag.distributed_tracing) {
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.feature_flag.distributed_tracing
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.feature_flag.distributed_tracing
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