newrelic 4.6.0 → 4.7.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 +112 -1
- package/api.js +8 -1
- package/index.js +16 -8
- package/lib/config/default.js +5 -0
- package/lib/db/tracer.js +14 -5
- package/lib/environment.js +1 -1
- package/lib/instrumentation/core/http.js +3 -3
- 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/transaction/dt-payload.js +16 -0
- package/lib/transaction/handle.js +1 -1
- package/lib/transaction/index.js +4 -0
- package/lib/transaction/trace/index.js +30 -37
- package/package.json +2 -2
package/NEWS.md
CHANGED
|
@@ -1,3 +1,40 @@
|
|
|
1
|
+
### 4.7.0 (2018-07-31):
|
|
2
|
+
|
|
3
|
+
* Added support for distributed tracing.
|
|
4
|
+
|
|
5
|
+
Distributed tracing lets you see the path that a request takes as it travels
|
|
6
|
+
through your distributed system. By showing the distributed activity through a
|
|
7
|
+
unified view, you can troubleshoot and understand a complex system better than
|
|
8
|
+
ever before.
|
|
9
|
+
|
|
10
|
+
Distributed tracing is available with an APM Pro or equivalent subscription.
|
|
11
|
+
To see a complete distributed trace, you need to enable the feature on a set of
|
|
12
|
+
neighboring services. Enabling distributed tracing changes the behavior of some
|
|
13
|
+
New Relic features, so carefully consult the [transition guide](https://docs.newrelic.com/docs/transition-guide-distributed-tracing) before
|
|
14
|
+
you enable this feature.
|
|
15
|
+
|
|
16
|
+
To enable distributed tracing, set `distributed_tracing.enabled` to `true` in
|
|
17
|
+
your `newrelic.js` file, or set `NEW_RELIC_DISTRIBUTED_TRACING_ENABLED` in your
|
|
18
|
+
environment.
|
|
19
|
+
|
|
20
|
+
* Added a warning for too-new versions of Node.js during agent startup.
|
|
21
|
+
|
|
22
|
+
* Appropriately obfuscated SQL statements will now be included in all transaction
|
|
23
|
+
traces.
|
|
24
|
+
|
|
25
|
+
Previously, the agent would only include the SQL statements if the corresponding
|
|
26
|
+
query was sufficiently slow.
|
|
27
|
+
|
|
28
|
+
* Added ability to execute instrumentation functions in the context of the segment
|
|
29
|
+
the segment descriptor is describing.
|
|
30
|
+
|
|
31
|
+
All `record*` methods supplied by all instrumentation shim classes now allow for
|
|
32
|
+
a function to be executed under the context of the segment the record call will
|
|
33
|
+
produce. This may be done by supplying a function in the `inContext` key for the
|
|
34
|
+
segment descriptor passed to the record method.
|
|
35
|
+
|
|
36
|
+
* Reservoirs will now respect setting their size to 0.
|
|
37
|
+
|
|
1
38
|
### 4.6.0 (2018-07-24):
|
|
2
39
|
|
|
3
40
|
* Added full support for Node v10.
|
|
@@ -11,6 +48,8 @@
|
|
|
11
48
|
* Updated tests to use `asyncResource.runInAsyncScope` instead of `emitBefore` and
|
|
12
49
|
`emitAfter`
|
|
13
50
|
|
|
51
|
+
* Pulled `distributed_tracing` config value from behind `feature_flag`.
|
|
52
|
+
|
|
14
53
|
### 4.5.1 (2018-07-18):
|
|
15
54
|
|
|
16
55
|
- The agent will now properly remerge event data on collection failure.
|
|
@@ -33,6 +72,12 @@
|
|
|
33
72
|
|
|
34
73
|
* Updated Hapi v17 instrumentation to wrap `server` export, in addition to `Server`.
|
|
35
74
|
|
|
75
|
+
* `ROOT` segment no longer turns into a span event.
|
|
76
|
+
|
|
77
|
+
* Fixed span collection when transactions are `sampled=false`.
|
|
78
|
+
|
|
79
|
+
* Removed `grandparentId` from spans.
|
|
80
|
+
|
|
36
81
|
### 4.4.0 (2018-07-12):
|
|
37
82
|
|
|
38
83
|
* Added config `utilization` env vars to the `BOOLEAN_VARS` set.
|
|
@@ -44,6 +89,29 @@
|
|
|
44
89
|
|
|
45
90
|
* Added node v10 to the test matrix.
|
|
46
91
|
|
|
92
|
+
* Converted distributed trace `x-newrelic-trace` header name to `newrelic`.
|
|
93
|
+
|
|
94
|
+
* Added support for different transport types in distributed tracing.
|
|
95
|
+
|
|
96
|
+
* Added more tests around priority/sampled attributes on traces and events.
|
|
97
|
+
|
|
98
|
+
* Lazily calculate transaction priority only when needed.
|
|
99
|
+
|
|
100
|
+
* Transaction priority is now truncated to 6 decimal places on generation.
|
|
101
|
+
|
|
102
|
+
* Adaptive sampling now uses the `sampling_target` and
|
|
103
|
+
`sampling_target_period_in_seconds` configuration values.
|
|
104
|
+
|
|
105
|
+
With these configurations, the adaptive sampling window is separated from the
|
|
106
|
+
harvest window.
|
|
107
|
+
|
|
108
|
+
* Removed `nr.tripId` attribute from distributed trace intrinsics.
|
|
109
|
+
|
|
110
|
+
* Default span events to enabled.
|
|
111
|
+
|
|
112
|
+
These are still protected behind `feature_flag.distributed_tracing` which defaults
|
|
113
|
+
to `false`.
|
|
114
|
+
|
|
47
115
|
### 4.3.0 (2018-07-09):
|
|
48
116
|
|
|
49
117
|
* Added `nonce` option for `newrelic.getBrowserTimingHeader()`
|
|
@@ -65,7 +133,7 @@
|
|
|
65
133
|
|
|
66
134
|
* Fixed issue with tracking external requests to default ports.
|
|
67
135
|
|
|
68
|
-
|
|
136
|
+
Special thanks to Ryan King for pinpointing the cause of this issue.
|
|
69
137
|
|
|
70
138
|
* Added extra check for handling arrays of functions when wrapping middleware
|
|
71
139
|
mounters.
|
|
@@ -103,6 +171,25 @@
|
|
|
103
171
|
|
|
104
172
|
* No longer download gcc on test suites that do not require it.
|
|
105
173
|
|
|
174
|
+
* Added `url` parameter to `http` external segments.
|
|
175
|
+
|
|
176
|
+
* Renamed request parameters on external segments.
|
|
177
|
+
|
|
178
|
+
Previously these were named just the parameter name (e.g. `/foo?bar=baz` would
|
|
179
|
+
become the parameter `"bar": "baz"`). Now they are prefixed with
|
|
180
|
+
`request.parameter`. (e.g. `"request.parameter.bar": "baz"`).
|
|
181
|
+
|
|
182
|
+
* Added `EventAggregator` base class.
|
|
183
|
+
|
|
184
|
+
The `ErrorAggregator` class was refactored and most generic event aggregation
|
|
185
|
+
logic was moved to the new `EventAggregator` class.
|
|
186
|
+
|
|
187
|
+
* Added `SpanEvent` and `SpanAggregator` classes.
|
|
188
|
+
|
|
189
|
+
* Added Span event generation to the trace `end` method.
|
|
190
|
+
|
|
191
|
+
* Added Span events to harvest cycle steps.
|
|
192
|
+
|
|
106
193
|
### 4.1.5 (2018-06-11):
|
|
107
194
|
|
|
108
195
|
* Make `require()` statements explicitly reference `package.json` as a `.json` file.
|
|
@@ -145,6 +232,11 @@
|
|
|
145
232
|
result in a false `uninstrumented` status, because the agent would interpret
|
|
146
233
|
`redis.js` as the module itself.
|
|
147
234
|
|
|
235
|
+
* Moved `computeSampled` call to `Transaction` constructor.
|
|
236
|
+
|
|
237
|
+
Previously it was only called in `createDistributedTracePayload`, but this
|
|
238
|
+
gives all transactions a `sampled` value, and potentially a boosted priority.
|
|
239
|
+
|
|
148
240
|
### 4.1.4 (2018-06-04):
|
|
149
241
|
|
|
150
242
|
* Transaction stubs are now created properly in `api#getTransaction`
|
|
@@ -168,6 +260,25 @@
|
|
|
168
260
|
|
|
169
261
|
* Modularlized configuration constants to improve readability.
|
|
170
262
|
|
|
263
|
+
* Added `distributed_tracing` feature flag.
|
|
264
|
+
|
|
265
|
+
* Added `acceptDistributedTracePayload` method to `Transaction`.
|
|
266
|
+
|
|
267
|
+
* Added `createDistributedTracePayload` method to `Transaction`.
|
|
268
|
+
|
|
269
|
+
* Updated `Agent#recordSupportability` to not include `Nodejs/` in the default metric name.
|
|
270
|
+
|
|
271
|
+
* Added distributed tracing methods to `TransactionHandle`.
|
|
272
|
+
|
|
273
|
+
* Added distributed tracing cases for `http` and `other` metric recorders.
|
|
274
|
+
|
|
275
|
+
* Implemented `_addDistributedTraceInstrinsics` on `Transaction`.
|
|
276
|
+
|
|
277
|
+
If the `distributed_tracing` feature flag is enabled, the agent will ignore old
|
|
278
|
+
CAT attributes in favor of distributed trace–related ones.
|
|
279
|
+
|
|
280
|
+
* Added integration tests around better CAT functionality.
|
|
281
|
+
|
|
171
282
|
### 4.1.2 (2018-05-22):
|
|
172
283
|
|
|
173
284
|
* Fixed access to properties on promisified methods.
|
package/api.js
CHANGED
|
@@ -702,6 +702,13 @@ function createTracer(name, callback) {
|
|
|
702
702
|
return arity.fixArity(callback, tracer.bindFunction(callback, segment, true))
|
|
703
703
|
}
|
|
704
704
|
|
|
705
|
+
/**
|
|
706
|
+
* @callback startSegmentCallback
|
|
707
|
+
* @param {function} cb
|
|
708
|
+
* The function to time with the created segment.
|
|
709
|
+
* @return {Promise=} Returns a promise if cb returns a promise.
|
|
710
|
+
*/
|
|
711
|
+
|
|
705
712
|
/**
|
|
706
713
|
* Wraps the given handler in a segment which may optionally be turned into a
|
|
707
714
|
* metric.
|
|
@@ -720,7 +727,7 @@ function createTracer(name, callback) {
|
|
|
720
727
|
* up on the transaction breakdown table and server breakdown graph. Segments
|
|
721
728
|
* just show up in transaction traces.
|
|
722
729
|
*
|
|
723
|
-
* @param {
|
|
730
|
+
* @param {startSegmentCallback} handler
|
|
724
731
|
* The function to track as a segment.
|
|
725
732
|
*
|
|
726
733
|
* @param {function} [callback]
|
package/index.js
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
// Record opening times before loading any other files.
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
const preAgentTime = process.uptime()
|
|
5
|
+
const agentStart = Date.now()
|
|
6
6
|
|
|
7
7
|
// Load unwrapped core now to ensure it gets the freshest properties.
|
|
8
8
|
require('./lib/util/unwrapped-core')
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
const featureFlags = require('./lib/feature_flags').prerelease
|
|
11
|
+
const psemver = require('./lib/util/process-version')
|
|
12
|
+
let logger = require('./lib/logger') // Gets re-loaded after initialization.
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
const pkgJSON = require('./package.json')
|
|
16
16
|
logger.info(
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
'Using New Relic for Node.js. Agent version: %s; Node version: %s.',
|
|
18
|
+
pkgJSON.version,
|
|
19
|
+
process.version
|
|
19
20
|
)
|
|
20
21
|
|
|
21
22
|
if (require.cache.__NR_cache) {
|
|
@@ -49,6 +50,13 @@ function initialize() {
|
|
|
49
50
|
|
|
50
51
|
logger.error(message)
|
|
51
52
|
throw new Error(message)
|
|
53
|
+
} else if (!psemver.satisfies(pkgJSON.engines.node)) {
|
|
54
|
+
logger.warn(
|
|
55
|
+
'New Relic for Node.js %s has not been tested on Node.js %s. Please ' +
|
|
56
|
+
'update the agent or downgrade your version of Node.js',
|
|
57
|
+
pkgJSON.version,
|
|
58
|
+
process.version
|
|
59
|
+
)
|
|
52
60
|
}
|
|
53
61
|
|
|
54
62
|
logger.debug("Current working directory at module load is %s.", process.cwd())
|
package/lib/config/default.js
CHANGED
|
@@ -793,6 +793,11 @@ exports.config = {
|
|
|
793
793
|
|
|
794
794
|
/**
|
|
795
795
|
* Controls the method of cross agent tracing in the agent.
|
|
796
|
+
* Distributed tracing lets you see the path that a request takes through your
|
|
797
|
+
* distributed system. Enabling distributed tracing changes the behavior of some
|
|
798
|
+
* New Relic features, so carefully consult the transition guide before you enable
|
|
799
|
+
* this feature: https://docs.newrelic.com/docs/transition-guide-distributed-tracing
|
|
800
|
+
* Default is false.
|
|
796
801
|
*/
|
|
797
802
|
distributed_tracing: {
|
|
798
803
|
/**
|
package/lib/db/tracer.js
CHANGED
|
@@ -46,27 +46,36 @@ QueryTracer.prototype.merge = function merge(tracer) {
|
|
|
46
46
|
|
|
47
47
|
QueryTracer.prototype.addQuery = function addQuery(segment, type, query, trace) {
|
|
48
48
|
const ttConfig = this.config.transaction_tracer
|
|
49
|
-
if (segment.getDurationInMillis() < ttConfig.explain_threshold) {
|
|
50
|
-
return
|
|
51
|
-
}
|
|
52
|
-
const slowQuery = new SlowQuery(segment, type, query, trace)
|
|
53
49
|
|
|
50
|
+
// If DT is enabled and the segment is part of a sampled transaction
|
|
51
|
+
// (i.e. we are creating a span event for this segment), then we need
|
|
52
|
+
// to collect the sql trace.
|
|
53
|
+
var slowQuery
|
|
54
54
|
switch (ttConfig.record_sql) {
|
|
55
55
|
case 'raw':
|
|
56
|
+
slowQuery = new SlowQuery(segment, type, query, trace)
|
|
56
57
|
logger.trace('recording raw sql')
|
|
57
58
|
segment.parameters.sql = slowQuery.query
|
|
58
59
|
break
|
|
59
60
|
case 'obfuscated':
|
|
61
|
+
slowQuery = new SlowQuery(segment, type, query, trace)
|
|
60
62
|
logger.trace('recording obfuscated sql')
|
|
61
63
|
segment.parameters.sql_obfuscated = slowQuery.obfuscated
|
|
62
64
|
break
|
|
63
65
|
default:
|
|
64
66
|
logger.trace(
|
|
65
|
-
'not
|
|
67
|
+
'not recording sql statement, transaction_tracer.record_sql was set to %s',
|
|
66
68
|
ttConfig.record_sql
|
|
67
69
|
)
|
|
68
70
|
return
|
|
69
71
|
}
|
|
72
|
+
|
|
73
|
+
if (segment.getDurationInMillis() < ttConfig.explain_threshold) {
|
|
74
|
+
return
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
slowQuery = slowQuery || new SlowQuery(segment, type, query, trace)
|
|
78
|
+
|
|
70
79
|
segment.parameters.backtrace = slowQuery.trace
|
|
71
80
|
|
|
72
81
|
if (!this.config.slow_sql.enabled) {
|
package/lib/environment.js
CHANGED
|
@@ -305,7 +305,7 @@ function getGlobalPackages(cb) {
|
|
|
305
305
|
* package appears at most once, with all the versions joined into a
|
|
306
306
|
* comma-delimited list.
|
|
307
307
|
*
|
|
308
|
-
* @return {Array.<
|
|
308
|
+
* @return {Array.<string[]>} Sorted list of [name, version] pairs.
|
|
309
309
|
*/
|
|
310
310
|
function flattenVersions(packages) {
|
|
311
311
|
var info = Object.create(null)
|
|
@@ -693,7 +693,7 @@ module.exports = function initialize(agent, http, moduleName) {
|
|
|
693
693
|
*
|
|
694
694
|
* @param {string} header - The raw X-NewRelic-Synthetics header
|
|
695
695
|
* @param {string} encKey - Encoding key handed down from the server
|
|
696
|
-
* @param {
|
|
696
|
+
* @param {Array.<number>} trustedIds - Array of accounts to trust the header from.
|
|
697
697
|
* @param {Transaction} transaction - Where the synthetics data is attached to.
|
|
698
698
|
*/
|
|
699
699
|
function handleSyntheticsHeader(header, encKey, trustedIds, transaction) {
|
|
@@ -711,8 +711,8 @@ function handleSyntheticsHeader(header, encKey, trustedIds, transaction) {
|
|
|
711
711
|
*
|
|
712
712
|
* @param {string} header - The raw X-NewRelic-Synthetics header
|
|
713
713
|
* @param {string} encKey - Encoding key handed down from the server
|
|
714
|
-
* @param {
|
|
715
|
-
* @return {Object
|
|
714
|
+
* @param {Array.<number>} trustedIds - Array of accounts to trust the header from.
|
|
715
|
+
* @return {Object|null} - On successful parse and verification an object of
|
|
716
716
|
* synthetics data is returned, otherwise null is
|
|
717
717
|
* returned.
|
|
718
718
|
*/
|
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
|
|
@@ -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)
|
|
@@ -49,30 +49,48 @@ function Trace(transaction) {
|
|
|
49
49
|
* segments that support recording.
|
|
50
50
|
*/
|
|
51
51
|
Trace.prototype.end = function end() {
|
|
52
|
+
var segments = [this.root]
|
|
53
|
+
|
|
54
|
+
while (segments.length) {
|
|
55
|
+
var segment = segments.pop()
|
|
56
|
+
_softEndSegment(segment)
|
|
57
|
+
Array.prototype.push.apply(segments, segment.getChildren())
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Iterates over the trace tree and generates a span event for each segment.
|
|
63
|
+
*/
|
|
64
|
+
Trace.prototype.generateSpanEvents = function generateSpanEvents() {
|
|
52
65
|
var config = this.transaction.agent.config
|
|
53
|
-
var segments = []
|
|
54
|
-
var processFn
|
|
55
66
|
|
|
56
67
|
if (
|
|
57
68
|
this.transaction.sampled &&
|
|
58
69
|
config.span_events.enabled &&
|
|
59
70
|
config.distributed_tracing.enabled
|
|
60
71
|
) {
|
|
72
|
+
var toProcess = []
|
|
61
73
|
// Root segment does not become a span, so we need to process it separately.
|
|
62
|
-
|
|
74
|
+
const spanAggregator = this.transaction.agent.spans
|
|
63
75
|
const children = this.root.getChildren()
|
|
64
76
|
for (let i = 0; i < children.length; ++i) {
|
|
65
|
-
|
|
77
|
+
toProcess.push(new DTTraceNode(children[i], this.transaction.parentSpanId))
|
|
66
78
|
}
|
|
67
|
-
processFn = makeDTNodeProcessor(this.transaction.agent.spans)
|
|
68
|
-
} else {
|
|
69
|
-
segments.push(this.root)
|
|
70
|
-
processFn = processNode
|
|
71
|
-
}
|
|
72
79
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
80
|
+
while (toProcess.length) {
|
|
81
|
+
var segmentInfo = toProcess.pop()
|
|
82
|
+
var segment = segmentInfo.segment
|
|
83
|
+
|
|
84
|
+
// Even though at some point we might want to stop adding events
|
|
85
|
+
// because all the priorities should be the same, we need to count
|
|
86
|
+
// the spans as seen.
|
|
87
|
+
spanAggregator.addSegment(segment, segmentInfo.parentId)
|
|
88
|
+
|
|
89
|
+
Array.prototype.push.apply(
|
|
90
|
+
toProcess,
|
|
91
|
+
segment.getChildren().map(child => new DTTraceNode(child, segment.id))
|
|
92
|
+
)
|
|
93
|
+
}
|
|
76
94
|
}
|
|
77
95
|
}
|
|
78
96
|
|
|
@@ -90,31 +108,6 @@ function _softEndSegment(segment) {
|
|
|
90
108
|
}
|
|
91
109
|
}
|
|
92
110
|
|
|
93
|
-
function makeDTNodeProcessor(spanAggregator) {
|
|
94
|
-
var addMoreSpans = true
|
|
95
|
-
return function processNodeDT(segmentInfo, segments) {
|
|
96
|
-
var segment = segmentInfo.segment
|
|
97
|
-
_softEndSegment(segment)
|
|
98
|
-
|
|
99
|
-
// This assumes that spans will have their transaction's priority. If insertion of
|
|
100
|
-
// one event fails, all following will fail due to having the same priority.
|
|
101
|
-
if (addMoreSpans && segment.name !== 'ROOT') {
|
|
102
|
-
addMoreSpans = spanAggregator.addSegment(segment, segmentInfo.parentId)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
var children = segment.getChildren()
|
|
106
|
-
Array.prototype.push.apply(
|
|
107
|
-
segments,
|
|
108
|
-
children.map(child => new DTTraceNode(child, segment.id))
|
|
109
|
-
)
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function processNode(segment, segments) {
|
|
114
|
-
_softEndSegment(segment)
|
|
115
|
-
Array.prototype.push.apply(segments, segment.getChildren())
|
|
116
|
-
}
|
|
117
|
-
|
|
118
111
|
/**
|
|
119
112
|
* Add a child to the list of segments.
|
|
120
113
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "newrelic",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.7.0",
|
|
4
4
|
"author": "New Relic Node.js agent team <nodejs@newrelic.com>",
|
|
5
5
|
"licenses": [
|
|
6
6
|
{
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
],
|
|
97
97
|
"homepage": "http://github.com/newrelic/node-newrelic",
|
|
98
98
|
"engines": {
|
|
99
|
-
"node": ">=4.0.0",
|
|
99
|
+
"node": ">=4.0.0 <11.0.0",
|
|
100
100
|
"npm": ">=2.0.0"
|
|
101
101
|
},
|
|
102
102
|
"directories": {
|