newrelic 9.5.0 → 9.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 +14 -0
- package/api.js +2 -0
- package/bin/test-naming-rules.js +1 -1
- package/esm-loader.mjs +1 -3
- package/index.js +6 -5
- package/lib/adaptive-sampler.js +1 -2
- package/lib/agent.js +2 -0
- package/lib/aggregators/event-aggregator.js +2 -2
- package/lib/attributes.js +2 -4
- package/lib/collector/api.js +20 -12
- package/lib/collector/facts.js +1 -3
- package/lib/collector/parse-response.js +3 -1
- package/lib/collector/remote-method.js +10 -10
- package/lib/config/attribute-filter.js +14 -16
- package/lib/config/default.js +544 -286
- package/lib/config/formatters.js +108 -0
- package/lib/config/harvest-config-validator.js +3 -5
- package/lib/config/index.js +74 -93
- package/lib/environment.js +6 -5
- package/lib/errors/error-collector.js +6 -3
- package/lib/errors/helper.js +10 -18
- package/lib/errors/index.js +12 -6
- package/lib/grpc/connection.js +12 -5
- package/lib/header-attributes.js +4 -2
- package/lib/header-processing.js +2 -2
- package/lib/instrumentation/@hapi/hapi.js +231 -1
- package/lib/instrumentation/{vision.js → @hapi/vision.js} +0 -0
- package/lib/instrumentation/@node-redis/client.js +2 -0
- package/lib/instrumentation/amqplib.js +2 -0
- package/lib/instrumentation/core/async_hooks.js +3 -4
- package/lib/instrumentation/core/globals.js +12 -10
- package/lib/instrumentation/core/http-outbound.js +17 -17
- package/lib/instrumentation/core/http.js +16 -27
- package/lib/instrumentation/core/timers.js +5 -1
- package/lib/instrumentation/fastify.js +1 -3
- package/lib/instrumentation/grpc-js/grpc.js +14 -3
- package/lib/instrumentation/memcached.js +5 -0
- package/lib/instrumentation/mongodb/common.js +3 -0
- package/lib/instrumentation/mongodb/v2-mongo.js +6 -3
- package/lib/instrumentation/mongodb.js +1 -1
- package/lib/instrumentation/mysql/mysql.js +6 -5
- package/lib/instrumentation/nr-winston-transport.js +3 -4
- package/lib/instrumentation/promise.js +22 -18
- package/lib/instrumentation/redis.js +2 -0
- package/lib/instrumentation/undici.js +12 -15
- package/lib/instrumentations.js +1 -1
- package/lib/metrics/mapper.js +2 -3
- package/lib/metrics/metric-aggregator.js +1 -3
- package/lib/metrics/names.js +19 -15
- package/lib/metrics/normalizer/rule.js +6 -7
- package/lib/metrics/normalizer/tx_segment.js +3 -2
- package/lib/metrics/normalizer.js +5 -3
- package/lib/parse-proc-cpuinfo.js +11 -6
- package/lib/serverless/api-gateway.js +3 -4
- package/lib/serverless/aws-lambda.js +3 -3
- package/lib/shim/conglomerate-shim.js +2 -3
- package/lib/shim/constants.js +1 -16
- package/lib/shim/datastore-shim.js +24 -105
- package/lib/shim/index.js +7 -0
- package/lib/shim/message-shim.js +2 -0
- package/lib/shim/promise-shim.js +66 -59
- package/lib/shim/shim.js +44 -89
- package/lib/shim/transaction-shim.js +1 -1
- package/lib/shim/webframework-shim.js +4 -8
- package/lib/shimmer.js +29 -23
- package/lib/spans/map-to-streaming-type.js +0 -2
- package/lib/spans/span-context.js +2 -0
- package/lib/spans/span-event-aggregator.js +2 -2
- package/lib/spans/span-event.js +2 -2
- package/lib/spans/span-streamer.js +4 -0
- package/lib/spans/streaming-span-event-aggregator.js +2 -4
- package/lib/spans/streaming-span-event.js +3 -2
- package/lib/symbols.js +26 -0
- package/lib/system-info.js +4 -7
- package/lib/timer.js +8 -6
- package/lib/transaction/dt-payload.js +4 -3
- package/lib/transaction/handle.js +12 -2
- package/lib/transaction/index.js +19 -18
- package/lib/transaction/name-state.js +17 -2
- package/lib/transaction/trace/aggregator.js +4 -12
- package/lib/transaction/trace/index.js +7 -5
- package/lib/transaction/trace/segment.js +6 -11
- package/lib/transaction/tracecontext.js +10 -6
- package/lib/transaction/tracer/index.js +35 -43
- package/lib/transaction/transaction-event-aggregator.js +1 -3
- package/lib/util/arity.js +4 -9
- package/lib/util/attribute-types.js +1 -2
- package/lib/util/byte-limit.js +1 -3
- package/lib/util/cat.js +16 -13
- package/lib/util/codec.js +0 -2
- package/lib/util/copy.js +1 -2
- package/lib/util/deep-equal.js +7 -0
- package/lib/util/flatten.js +4 -6
- package/lib/util/hashes.js +1 -3
- package/lib/util/process-version.js +2 -3
- package/lib/util/properties.js +2 -51
- package/lib/util/stream-sink.js +2 -0
- package/lib/util/urltils.js +4 -10
- package/newrelic.js +1 -1
- package/package.json +2 -1
- package/lib/config/env.js +0 -294
- package/lib/instrumentation/hapi/hapi.js +0 -207
- package/lib/instrumentation/hapi/shared.js +0 -28
- package/lib/instrumentation/hapi.js +0 -254
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
+
/* eslint sonarjs/cognitive-complexity: ["error", 69] -- TODO: https://issues.newrelic.com/browse/NEWRELIC-5252 */
|
|
9
|
+
|
|
8
10
|
const genericRecorder = require('../metrics/recorders/generic')
|
|
9
11
|
const logger = require('../logger.js').child({ component: 'WebFrameworkShim' })
|
|
10
12
|
const metrics = require('../metrics/names')
|
|
@@ -13,6 +15,7 @@ const Shim = require('./shim')
|
|
|
13
15
|
const specs = require('./specs')
|
|
14
16
|
const urltils = require('../util/urltils')
|
|
15
17
|
const util = require('util')
|
|
18
|
+
const symbols = require('../symbols')
|
|
16
19
|
|
|
17
20
|
/**
|
|
18
21
|
* An enumeration of well-known web frameworks so that new instrumentations can
|
|
@@ -54,13 +57,6 @@ const MIDDLEWARE_TYPE_NAMES = {
|
|
|
54
57
|
ROUTER: 'ROUTER'
|
|
55
58
|
}
|
|
56
59
|
|
|
57
|
-
/**
|
|
58
|
-
* Name of the key used to store transaction information on `req` and `res`.
|
|
59
|
-
*
|
|
60
|
-
* @private
|
|
61
|
-
*/
|
|
62
|
-
const TRANSACTION_INFO_KEY = '__NR_transactionInfo'
|
|
63
|
-
|
|
64
60
|
/**
|
|
65
61
|
* Constructs a shim associated with the given agent instance, specialized for
|
|
66
62
|
* instrumenting web frameworks.
|
|
@@ -1036,7 +1032,7 @@ function _makeNextBinder(nextDetails, txInfo) {
|
|
|
1036
1032
|
*/
|
|
1037
1033
|
function _getTransactionInfo(shim, req) {
|
|
1038
1034
|
try {
|
|
1039
|
-
return req[
|
|
1035
|
+
return req[symbols.transactionInfo] || null
|
|
1040
1036
|
} catch (e) {
|
|
1041
1037
|
shim.logger.debug(e, 'Failed to fetch transaction info from req')
|
|
1042
1038
|
return null
|
package/lib/shimmer.js
CHANGED
|
@@ -14,6 +14,7 @@ const properties = require('./util/properties')
|
|
|
14
14
|
const shims = require('./shim')
|
|
15
15
|
|
|
16
16
|
const NAMES = require('./metrics/names')
|
|
17
|
+
const symbols = require('./symbols')
|
|
17
18
|
|
|
18
19
|
const MODULE_TYPE = shims.constants.MODULE_TYPE
|
|
19
20
|
|
|
@@ -97,7 +98,7 @@ const shimmer = (module.exports = {
|
|
|
97
98
|
* @returns {bool} True if `fn` exists and has an attached original, else false.
|
|
98
99
|
*/
|
|
99
100
|
isWrapped: function isWrapped(fn) {
|
|
100
|
-
return !!(fn && fn.
|
|
101
|
+
return !!(fn && fn[symbols.original])
|
|
101
102
|
},
|
|
102
103
|
|
|
103
104
|
/**
|
|
@@ -118,7 +119,8 @@ const shimmer = (module.exports = {
|
|
|
118
119
|
*/
|
|
119
120
|
wrapMethod: function wrapMethod(nodule, noduleName, methods, wrapper) {
|
|
120
121
|
if (!methods) {
|
|
121
|
-
|
|
122
|
+
logger.warn(new Error(), 'Must include a method name to wrap. Called from:')
|
|
123
|
+
return
|
|
122
124
|
}
|
|
123
125
|
|
|
124
126
|
if (!noduleName) {
|
|
@@ -132,29 +134,33 @@ const shimmer = (module.exports = {
|
|
|
132
134
|
const fqmn = noduleName + '.' + method
|
|
133
135
|
|
|
134
136
|
if (!nodule) {
|
|
135
|
-
|
|
137
|
+
logger.debug("Can't wrap %s from nonexistent object.", fqmn)
|
|
138
|
+
return
|
|
136
139
|
}
|
|
137
140
|
|
|
138
141
|
if (!wrapper) {
|
|
139
|
-
|
|
142
|
+
logger.debug("Can't wrap %s without a wrapper generator.", fqmn)
|
|
143
|
+
return
|
|
140
144
|
}
|
|
141
145
|
|
|
142
146
|
const original = nodule[method]
|
|
143
147
|
|
|
144
148
|
if (!original) {
|
|
145
|
-
|
|
149
|
+
logger.trace('%s not defined, so not wrapping.', fqmn)
|
|
150
|
+
return
|
|
146
151
|
}
|
|
147
|
-
if (original.
|
|
148
|
-
|
|
152
|
+
if (original[symbols.unwrap]) {
|
|
153
|
+
logger.debug('%s already wrapped by agent.', fqmn)
|
|
154
|
+
return
|
|
149
155
|
}
|
|
150
156
|
|
|
151
157
|
const wrapped = wrapper(original, method)
|
|
152
158
|
Object.keys(original).forEach((key) => {
|
|
153
159
|
wrapped[key] = original[key]
|
|
154
160
|
})
|
|
155
|
-
wrapped.
|
|
161
|
+
wrapped[symbols.original] = original
|
|
156
162
|
// eslint-disable-next-line camelcase
|
|
157
|
-
wrapped.
|
|
163
|
+
wrapped[symbols.unwrap] = function unwrap() {
|
|
158
164
|
nodule[method] = original
|
|
159
165
|
logger.trace('Removed instrumentation from %s.', fqmn)
|
|
160
166
|
}
|
|
@@ -221,7 +227,7 @@ const shimmer = (module.exports = {
|
|
|
221
227
|
|
|
222
228
|
if (shimmer.debug) {
|
|
223
229
|
instrumented.push({
|
|
224
|
-
|
|
230
|
+
[symbols.unwrap]: function unwrapDeprecated() {
|
|
225
231
|
delete nodule[property]
|
|
226
232
|
nodule[property] = original
|
|
227
233
|
}
|
|
@@ -259,16 +265,16 @@ const shimmer = (module.exports = {
|
|
|
259
265
|
if (!wrapped) {
|
|
260
266
|
return logger.debug('%s not defined, so not unwrapping.', fqmn)
|
|
261
267
|
}
|
|
262
|
-
if (!wrapped.
|
|
268
|
+
if (!wrapped[symbols.unwrap]) {
|
|
263
269
|
return logger.debug("%s isn't unwrappable.", fqmn)
|
|
264
270
|
}
|
|
265
271
|
|
|
266
|
-
wrapped.
|
|
272
|
+
wrapped[symbols.unwrap]()
|
|
267
273
|
},
|
|
268
274
|
|
|
269
275
|
unwrapAll: function unwrapAll() {
|
|
270
276
|
instrumented.forEach((wrapper) => {
|
|
271
|
-
wrapper.
|
|
277
|
+
wrapper[symbols.unwrap]()
|
|
272
278
|
})
|
|
273
279
|
instrumented = []
|
|
274
280
|
},
|
|
@@ -472,7 +478,7 @@ const shimmer = (module.exports = {
|
|
|
472
478
|
// This is to not break the public API
|
|
473
479
|
// previously it would just call instrumentation
|
|
474
480
|
// and not check the result
|
|
475
|
-
return returnModule ? result : !!result.
|
|
481
|
+
return returnModule ? result : !!result[symbols.instrumented]
|
|
476
482
|
}
|
|
477
483
|
})
|
|
478
484
|
|
|
@@ -481,13 +487,13 @@ function applyDebugState(shim, nodule) {
|
|
|
481
487
|
shim.enableDebug()
|
|
482
488
|
instrumented.push(shim)
|
|
483
489
|
instrumented.push({
|
|
484
|
-
|
|
485
|
-
delete nodule.
|
|
486
|
-
delete nodule.
|
|
487
|
-
delete nodule.
|
|
490
|
+
[symbols.unwrap]: function unwrapNodule() {
|
|
491
|
+
delete nodule[symbols.instrumentedErrored]
|
|
492
|
+
delete nodule[symbols.instrumented]
|
|
493
|
+
delete nodule[symbols.shim]
|
|
488
494
|
}
|
|
489
495
|
})
|
|
490
|
-
nodule.
|
|
496
|
+
nodule[symbols.shim] = shim
|
|
491
497
|
}
|
|
492
498
|
}
|
|
493
499
|
|
|
@@ -504,8 +510,8 @@ function applyDebugState(shim, nodule) {
|
|
|
504
510
|
function instrumentPostLoad(agent, nodule, moduleName, resolvedName) {
|
|
505
511
|
const instrumentation = shimmer.registeredInstrumentations[moduleName]
|
|
506
512
|
if (
|
|
507
|
-
properties.hasOwn(nodule,
|
|
508
|
-
properties.hasOwn(nodule,
|
|
513
|
+
properties.hasOwn(nodule, symbols.instrumented) ||
|
|
514
|
+
properties.hasOwn(nodule, symbols.instrumentedErrored)
|
|
509
515
|
) {
|
|
510
516
|
logger.trace(
|
|
511
517
|
'Already instrumented or failed to instrument %s, skipping redundant instrumentation',
|
|
@@ -527,10 +533,10 @@ function instrumentPostLoad(agent, nodule, moduleName, resolvedName) {
|
|
|
527
533
|
try {
|
|
528
534
|
if (instrumentation.onRequire(shim, nodule, moduleName) !== false) {
|
|
529
535
|
nodule = shim.getExport(nodule)
|
|
530
|
-
nodule.
|
|
536
|
+
nodule[symbols.instrumented] = true
|
|
531
537
|
}
|
|
532
538
|
} catch (instrumentationError) {
|
|
533
|
-
nodule.
|
|
539
|
+
nodule[symbols.instrumentedErrored] = true
|
|
534
540
|
if (instrumentation.onError) {
|
|
535
541
|
try {
|
|
536
542
|
instrumentation.onError(instrumentationError)
|
|
@@ -63,8 +63,8 @@ class SpanEventAggregator extends EventAggregator {
|
|
|
63
63
|
*
|
|
64
64
|
* @param {TraceSegment} segment - The segment to add.
|
|
65
65
|
* @param {string} [parentId=null] - The GUID of the parent span.
|
|
66
|
-
*
|
|
67
|
-
* @
|
|
66
|
+
* @param isRoot
|
|
67
|
+
* @returns {boolean} True if the segment was added, or false if it was discarded.
|
|
68
68
|
*/
|
|
69
69
|
addSegment(segment, parentId, isRoot) {
|
|
70
70
|
// Check if the priority would be accepted before creating the event object.
|
package/lib/spans/span-event.js
CHANGED
|
@@ -83,8 +83,8 @@ class SpanEvent {
|
|
|
83
83
|
*
|
|
84
84
|
* @param {TraceSegment} segment - The segment to turn into a span event.
|
|
85
85
|
* @param {?string} [parentId=null] - The ID of the segment's parent.
|
|
86
|
-
*
|
|
87
|
-
* @
|
|
86
|
+
* @param isRoot
|
|
87
|
+
* @returns {SpanEvent} The constructed event.
|
|
88
88
|
*/
|
|
89
89
|
static fromSegment(segment, parentId = null, isRoot = false) {
|
|
90
90
|
const spanContext = segment.getSpanContext()
|
|
@@ -83,6 +83,8 @@ class SpanStreamer {
|
|
|
83
83
|
* Sends the span over the stream. Spans are only sent here if the stream is
|
|
84
84
|
* in a writable state. If the stream becomes unwritable after sending the
|
|
85
85
|
* span, a drain event handler is setup to continue writing when possible.
|
|
86
|
+
*
|
|
87
|
+
* @param span
|
|
86
88
|
*/
|
|
87
89
|
send(span) {
|
|
88
90
|
// false indicates the stream has reached the highWaterMark
|
|
@@ -104,6 +106,8 @@ class SpanStreamer {
|
|
|
104
106
|
* initially blocked, used to time how long the stream was blocked. If this
|
|
105
107
|
* is not defined, it is assumed this is being called after a reconnect,
|
|
106
108
|
* and the metric is not used.
|
|
109
|
+
*
|
|
110
|
+
* @param waitDrainStart
|
|
107
111
|
*/
|
|
108
112
|
drain(waitDrainStart) {
|
|
109
113
|
// Metric can be used to see how frequently completing drains as well as
|
|
@@ -60,8 +60,6 @@ class StreamingSpanEventAggregator extends Aggregator {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
this.emit(`finished ${this.method} data send.`)
|
|
63
|
-
|
|
64
|
-
return
|
|
65
63
|
}
|
|
66
64
|
|
|
67
65
|
/**
|
|
@@ -78,8 +76,8 @@ class StreamingSpanEventAggregator extends Aggregator {
|
|
|
78
76
|
*
|
|
79
77
|
* @param {TraceSegment} segment - The segment to add.
|
|
80
78
|
* @param {string} [parentId=null] - The GUID of the parent span.
|
|
81
|
-
*
|
|
82
|
-
* @
|
|
79
|
+
* @param isRoot
|
|
80
|
+
* @returns {bool} True if the segment was added, or false if it was discarded.
|
|
83
81
|
*/
|
|
84
82
|
addSegment(segment, parentId, isRoot) {
|
|
85
83
|
if (!this.started) {
|
|
@@ -61,6 +61,7 @@ class StreamingSpanEvent {
|
|
|
61
61
|
|
|
62
62
|
/**
|
|
63
63
|
* Add a key/value pair to the Span's custom/user attributes collection.
|
|
64
|
+
*
|
|
64
65
|
* @param {string} key Name of the attribute to be stored.
|
|
65
66
|
* @param {string|boolean|number} value Value of the attribute to be stored.
|
|
66
67
|
* @param {boolean} [truncateExempt=false] Set to true if attribute should not be truncated.
|
|
@@ -75,6 +76,7 @@ class StreamingSpanEvent {
|
|
|
75
76
|
|
|
76
77
|
/**
|
|
77
78
|
* Add a key/value pair to the Span's agent attributes collection.
|
|
79
|
+
*
|
|
78
80
|
* @param {string} key Name of the attribute to be stored.
|
|
79
81
|
* @param {string|boolean|number} value Value of the attribute to be stored.
|
|
80
82
|
* @param {boolean} [truncateExempt=false] Set to true if attribute should not be truncated.
|
|
@@ -95,13 +97,12 @@ class StreamingSpanEvent {
|
|
|
95
97
|
|
|
96
98
|
toStreamingFormat() {
|
|
97
99
|
// Attributes are pre-formatted.
|
|
98
|
-
|
|
100
|
+
return {
|
|
99
101
|
trace_id: this._traceId,
|
|
100
102
|
intrinsics: this._intrinsicAttributes,
|
|
101
103
|
user_attributes: this._customAttributes,
|
|
102
104
|
agent_attributes: this._agentAttributes
|
|
103
105
|
}
|
|
104
|
-
return formatted
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
static fromSegment(segment, parentId = null, isRoot = false) {
|
package/lib/symbols.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
cache: Symbol('cache'),
|
|
10
|
+
context: Symbol('context'),
|
|
11
|
+
databaseName: Symbol('databaseName'),
|
|
12
|
+
disableDT: Symbol('Disable distributed tracing'), // description for backwards compatibility
|
|
13
|
+
executorContext: Symbol('executorContext'),
|
|
14
|
+
instrumented: Symbol('instrumented'),
|
|
15
|
+
instrumentedErrored: Symbol('instrumentedErrored'),
|
|
16
|
+
name: Symbol('name'),
|
|
17
|
+
onceExecuted: Symbol('onceExecuted'),
|
|
18
|
+
offTheRecord: Symbol('offTheRecord'),
|
|
19
|
+
original: Symbol('original'),
|
|
20
|
+
segment: Symbol('segment'),
|
|
21
|
+
shim: Symbol('shim'),
|
|
22
|
+
storeDatabase: Symbol('storeDatabase'),
|
|
23
|
+
transaction: Symbol('transaction'),
|
|
24
|
+
transactionInfo: Symbol('transactionInfo'),
|
|
25
|
+
unwrap: Symbol('unwrap')
|
|
26
|
+
}
|
package/lib/system-info.js
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
+
/* eslint sonarjs/cognitive-complexity: ["error", 29] -- TODO: https://issues.newrelic.com/browse/NEWRELIC-5252 */
|
|
9
|
+
|
|
8
10
|
const exec = require('child_process').exec
|
|
9
11
|
const readProc = require('./utilization/common').readProc
|
|
10
12
|
const getBootId = require('./utilization/docker-info').getBootId
|
|
@@ -21,7 +23,7 @@ function isInteger(i) {
|
|
|
21
23
|
return i === parseInt(i, 10)
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
function fetchSystemInfo(agent, callback) {
|
|
26
|
+
function fetchSystemInfo(agent, callback, numTasks = 5) {
|
|
25
27
|
const config = agent.config
|
|
26
28
|
const systemInfo = {
|
|
27
29
|
processorArch: os.arch()
|
|
@@ -74,7 +76,6 @@ function fetchSystemInfo(agent, callback) {
|
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
let tasksDone = 0
|
|
77
|
-
const numTasks = 5
|
|
78
79
|
function finishedResponse() {
|
|
79
80
|
if (++tasksDone === numTasks) {
|
|
80
81
|
callback(null, systemInfo)
|
|
@@ -174,11 +175,7 @@ module.exports._getMemoryStats = function getMemoryStats(callback) {
|
|
|
174
175
|
}
|
|
175
176
|
|
|
176
177
|
function getKernelVersion(callback) {
|
|
177
|
-
if (platform.match(/darwin/i)) {
|
|
178
|
-
getSysctlValue(['kern.version'], function getMem(version) {
|
|
179
|
-
callback(version)
|
|
180
|
-
})
|
|
181
|
-
} else if (platform.match(/bsd/i)) {
|
|
178
|
+
if (platform.match(/darwin/i) || platform.match(/bsd/i)) {
|
|
182
179
|
getSysctlValue(['kern.version'], function getMem(version) {
|
|
183
180
|
callback(version)
|
|
184
181
|
})
|
package/lib/timer.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
* Explicit enumeration of the states a transaction can be in:
|
|
11
11
|
*
|
|
12
12
|
* PENDING upon instantiation (implicitly, no start time set)
|
|
@@ -106,21 +106,21 @@ Timer.prototype.softEnd = function softEnd() {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
/**
|
|
109
|
-
* @
|
|
109
|
+
* @returns {bool} Is this timer currently running?
|
|
110
110
|
*/
|
|
111
111
|
Timer.prototype.isRunning = function isRunning() {
|
|
112
112
|
return this.state === RUNNING
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
/**
|
|
116
|
-
* @
|
|
116
|
+
* @returns {bool} Is this timer still alive?
|
|
117
117
|
*/
|
|
118
118
|
Timer.prototype.isActive = function isActive() {
|
|
119
119
|
return this.state < STOPPED
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
/**
|
|
123
|
-
* @
|
|
123
|
+
* @returns {bool} Has the timer been touched or ended?
|
|
124
124
|
*/
|
|
125
125
|
Timer.prototype.hasEnd = function hasEnd() {
|
|
126
126
|
return !!this.hrDuration
|
|
@@ -192,7 +192,7 @@ Timer.prototype.getDurationInMillis = function getDurationInMillis() {
|
|
|
192
192
|
/**
|
|
193
193
|
* Get a single object containing the interval this timer was active.
|
|
194
194
|
*
|
|
195
|
-
* @
|
|
195
|
+
* @returns {Array} 2-tuple of start time in milliseconds, end time in
|
|
196
196
|
* milliseconds.
|
|
197
197
|
*/
|
|
198
198
|
Timer.prototype.toRange = function toRange() {
|
|
@@ -205,7 +205,7 @@ Timer.prototype.toRange = function toRange() {
|
|
|
205
205
|
* milliseconds since start.
|
|
206
206
|
*
|
|
207
207
|
* @param {Timer} other The point relative to which this timer started.
|
|
208
|
-
* @
|
|
208
|
+
* @returns {number} The offset in (floating-point) milliseconds.
|
|
209
209
|
*/
|
|
210
210
|
Timer.prototype.startedRelativeTo = function startedRelativeTo(other) {
|
|
211
211
|
if (this.hrstart && other.hrstart) {
|
|
@@ -220,6 +220,8 @@ Timer.prototype.startedRelativeTo = function startedRelativeTo(other) {
|
|
|
220
220
|
|
|
221
221
|
/**
|
|
222
222
|
* Returns true if this timer ends after the other.
|
|
223
|
+
*
|
|
224
|
+
* @param other
|
|
223
225
|
*/
|
|
224
226
|
Timer.prototype.endsAfter = function compare(other) {
|
|
225
227
|
return this.getDurationInMillis() + this.start > other.getDurationInMillis() + other.start
|
|
@@ -15,7 +15,8 @@ module.exports = class DistributedTracePayload {
|
|
|
15
15
|
* The class responsible for producing distributed trace payloads.
|
|
16
16
|
* Created by calling {@link TransactionHandle#_createDistributedTracePayload}.
|
|
17
17
|
*
|
|
18
|
-
* @
|
|
18
|
+
* @param payload
|
|
19
|
+
* @class
|
|
19
20
|
*/
|
|
20
21
|
constructor(payload) {
|
|
21
22
|
logger.trace('DistributedTracePayload created with %s', payload)
|
|
@@ -27,7 +28,7 @@ module.exports = class DistributedTracePayload {
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
|
-
* @returns {
|
|
31
|
+
* @returns {string} The base64 encoded JSON representation of the
|
|
31
32
|
* distributed trace payload.
|
|
32
33
|
*/
|
|
33
34
|
text() {
|
|
@@ -38,7 +39,7 @@ module.exports = class DistributedTracePayload {
|
|
|
38
39
|
/**
|
|
39
40
|
* Construct a payload suitable for HTTP transport.
|
|
40
41
|
*
|
|
41
|
-
* @returns {
|
|
42
|
+
* @returns {string} The base64 encoded JSON representation of the
|
|
42
43
|
* distributed trace payload.
|
|
43
44
|
*/
|
|
44
45
|
httpSafe() {
|
|
@@ -14,7 +14,9 @@ class TransactionHandle {
|
|
|
14
14
|
* A light representation of a transaction instance, returned by calling
|
|
15
15
|
* {@link API#getTransaction}.
|
|
16
16
|
*
|
|
17
|
-
* @
|
|
17
|
+
* @param transaction
|
|
18
|
+
* @param metrics
|
|
19
|
+
* @class
|
|
18
20
|
*/
|
|
19
21
|
constructor(transaction, metrics) {
|
|
20
22
|
this._transaction = transaction
|
|
@@ -54,7 +56,9 @@ class TransactionHandle {
|
|
|
54
56
|
* Parsing incoming headers for use in a distributed trace.
|
|
55
57
|
* W3C TraceContext format is preferred over the NewRelic DT format.
|
|
56
58
|
* NewRelic DT format will be used if no `traceparent` header is found.
|
|
59
|
+
*
|
|
57
60
|
* @param @param {string} [transportType='Unknown'] - The transport type that delivered the trace.
|
|
61
|
+
* @param transportType
|
|
58
62
|
* @param {object} headers - Headers to search for supported formats. Keys must be lowercase.
|
|
59
63
|
*/
|
|
60
64
|
acceptDistributedTraceHeaders(transportType, headers) {
|
|
@@ -64,7 +68,8 @@ class TransactionHandle {
|
|
|
64
68
|
|
|
65
69
|
/**
|
|
66
70
|
* Inserts distributed trace headers into the provided headers map.
|
|
67
|
-
*
|
|
71
|
+
*
|
|
72
|
+
* @param {object} headers
|
|
68
73
|
*/
|
|
69
74
|
insertDistributedTraceHeaders(headers) {
|
|
70
75
|
incrementApiSupportMetric(this._metrics, 'insertDistributedTraceHeaders')
|
|
@@ -74,6 +79,11 @@ class TransactionHandle {
|
|
|
74
79
|
|
|
75
80
|
module.exports = TransactionHandle
|
|
76
81
|
|
|
82
|
+
/**
|
|
83
|
+
*
|
|
84
|
+
* @param metrics
|
|
85
|
+
* @param functionName
|
|
86
|
+
*/
|
|
77
87
|
function incrementApiSupportMetric(metrics, functionName) {
|
|
78
88
|
if (!metrics) {
|
|
79
89
|
logger.warnOnce(
|
package/lib/transaction/index.js
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
+
/* eslint sonarjs/cognitive-complexity: ["error", 29] -- TODO: https://issues.newrelic.com/browse/NEWRELIC-5252 */
|
|
9
|
+
|
|
8
10
|
const errorHelper = require('../errors/helper')
|
|
9
11
|
const hashes = require('../util/hashes')
|
|
10
12
|
const logger = require('../logger').child({ component: 'transaction' })
|
|
@@ -18,6 +20,9 @@ const url = require('url')
|
|
|
18
20
|
const urltils = require('../util/urltils')
|
|
19
21
|
const TraceContext = require('./tracecontext').TraceContext
|
|
20
22
|
const Logs = require('./logs')
|
|
23
|
+
const DT_ACCEPT_PAYLOAD_EXCEPTION_METRIC = 'DistributedTrace/AcceptPayload/Exception'
|
|
24
|
+
const DT_ACCEPT_PAYLOAD_PARSE_EXCEPTION_METRIC = 'DistributedTrace/AcceptPayload/ParseException'
|
|
25
|
+
const REQUEST_PARAMS_PATH = 'request.parameters.'
|
|
21
26
|
|
|
22
27
|
/*
|
|
23
28
|
*
|
|
@@ -425,7 +430,7 @@ function finalizeNameFromUri(requestURL, statusCode) {
|
|
|
425
430
|
this.nameState.forEachParams(function forEachRouteParams(params) {
|
|
426
431
|
for (const key in params) {
|
|
427
432
|
if (props.hasOwn(params, key)) {
|
|
428
|
-
this.trace.attributes.addAttribute(DESTS.NONE,
|
|
433
|
+
this.trace.attributes.addAttribute(DESTS.NONE, REQUEST_PARAMS_PATH + key, params[key])
|
|
429
434
|
|
|
430
435
|
const segment = this.agent.tracer.getSegment()
|
|
431
436
|
|
|
@@ -435,7 +440,7 @@ function finalizeNameFromUri(requestURL, statusCode) {
|
|
|
435
440
|
key
|
|
436
441
|
)
|
|
437
442
|
} else {
|
|
438
|
-
segment.attributes.addAttribute(DESTS.NONE,
|
|
443
|
+
segment.attributes.addAttribute(DESTS.NONE, REQUEST_PARAMS_PATH + key, params[key])
|
|
439
444
|
}
|
|
440
445
|
}
|
|
441
446
|
}
|
|
@@ -484,7 +489,7 @@ Transaction.prototype._markAsWeb = function _markAsWeb(rawURL) {
|
|
|
484
489
|
const params = urltils.parseParameters(rawURL)
|
|
485
490
|
for (const key in params) {
|
|
486
491
|
if (props.hasOwn(params, key)) {
|
|
487
|
-
this.trace.attributes.addAttribute(DESTS.NONE,
|
|
492
|
+
this.trace.attributes.addAttribute(DESTS.NONE, REQUEST_PARAMS_PATH + key, params[key])
|
|
488
493
|
|
|
489
494
|
const segment = this.agent.tracer.getSegment()
|
|
490
495
|
|
|
@@ -494,7 +499,7 @@ Transaction.prototype._markAsWeb = function _markAsWeb(rawURL) {
|
|
|
494
499
|
key
|
|
495
500
|
)
|
|
496
501
|
} else {
|
|
497
|
-
segment.attributes.addAttribute(DESTS.NONE,
|
|
502
|
+
segment.attributes.addAttribute(DESTS.NONE, REQUEST_PARAMS_PATH + key, params[key])
|
|
498
503
|
}
|
|
499
504
|
}
|
|
500
505
|
}
|
|
@@ -1058,7 +1063,7 @@ function _acceptDistributedTracePayload(payload, transport) {
|
|
|
1058
1063
|
trustedAccount
|
|
1059
1064
|
)
|
|
1060
1065
|
|
|
1061
|
-
this.agent.recordSupportability(
|
|
1066
|
+
this.agent.recordSupportability(DT_ACCEPT_PAYLOAD_EXCEPTION_METRIC)
|
|
1062
1067
|
return
|
|
1063
1068
|
}
|
|
1064
1069
|
|
|
@@ -1075,14 +1080,14 @@ function _acceptDistributedTracePayload(payload, transport) {
|
|
|
1075
1080
|
if (!parsed.d) {
|
|
1076
1081
|
logger.warn('Received a distributed trace payload with no data field', this.id)
|
|
1077
1082
|
}
|
|
1078
|
-
this.agent.recordSupportability(
|
|
1083
|
+
this.agent.recordSupportability(DT_ACCEPT_PAYLOAD_PARSE_EXCEPTION_METRIC)
|
|
1079
1084
|
return
|
|
1080
1085
|
}
|
|
1081
1086
|
|
|
1082
1087
|
const majorVersion = parsed.v && typeof parsed.v[0] === 'number' && parsed.v[0]
|
|
1083
1088
|
if (majorVersion == null) {
|
|
1084
1089
|
logger.warn('Invalid distributed trace payload, not accepting')
|
|
1085
|
-
this.agent.recordSupportability(
|
|
1090
|
+
this.agent.recordSupportability(DT_ACCEPT_PAYLOAD_EXCEPTION_METRIC)
|
|
1086
1091
|
}
|
|
1087
1092
|
if (majorVersion > 0) {
|
|
1088
1093
|
// TODO: Add DistributedTracePayload class?
|
|
@@ -1094,7 +1099,7 @@ function _acceptDistributedTracePayload(payload, transport) {
|
|
|
1094
1099
|
|
|
1095
1100
|
if (!data) {
|
|
1096
1101
|
logger.warn('No distributed trace data received, not accepting payload')
|
|
1097
|
-
this.agent.recordSupportability(
|
|
1102
|
+
this.agent.recordSupportability(DT_ACCEPT_PAYLOAD_EXCEPTION_METRIC)
|
|
1098
1103
|
return
|
|
1099
1104
|
}
|
|
1100
1105
|
|
|
@@ -1103,7 +1108,7 @@ function _acceptDistributedTracePayload(payload, transport) {
|
|
|
1103
1108
|
})
|
|
1104
1109
|
// Either parentSpanId or parentId are required.
|
|
1105
1110
|
if (!requiredKeysExist || (data.tx == null && data.id == null)) {
|
|
1106
|
-
this.agent.recordSupportability(
|
|
1111
|
+
this.agent.recordSupportability(DT_ACCEPT_PAYLOAD_PARSE_EXCEPTION_METRIC)
|
|
1107
1112
|
return
|
|
1108
1113
|
}
|
|
1109
1114
|
|
|
@@ -1157,7 +1162,7 @@ Transaction.prototype._getParsedPayload = function _getParsedPayload(payload) {
|
|
|
1157
1162
|
payload = Buffer.from(payload, 'base64').toString('utf-8')
|
|
1158
1163
|
} catch (err) {
|
|
1159
1164
|
logger.warn(err, 'Got unparseable distributed trace payload in transaction %s', this.id)
|
|
1160
|
-
this.agent.recordSupportability(
|
|
1165
|
+
this.agent.recordSupportability(DT_ACCEPT_PAYLOAD_PARSE_EXCEPTION_METRIC)
|
|
1161
1166
|
return null
|
|
1162
1167
|
}
|
|
1163
1168
|
}
|
|
@@ -1165,7 +1170,7 @@ Transaction.prototype._getParsedPayload = function _getParsedPayload(payload) {
|
|
|
1165
1170
|
parsed = JSON.parse(payload)
|
|
1166
1171
|
} catch (err) {
|
|
1167
1172
|
logger.warn(err, 'Failed to parse distributed trace payload in transaction %s', this.id)
|
|
1168
|
-
this.agent.recordSupportability(
|
|
1173
|
+
this.agent.recordSupportability(DT_ACCEPT_PAYLOAD_PARSE_EXCEPTION_METRIC)
|
|
1169
1174
|
return null
|
|
1170
1175
|
}
|
|
1171
1176
|
}
|
|
@@ -1300,24 +1305,20 @@ Transaction.prototype.addRequestParameters = addRequestParameters
|
|
|
1300
1305
|
* 'request.parameters.{key}'. These attributes will only be created
|
|
1301
1306
|
* when 'request.parameters.*' is included in the attribute config.
|
|
1302
1307
|
*
|
|
1303
|
-
* @param {
|
|
1308
|
+
* @param {Object<string, string>} requestParameters
|
|
1304
1309
|
*/
|
|
1305
1310
|
function addRequestParameters(requestParameters) {
|
|
1306
1311
|
for (const key in requestParameters) {
|
|
1307
1312
|
if (props.hasOwn(requestParameters, key)) {
|
|
1308
1313
|
this.trace.attributes.addAttribute(
|
|
1309
1314
|
DESTS.NONE,
|
|
1310
|
-
|
|
1315
|
+
REQUEST_PARAMS_PATH + key,
|
|
1311
1316
|
requestParameters[key]
|
|
1312
1317
|
)
|
|
1313
1318
|
|
|
1314
1319
|
const segment = this.baseSegment
|
|
1315
1320
|
|
|
1316
|
-
segment.attributes.addAttribute(
|
|
1317
|
-
DESTS.NONE,
|
|
1318
|
-
'request.parameters.' + key,
|
|
1319
|
-
requestParameters[key]
|
|
1320
|
-
)
|
|
1321
|
+
segment.attributes.addAttribute(DESTS.NONE, REQUEST_PARAMS_PATH + key, requestParameters[key])
|
|
1321
1322
|
}
|
|
1322
1323
|
}
|
|
1323
1324
|
}
|