newrelic 6.13.1 → 7.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NEWS.md +80 -1
- package/README.md +14 -5
- package/THIRD_PARTY_NOTICES.md +10 -68
- package/api.js +0 -32
- package/bin/run-versioned-tests.sh +3 -8
- package/index.js +5 -3
- package/lib/agent.js +4 -0
- package/lib/collector/remote-method.js +17 -11
- package/lib/collector/serverless.js +1 -4
- package/lib/config/default.js +0 -8
- package/lib/config/env.js +0 -1
- package/lib/config/index.js +0 -21
- package/lib/errors/error-collector.js +6 -1
- package/lib/errors/index.js +14 -1
- package/lib/grpc/connection.js +26 -2
- package/lib/instrumentation/core/http.js +31 -79
- package/lib/metrics/names.js +4 -1
- package/lib/serverless/aws-lambda.js +0 -18
- package/lib/spans/span-context.js +18 -0
- package/lib/spans/span-event.js +13 -2
- package/lib/spans/span-streamer.js +24 -13
- package/lib/spans/streaming-span-event-aggregator.js +4 -0
- package/lib/spans/streaming-span-event.js +13 -1
- package/lib/transaction/dt-payload.js +1 -1
- package/lib/transaction/handle.js +0 -54
- package/lib/transaction/index.js +23 -37
- package/lib/transaction/tracecontext.js +17 -2
- package/package.json +11 -12
- package/third_party_manifest.json +36 -49
|
@@ -15,7 +15,6 @@ const util = require('util')
|
|
|
15
15
|
const url = require('url')
|
|
16
16
|
const urltils = require('../../util/urltils')
|
|
17
17
|
const properties = require('../../util/properties')
|
|
18
|
-
const psemver = require('../../util/process-version')
|
|
19
18
|
const headerAttributes = require('../../header-attributes')
|
|
20
19
|
const headerProcessing = require('../../header-processing')
|
|
21
20
|
|
|
@@ -27,8 +26,6 @@ const DESTS = require('../../config/attribute-filter').DESTINATIONS
|
|
|
27
26
|
* CONSTANTS
|
|
28
27
|
*
|
|
29
28
|
*/
|
|
30
|
-
const SHOULD_WRAP_HTTPS = psemver.satisfies('>=9.0.0 || 8.9.0')
|
|
31
|
-
const SHOULD_FORMAT_ARGS = psemver.satisfies('>=10.0.0')
|
|
32
29
|
const NR_CONNECTION_PROP = '__NR__connection'
|
|
33
30
|
const NEWRELIC_ID_HEADER = 'x-newrelic-id'
|
|
34
31
|
const NEWRELIC_APP_DATA_HEADER = 'x-newrelic-app-data'
|
|
@@ -172,16 +169,7 @@ function wrapEmitWithTransaction(agent, emit, isHTTPS) {
|
|
|
172
169
|
|
|
173
170
|
if (response) {
|
|
174
171
|
if (response.statusCode != null) {
|
|
175
|
-
/*
|
|
176
|
-
TODO: remove with next major release
|
|
177
|
-
httpResponseCode attribute is deprecated
|
|
178
|
-
*/
|
|
179
172
|
var responseCode = String(response.statusCode)
|
|
180
|
-
transaction.trace.attributes.addAttribute(
|
|
181
|
-
DESTS.TRANS_COMMON,
|
|
182
|
-
'httpResponseCode',
|
|
183
|
-
responseCode
|
|
184
|
-
)
|
|
185
173
|
|
|
186
174
|
if (/^\d+$/.test(responseCode)) {
|
|
187
175
|
transaction.trace.attributes.addAttribute(
|
|
@@ -191,16 +179,6 @@ function wrapEmitWithTransaction(agent, emit, isHTTPS) {
|
|
|
191
179
|
)
|
|
192
180
|
|
|
193
181
|
segment.addSpanAttribute('http.statusCode', responseCode)
|
|
194
|
-
|
|
195
|
-
/*
|
|
196
|
-
TODO: remove with next major release
|
|
197
|
-
response.status attribute is deprecated
|
|
198
|
-
*/
|
|
199
|
-
transaction.trace.attributes.addAttribute(
|
|
200
|
-
DESTS.TRANS_COMMON,
|
|
201
|
-
'response.status',
|
|
202
|
-
responseCode
|
|
203
|
-
)
|
|
204
182
|
}
|
|
205
183
|
}
|
|
206
184
|
|
|
@@ -212,16 +190,6 @@ function wrapEmitWithTransaction(agent, emit, isHTTPS) {
|
|
|
212
190
|
)
|
|
213
191
|
|
|
214
192
|
segment.addSpanAttribute('http.statusText', response.statusMessage)
|
|
215
|
-
|
|
216
|
-
/*
|
|
217
|
-
TODO: remove with next major release
|
|
218
|
-
httpResponseMessage attribute is deprecated
|
|
219
|
-
*/
|
|
220
|
-
transaction.trace.attributes.addAttribute(
|
|
221
|
-
DESTS.TRANS_COMMON,
|
|
222
|
-
'httpResponseMessage',
|
|
223
|
-
response.statusMessage
|
|
224
|
-
)
|
|
225
193
|
}
|
|
226
194
|
|
|
227
195
|
var headers = response.getHeaders()
|
|
@@ -442,37 +410,30 @@ function urlToOptions(_url) {
|
|
|
442
410
|
}
|
|
443
411
|
|
|
444
412
|
function wrapRequest(agent, request) {
|
|
445
|
-
// URL as a global was not added until Node v10
|
|
446
|
-
const URLClass = global.URL ? global.URL : url.URL
|
|
447
413
|
return function wrappedRequest(input, options, cb) {
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
} else if (input.constructor && input.constructor.name === 'URL') {
|
|
456
|
-
input = urlToOptions(input)
|
|
457
|
-
} else {
|
|
458
|
-
cb = options
|
|
459
|
-
options = input
|
|
460
|
-
input = null
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
if (typeof options === 'function') {
|
|
464
|
-
cb = options
|
|
465
|
-
options = input || {}
|
|
466
|
-
} else {
|
|
467
|
-
options = Object.assign(input || {}, options)
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
reqArgs = [options, cb]
|
|
414
|
+
// If the first argument is a URL, merge it into the options object.
|
|
415
|
+
// This code is copied from Node internals.
|
|
416
|
+
if (typeof input === 'string') {
|
|
417
|
+
const urlStr = input
|
|
418
|
+
input = urlToOptions(new URL(urlStr))
|
|
419
|
+
} else if (input.constructor && input.constructor.name === 'URL') {
|
|
420
|
+
input = urlToOptions(input)
|
|
471
421
|
} else {
|
|
472
|
-
|
|
422
|
+
cb = options
|
|
473
423
|
options = input
|
|
424
|
+
input = null
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (typeof options === 'function') {
|
|
428
|
+
cb = options
|
|
429
|
+
options = input || {}
|
|
430
|
+
} else {
|
|
431
|
+
options = Object.assign(input || {}, options)
|
|
474
432
|
}
|
|
475
433
|
|
|
434
|
+
let reqArgs = [options, cb]
|
|
435
|
+
|
|
436
|
+
|
|
476
437
|
// Don't pollute metrics and calls with NR connections
|
|
477
438
|
const internalOnly = options && options[NR_CONNECTION_PROP]
|
|
478
439
|
if (internalOnly) {
|
|
@@ -552,28 +513,19 @@ module.exports = function initialize(agent, http, moduleName) {
|
|
|
552
513
|
|
|
553
514
|
var agentProto = http && http.Agent && http.Agent.prototype
|
|
554
515
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
// TODO: Remove `SHOULD_WRAP_HTTPS` after deprecating Node <9.
|
|
562
|
-
if (SHOULD_WRAP_HTTPS || !IS_HTTPS) {
|
|
563
|
-
shimmer.wrapMethod(
|
|
564
|
-
http,
|
|
565
|
-
'http',
|
|
566
|
-
'request',
|
|
567
|
-
wrapRequest.bind(null, agent)
|
|
568
|
-
)
|
|
516
|
+
shimmer.wrapMethod(
|
|
517
|
+
http,
|
|
518
|
+
'http',
|
|
519
|
+
'request',
|
|
520
|
+
wrapRequest.bind(null, agent)
|
|
521
|
+
)
|
|
569
522
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
}
|
|
523
|
+
shimmer.wrapMethod(
|
|
524
|
+
http,
|
|
525
|
+
'http',
|
|
526
|
+
'get',
|
|
527
|
+
wrapRequest.bind(null, agent)
|
|
528
|
+
)
|
|
577
529
|
|
|
578
530
|
shimmer.wrapMethod(
|
|
579
531
|
agentProto,
|
package/lib/metrics/names.js
CHANGED
|
@@ -240,10 +240,13 @@ const SPAN_EVENTS = {
|
|
|
240
240
|
const INFINITE_TRACING = {
|
|
241
241
|
SEEN: SUPPORTABILITY.INFINITE_TRACING + '/Span/Seen',
|
|
242
242
|
SENT: SUPPORTABILITY.INFINITE_TRACING + '/Span/Sent',
|
|
243
|
+
DROPPED: SUPPORTABILITY.INFINITE_TRACING + '/Span/Dropped',
|
|
243
244
|
SPAN_RESPONSE_ERROR: SUPPORTABILITY.INFINITE_TRACING + '/Span/Response/Error',
|
|
244
245
|
SPAN_RESPONSE_GRPC_UNIMPLEMENTED: SUPPORTABILITY.INFINITE_TRACING + '/Span/gRPC/UNIMPLEMENTED',
|
|
245
246
|
SPAN_RESPONSE_GRPC_STATUS: SUPPORTABILITY.INFINITE_TRACING + '/Span/gRPC/%s',
|
|
246
|
-
|
|
247
|
+
QUEUE_CAPACITY: SUPPORTABILITY.INFINITE_TRACING + '/Span/QueueCapacity',
|
|
248
|
+
QUEUE_SIZE: SUPPORTABILITY.INFINITE_TRACING + '/Span/QueueSize',
|
|
249
|
+
DRAIN_DURATION: SUPPORTABILITY.INFINITE_TRACING + '/Drain/Duration',
|
|
247
250
|
}
|
|
248
251
|
|
|
249
252
|
module.exports = {
|
|
@@ -389,26 +389,8 @@ function setWebResponse(transaction, response) {
|
|
|
389
389
|
transaction.statusCode = response.statusCode
|
|
390
390
|
|
|
391
391
|
const responseCode = String(response.statusCode)
|
|
392
|
-
/*
|
|
393
|
-
TODO: remove with next major release
|
|
394
|
-
httpResponseCode attribute is deprecated
|
|
395
|
-
*/
|
|
396
|
-
transaction.trace.attributes.addAttribute(
|
|
397
|
-
ATTR_DEST.TRANS_COMMON,
|
|
398
|
-
'httpResponseCode',
|
|
399
|
-
responseCode
|
|
400
|
-
)
|
|
401
392
|
|
|
402
393
|
if (/^\d+$/.test(responseCode)) {
|
|
403
|
-
/*
|
|
404
|
-
TODO: remove with next major release
|
|
405
|
-
response.status attribute is deprecated
|
|
406
|
-
*/
|
|
407
|
-
transaction.trace.attributes.addAttribute(
|
|
408
|
-
ATTR_DEST.TRANS_COMMON,
|
|
409
|
-
'response.status',
|
|
410
|
-
responseCode)
|
|
411
|
-
|
|
412
394
|
transaction.trace.attributes.addAttribute(
|
|
413
395
|
ATTR_DEST.TRANS_COMMON,
|
|
414
396
|
'http.statusCode',
|
|
@@ -21,6 +21,9 @@ class SpanContext {
|
|
|
21
21
|
customAttributes || new PrioritizedAttributes(ATTRIBUTE_SCOPE, MAXIMUM_CUSTOM_ATTRIBUTES)
|
|
22
22
|
|
|
23
23
|
this.ATTRIBUTE_PRIORITY = ATTRIBUTE_PRIORITY
|
|
24
|
+
|
|
25
|
+
this.hasError = false
|
|
26
|
+
this.errorDetails = null
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
addIntrinsicAttribute(key, value) {
|
|
@@ -36,6 +39,21 @@ class SpanContext {
|
|
|
36
39
|
priority
|
|
37
40
|
)
|
|
38
41
|
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Set error details to be potentially be used to create span
|
|
45
|
+
* attributes. Attributes will be created unless the transaction
|
|
46
|
+
* ends with an ignored error status code.
|
|
47
|
+
*
|
|
48
|
+
* Last error wins.
|
|
49
|
+
*/
|
|
50
|
+
setError(details) {
|
|
51
|
+
this.hasError = true
|
|
52
|
+
|
|
53
|
+
// Error details will be used to create attributes unless the transaction ends
|
|
54
|
+
// with an ignored status code.
|
|
55
|
+
this.errorDetails = details
|
|
56
|
+
}
|
|
39
57
|
}
|
|
40
58
|
|
|
41
59
|
module.exports = SpanContext
|
package/lib/spans/span-event.js
CHANGED
|
@@ -84,9 +84,21 @@ class SpanEvent {
|
|
|
84
84
|
* @return {SpanEvent} The constructed event.
|
|
85
85
|
*/
|
|
86
86
|
static fromSegment(segment, parentId = null, isRoot = false) {
|
|
87
|
+
const spanContext = segment.getSpanContext()
|
|
88
|
+
|
|
89
|
+
// Since segments already hold span agent attributes and we want to leverage
|
|
90
|
+
// filtering, we add to the segment attributes prior to processing.
|
|
91
|
+
if (spanContext.hasError && !segment.transaction.hasIgnoredErrorStatusCode()) {
|
|
92
|
+
const details = spanContext.errorDetails
|
|
93
|
+
segment.addSpanAttribute('error.message', details.message)
|
|
94
|
+
segment.addSpanAttribute('error.class', details.type)
|
|
95
|
+
if (details.expected) {
|
|
96
|
+
segment.addSpanAttribute('error.expected', details.expected)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
87
100
|
const attributes = segment.attributes.get(DESTINATIONS.SPAN_EVENT)
|
|
88
101
|
|
|
89
|
-
const spanContext = segment.getSpanContext()
|
|
90
102
|
const customAttributes = spanContext.customAttributes.get(DESTINATIONS.SPAN_EVENT)
|
|
91
103
|
|
|
92
104
|
let span = null
|
|
@@ -98,7 +110,6 @@ class SpanEvent {
|
|
|
98
110
|
span = new SpanEvent(attributes, customAttributes)
|
|
99
111
|
}
|
|
100
112
|
|
|
101
|
-
|
|
102
113
|
for (const [key, value] of Object.entries(spanContext.intrinsicAttributes)) {
|
|
103
114
|
span.intrinsics[key] = value
|
|
104
115
|
}
|
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
const logger = require('../logger').child({component: 'span-streamer'})
|
|
9
9
|
const NAMES = require('../metrics/names').INFINITE_TRACING
|
|
10
10
|
|
|
11
|
+
const SPAN_DROP_MSG_INTERVAL_MS = 30000
|
|
11
12
|
const SPAN_DROP_MSG =
|
|
12
|
-
'Queue full, dropping spans.'
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
'Queue full, dropping spans. ' +
|
|
14
|
+
`Will not warn again for ${SPAN_DROP_MSG_INTERVAL_MS / 1000} seconds.`
|
|
15
15
|
|
|
16
16
|
class SpanStreamer {
|
|
17
17
|
constructor(license_key, connection, metrics, queue_size) {
|
|
@@ -47,21 +47,20 @@ class SpanStreamer {
|
|
|
47
47
|
|
|
48
48
|
// If not writeable (because of backpressure) queue the span
|
|
49
49
|
if (!this._writable) {
|
|
50
|
-
if (this.spans.length
|
|
50
|
+
if (this.spans.length < this.queue_size) {
|
|
51
51
|
this.spans.push(span)
|
|
52
52
|
return
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
// While this can be directionally calculated between seen/sent the
|
|
56
|
+
// queue makes that a bit more disconnected. This will be a bit more specific.
|
|
57
|
+
this._metrics.getOrCreateMetric(NAMES.DROPPED).incrementCallCount()
|
|
58
|
+
|
|
55
59
|
// If the queue is full drop the span
|
|
56
60
|
logger.infoOncePer(
|
|
57
|
-
// key for the OncePer
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
SPAN_DROP_INTERVAL * 1000,
|
|
61
|
-
// message
|
|
62
|
-
SPAN_DROP_MSG + ' Will not warn again for %s seconds.',
|
|
63
|
-
// variables to put in log message
|
|
64
|
-
SPAN_DROP_INTERVAL
|
|
61
|
+
'SPAN_DROP_MSG', // key for the OncePer
|
|
62
|
+
SPAN_DROP_MSG_INTERVAL_MS,
|
|
63
|
+
SPAN_DROP_MSG
|
|
65
64
|
)
|
|
66
65
|
|
|
67
66
|
return
|
|
@@ -121,14 +120,21 @@ class SpanStreamer {
|
|
|
121
120
|
}
|
|
122
121
|
|
|
123
122
|
sendQueue() {
|
|
123
|
+
logger.trace('Sending spans from queue.')
|
|
124
|
+
|
|
124
125
|
// Continue sending the spans that were in the queue. _writable is checked
|
|
125
126
|
// so that if a send fails while clearing the queue, this drain handler can
|
|
126
127
|
// finish, and the drain handler setup on the failed send will then attempt
|
|
127
128
|
// to clear the queue
|
|
128
129
|
while (this.spans.length > 0 && this._writable) {
|
|
129
130
|
const nextObject = this.spans.shift()
|
|
130
|
-
this.send(nextObject)
|
|
131
|
+
this.send(nextObject.toStreamingFormat())
|
|
131
132
|
}
|
|
133
|
+
|
|
134
|
+
logger.trace(
|
|
135
|
+
'Finished sending spans from queue. Items left in queue: %s',
|
|
136
|
+
this.spans.length
|
|
137
|
+
)
|
|
132
138
|
}
|
|
133
139
|
|
|
134
140
|
connect(agent_run_id, requestHeadersMap) {
|
|
@@ -144,6 +150,11 @@ class SpanStreamer {
|
|
|
144
150
|
disconnect() {
|
|
145
151
|
this.connection.disconnect()
|
|
146
152
|
}
|
|
153
|
+
|
|
154
|
+
createMetrics() {
|
|
155
|
+
this._metrics.getOrCreateMetric(NAMES.QUEUE_CAPACITY).recordValue(this.queue_size)
|
|
156
|
+
this._metrics.getOrCreateMetric(NAMES.QUEUE_SIZE).recordValue(this.spans.length)
|
|
157
|
+
}
|
|
147
158
|
}
|
|
148
159
|
|
|
149
160
|
module.exports = SpanStreamer
|
|
@@ -102,9 +102,21 @@ class StreamingSpanEvent {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
static fromSegment(segment, parentId = null, isRoot = false) {
|
|
105
|
+
const spanContext = segment.getSpanContext()
|
|
106
|
+
|
|
107
|
+
// Since segments already hold span agent attributes and we want to leverage
|
|
108
|
+
// filtering, we add to the segment attributes prior to processing.
|
|
109
|
+
if (spanContext.hasError && !segment.transaction.hasIgnoredErrorStatusCode()) {
|
|
110
|
+
const details = spanContext.errorDetails
|
|
111
|
+
segment.addSpanAttribute('error.message', details.message)
|
|
112
|
+
segment.addSpanAttribute('error.class', details.type)
|
|
113
|
+
if (details.expected) {
|
|
114
|
+
segment.addSpanAttribute('error.expected', details.expected)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
105
118
|
const agentAttributes = segment.attributes.get(DESTINATIONS.SPAN_EVENT)
|
|
106
119
|
|
|
107
|
-
const spanContext = segment.getSpanContext()
|
|
108
120
|
const customAttributes = spanContext.customAttributes.get(DESTINATIONS.SPAN_EVENT)
|
|
109
121
|
|
|
110
122
|
const transaction = segment.transaction
|
|
@@ -13,7 +13,7 @@ const DT_VERSION_MINOR = 1
|
|
|
13
13
|
module.exports = class DistributedTracePayload {
|
|
14
14
|
/**
|
|
15
15
|
* The class reponsible for producing distributed trace payloads.
|
|
16
|
-
* Created by calling {@link TransactionHandle#
|
|
16
|
+
* Created by calling {@link TransactionHandle#_createDistributedTracePayload}.
|
|
17
17
|
*
|
|
18
18
|
* @constructor
|
|
19
19
|
*/
|
|
@@ -5,9 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
const util = require('util')
|
|
9
8
|
const logger = require('../logger').child({component: 'transactionHandle'})
|
|
10
|
-
const DistributedTracePayloadStub = require('./dt-payload').Stub
|
|
11
9
|
|
|
12
10
|
const NAMES = require('../../lib/metrics/names')
|
|
13
11
|
|
|
@@ -61,7 +59,6 @@ class TransactionHandle {
|
|
|
61
59
|
*/
|
|
62
60
|
acceptDistributedTraceHeaders(transportType, headers) {
|
|
63
61
|
incrementApiSupportMetric(this._metrics, 'acceptDistributedTraceHeaders')
|
|
64
|
-
|
|
65
62
|
return this._transaction.acceptDistributedTraceHeaders(transportType, headers)
|
|
66
63
|
}
|
|
67
64
|
|
|
@@ -71,48 +68,10 @@ class TransactionHandle {
|
|
|
71
68
|
*/
|
|
72
69
|
insertDistributedTraceHeaders(headers) {
|
|
73
70
|
incrementApiSupportMetric(this._metrics, 'insertDistributedTraceHeaders')
|
|
74
|
-
|
|
75
71
|
return this._transaction.insertDistributedTraceHeaders(headers)
|
|
76
72
|
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
*
|
|
80
|
-
* Proxy method for Transaction#createDistrubtedTracePayload.
|
|
81
|
-
*
|
|
82
|
-
* @returns {DistributedTracePayload} The created payload object.
|
|
83
|
-
*
|
|
84
|
-
*/
|
|
85
|
-
createDistributedTracePayload() {
|
|
86
|
-
return this._transaction.createDistributedTracePayload()
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
*
|
|
91
|
-
* Proxy method for Transaction#acceptDistributedTracePayload
|
|
92
|
-
*
|
|
93
|
-
* @param {String} The payload to accept as the parent to the current trace
|
|
94
|
-
*
|
|
95
|
-
*/
|
|
96
|
-
acceptDistributedTracePayload(payload) {
|
|
97
|
-
return this._transaction.acceptDistributedTracePayload(payload)
|
|
98
|
-
}
|
|
99
73
|
}
|
|
100
74
|
|
|
101
|
-
// TODO: Fully remove functions in future Major release. v7.0.0?
|
|
102
|
-
TransactionHandle.prototype.acceptDistributedTracePayload = util.deprecate(
|
|
103
|
-
TransactionHandle.prototype.acceptDistributedTracePayload,
|
|
104
|
-
'TransactionHandle#acceptDistributedTracePayload has been deprecated! ' +
|
|
105
|
-
'Please use TransactionHandle#acceptDistributedTraceHeaders ' +
|
|
106
|
-
'which supports multiple distributed trace formats.'
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
TransactionHandle.prototype.createDistributedTracePayload = util.deprecate(
|
|
110
|
-
TransactionHandle.prototype.createDistributedTracePayload,
|
|
111
|
-
'TransactionHandle#createDistributedTracePayload has been deprecated! ' +
|
|
112
|
-
'Please use TransactionHandle#insertDistributedTraceHeaders ' +
|
|
113
|
-
'which supports multiple distributed trace formats.'
|
|
114
|
-
)
|
|
115
|
-
|
|
116
75
|
module.exports = TransactionHandle
|
|
117
76
|
|
|
118
77
|
function incrementApiSupportMetric(metrics, functionName) {
|
|
@@ -147,19 +106,6 @@ module.exports.Stub = class TransactionHandleStub {
|
|
|
147
106
|
logger.debug("No transaction found when calling Transaction.isSampled")
|
|
148
107
|
}
|
|
149
108
|
|
|
150
|
-
createDistributedTracePayload() {
|
|
151
|
-
logger.debug(
|
|
152
|
-
"No transaction found when calling Transaction.createDistributedTracePayload"
|
|
153
|
-
)
|
|
154
|
-
return new DistributedTracePayloadStub()
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
acceptDistributedTracePayload() {
|
|
158
|
-
logger.debug(
|
|
159
|
-
"No transaction found when calling Transaction.acceptDistributedTracePayload"
|
|
160
|
-
)
|
|
161
|
-
}
|
|
162
|
-
|
|
163
109
|
acceptDistributedTraceHeaders() {
|
|
164
110
|
logger.debug("No transaction found when calling Transaction.acceptDistributedTraceHeaders")
|
|
165
111
|
}
|
package/lib/transaction/index.js
CHANGED
|
@@ -679,7 +679,6 @@ Transaction.prototype.measure = function measure(name, scope, duration, exclusiv
|
|
|
679
679
|
Transaction.prototype._setApdex = function _setApdex(name, duration, keyApdexInMillis) {
|
|
680
680
|
var apdexStats = this.metrics.getOrCreateApdexMetric(name, null, keyApdexInMillis)
|
|
681
681
|
|
|
682
|
-
|
|
683
682
|
// if we have an error-like status code, and all the errors are
|
|
684
683
|
// expected, we know the status code was caused by an expected
|
|
685
684
|
// error, so we will not report "frustrating". Otherwise, we
|
|
@@ -747,19 +746,13 @@ function _linkExceptionToSegment(exception) {
|
|
|
747
746
|
return
|
|
748
747
|
}
|
|
749
748
|
|
|
750
|
-
const
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
const isExpected =
|
|
758
|
-
errorHelper.isExpectedErrorClass(config, details.type) ||
|
|
759
|
-
errorHelper.isExpectedErrorMessage(config, details.type, details.message)
|
|
760
|
-
|
|
761
|
-
if (isExpected) {
|
|
762
|
-
segment.addSpanAttribute('error.expected', isExpected)
|
|
749
|
+
const spanContext = segment.getSpanContext()
|
|
750
|
+
if (spanContext) {
|
|
751
|
+
// Exception attributes will be added to span unless transaction
|
|
752
|
+
// status code has been ignored. Last error wins.
|
|
753
|
+
const config = this.agent.config
|
|
754
|
+
const details = exception.getErrorDetails(config)
|
|
755
|
+
spanContext.setError(details)
|
|
763
756
|
}
|
|
764
757
|
|
|
765
758
|
// Add the span/segment ID to the exception as agent attributes
|
|
@@ -793,6 +786,14 @@ function _addUserError(exception) {
|
|
|
793
786
|
this.userErrors.push(exception)
|
|
794
787
|
}
|
|
795
788
|
|
|
789
|
+
/**
|
|
790
|
+
* Returns if the transaction's current status code is errored
|
|
791
|
+
* but considered ignored via the config.
|
|
792
|
+
*/
|
|
793
|
+
Transaction.prototype.hasIgnoredErrorStatusCode = function _hasIgnoredErrorStatusCode() {
|
|
794
|
+
return urltils.isIgnoredError(this.agent.config, this.statusCode)
|
|
795
|
+
}
|
|
796
|
+
|
|
796
797
|
/**
|
|
797
798
|
* Returns true if an error happened during the transaction or if the transaction itself is
|
|
798
799
|
* considered to be an error.
|
|
@@ -885,19 +886,14 @@ function acceptDistributedTraceHeaders(transportType, headers) {
|
|
|
885
886
|
|
|
886
887
|
if (traceparent) {
|
|
887
888
|
logger.trace('Accepting trace context DT payload for transaction %s', this.id)
|
|
888
|
-
|
|
889
889
|
// assumes header keys already lowercase
|
|
890
890
|
const tracestate = headers[TRACE_CONTEXT_STATE_HEADER]
|
|
891
|
-
|
|
892
891
|
this.acceptTraceContextPayload(traceparent, tracestate, transport)
|
|
893
|
-
} else {
|
|
892
|
+
} else if (NEWRELIC_TRACE_HEADER in headers) {
|
|
893
|
+
logger.trace('Accepting newrelic DT payload for transaction %s', this.id)
|
|
894
894
|
// assumes header keys already lowercase
|
|
895
895
|
const payload = headers[NEWRELIC_TRACE_HEADER]
|
|
896
|
-
|
|
897
|
-
logger.trace('Accepting newrelic DT payload for transaction %s', this.id)
|
|
898
|
-
|
|
899
|
-
this.acceptDistributedTracePayload(payload, transport)
|
|
900
|
-
}
|
|
896
|
+
this._acceptDistributedTracePayload(payload, transport)
|
|
901
897
|
}
|
|
902
898
|
}
|
|
903
899
|
|
|
@@ -928,7 +924,7 @@ function insertDistributedTraceHeaders(headers) {
|
|
|
928
924
|
}
|
|
929
925
|
|
|
930
926
|
try {
|
|
931
|
-
const newrelicFormatData = this.
|
|
927
|
+
const newrelicFormatData = this._createDistributedTracePayload().httpSafe()
|
|
932
928
|
headers[NEWRELIC_TRACE_HEADER] = newrelicFormatData
|
|
933
929
|
logger.trace('Added outbound request distributed tracing headers in transaction %s', this.id)
|
|
934
930
|
} catch (error) {
|
|
@@ -992,8 +988,8 @@ function acceptTraceContextPayload(traceparent, tracestate, transport) {
|
|
|
992
988
|
* @param {object} payload - The distributed trace payload to accept.
|
|
993
989
|
* @param {string} [transport='Unknown'] - The transport type that delivered the payload.
|
|
994
990
|
*/
|
|
995
|
-
Transaction.prototype.
|
|
996
|
-
function
|
|
991
|
+
Transaction.prototype._acceptDistributedTracePayload = _acceptDistributedTracePayload
|
|
992
|
+
function _acceptDistributedTracePayload(payload, transport) {
|
|
997
993
|
if (!payload) {
|
|
998
994
|
this.agent.recordSupportability('DistributedTrace/AcceptPayload/Ignored/Null')
|
|
999
995
|
return
|
|
@@ -1088,11 +1084,6 @@ function acceptDistributedTracePayload(payload, transport) {
|
|
|
1088
1084
|
return
|
|
1089
1085
|
}
|
|
1090
1086
|
|
|
1091
|
-
// TODO: This should be removable / covered by acceptDistributedTraceHeaders
|
|
1092
|
-
// once the Transaction#acceptDistributedTracePayload API that directly invokes
|
|
1093
|
-
// this acceptDistributedTracePayload is fully removed in a future Major version.
|
|
1094
|
-
transport = TRANSPORT_TYPES_SET[transport] ? transport : TRANSPORT_TYPES.UNKNOWN
|
|
1095
|
-
|
|
1096
1087
|
this.parentType = data.ty
|
|
1097
1088
|
this.parentApp = data.ap
|
|
1098
1089
|
this.parentAcct = data.ac
|
|
@@ -1162,9 +1153,9 @@ Transaction.prototype._getParsedPayload = function _getParsedPayload(payload) {
|
|
|
1162
1153
|
/**
|
|
1163
1154
|
* Creates a distributed trace payload.
|
|
1164
1155
|
*/
|
|
1165
|
-
Transaction.prototype.
|
|
1156
|
+
Transaction.prototype._createDistributedTracePayload = _createDistributedTracePayload
|
|
1166
1157
|
|
|
1167
|
-
function
|
|
1158
|
+
function _createDistributedTracePayload() {
|
|
1168
1159
|
const config = this.agent.config
|
|
1169
1160
|
const accountId = config.account_id
|
|
1170
1161
|
const appId = config.primary_application_id
|
|
@@ -1184,11 +1175,6 @@ function createDistributedTracePayload() {
|
|
|
1184
1175
|
return new DTPayloadStub()
|
|
1185
1176
|
}
|
|
1186
1177
|
|
|
1187
|
-
// TODO: This should be removable / covered by insertDistributedTraceHeaders
|
|
1188
|
-
// once the Transaction#createDistributedTracePayload API that directly invokes
|
|
1189
|
-
// this createDistributedTracePayload is fully removed in a future Major version.
|
|
1190
|
-
this._calculatePriority()
|
|
1191
|
-
|
|
1192
1178
|
const currSegment = this.agent.tracer.getSegment()
|
|
1193
1179
|
const data = {
|
|
1194
1180
|
ty: 'App',
|
|
@@ -63,7 +63,14 @@ class TraceContext {
|
|
|
63
63
|
// If no segment/span is in context, generate one so we can have a valid traceparent
|
|
64
64
|
const segment = this.transaction.agent.tracer.getSegment()
|
|
65
65
|
let parentId = segment && segment.id
|
|
66
|
-
|
|
66
|
+
if (!parentId) {
|
|
67
|
+
parentId = hashes.makeId(16)
|
|
68
|
+
logger.debug(
|
|
69
|
+
'No segment/span in context. Generated new traceparent parentId (%s) for traceId (%s)',
|
|
70
|
+
parentId,
|
|
71
|
+
traceId
|
|
72
|
+
)
|
|
73
|
+
}
|
|
67
74
|
|
|
68
75
|
return `${W3C_TRACEPARENT_VERSION}-${traceId}-${parentId}-${this.createFlagsHex()}`
|
|
69
76
|
}
|
|
@@ -103,7 +110,11 @@ class TraceContext {
|
|
|
103
110
|
const segment = this.transaction.agent.tracer.getSegment()
|
|
104
111
|
if (segment) {
|
|
105
112
|
spanId = segment.id
|
|
113
|
+
} else {
|
|
114
|
+
logger.debug('No segment/span in context. Not sending spanId in tracestate.')
|
|
106
115
|
}
|
|
116
|
+
} else {
|
|
117
|
+
logger.trace('Span events disabled. Not sending spanId in tracestate.')
|
|
107
118
|
}
|
|
108
119
|
|
|
109
120
|
const transactionId = config.transaction_events.enabled ? this.transaction.id : ''
|
|
@@ -130,11 +141,15 @@ class TraceContext {
|
|
|
130
141
|
return
|
|
131
142
|
}
|
|
132
143
|
|
|
133
|
-
|
|
144
|
+
const traceParent = this.createTraceparent()
|
|
145
|
+
headers[TRACE_CONTEXT_PARENT_HEADER] = traceParent
|
|
146
|
+
|
|
147
|
+
logger.trace('traceparent added with %s', traceParent)
|
|
134
148
|
|
|
135
149
|
const tracestate = this.createTracestate()
|
|
136
150
|
if (tracestate) {
|
|
137
151
|
headers[TRACE_CONTEXT_STATE_HEADER] = tracestate
|
|
152
|
+
logger.trace('tracestate added with %s', tracestate)
|
|
138
153
|
}
|
|
139
154
|
|
|
140
155
|
this.transaction.agent.recordSupportability('TraceContext/Create/Success')
|