newrelic 8.0.0 → 8.4.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 +5023 -4922
- package/THIRD_PARTY_NOTICES.md +618 -209
- package/api.js +156 -219
- package/bin/test-naming-rules.js +57 -51
- package/bin/tracetractor +0 -1
- package/index.js +7 -14
- package/lib/agent.js +111 -114
- package/lib/aggregators/base-aggregator.js +1 -1
- package/lib/aggregators/event-aggregator.js +6 -6
- package/lib/attributes.js +13 -14
- package/lib/collector/api.js +44 -54
- package/lib/collector/facts.js +68 -66
- package/lib/collector/http-agents.js +36 -32
- package/lib/collector/key-parser.js +1 -1
- package/lib/collector/parse-response.js +1 -2
- package/lib/collector/remote-method.js +69 -61
- package/lib/collector/serverless.js +13 -18
- package/lib/collector/ssl/certificates.js +1056 -1056
- package/lib/config/attribute-filter.js +109 -101
- package/lib/config/default.js +35 -21
- package/lib/config/env.js +17 -12
- package/lib/config/harvest-config-validator.js +1 -1
- package/lib/config/hsm.js +1 -1
- package/lib/config/index.js +240 -234
- package/lib/config/lasp.js +3 -3
- package/lib/config/merge-server-config.js +8 -6
- package/lib/custom-events/custom-event-aggregator.js +1 -1
- package/lib/db/parse-sql.js +13 -16
- package/lib/db/parsed-statement.js +13 -19
- package/lib/db/query-parsers/sql.js +12 -15
- package/lib/db/query-sample.js +16 -12
- package/lib/db/query-trace-aggregator.js +16 -16
- package/lib/db/statement-matcher.js +5 -5
- package/lib/db/utils.js +2 -2
- package/lib/environment.js +210 -175
- package/lib/errors/error-collector.js +20 -33
- package/lib/errors/error-event-aggregator.js +1 -1
- package/lib/errors/error-trace-aggregator.js +3 -4
- package/lib/errors/helper.js +23 -32
- package/lib/errors/index.js +31 -43
- package/lib/feature_flags.js +3 -4
- package/lib/grpc/connection/states.js +6 -6
- package/lib/grpc/connection.js +35 -46
- package/lib/header-attributes.js +55 -59
- package/lib/header-processing.js +1 -1
- package/lib/instrumentation/amqplib.js +34 -43
- package/lib/instrumentation/bluebird.js +63 -22
- package/lib/instrumentation/cassandra-driver.js +8 -4
- package/lib/instrumentation/connect.js +7 -6
- package/lib/instrumentation/core/async_hooks.js +16 -9
- package/lib/instrumentation/core/child_process.js +20 -28
- package/lib/instrumentation/core/crypto.js +1 -7
- package/lib/instrumentation/core/dns.js +3 -7
- package/lib/instrumentation/core/domain.js +4 -10
- package/lib/instrumentation/core/fs.js +22 -37
- package/lib/instrumentation/core/globals.js +4 -8
- package/lib/instrumentation/core/http-outbound.js +20 -114
- package/lib/instrumentation/core/http.js +61 -128
- package/lib/instrumentation/core/inspector.js +7 -11
- package/lib/instrumentation/core/net.js +3 -1
- package/lib/instrumentation/core/timers.js +21 -28
- package/lib/instrumentation/core/zlib.js +3 -11
- package/lib/instrumentation/director.js +4 -4
- package/lib/instrumentation/express.js +12 -10
- package/lib/instrumentation/fastify/spec-builders.js +5 -0
- package/lib/instrumentation/fastify.js +37 -10
- package/lib/instrumentation/generic-pool.js +1 -1
- package/lib/instrumentation/hapi/hapi-17.js +20 -21
- package/lib/instrumentation/hapi/shared.js +1 -1
- package/lib/instrumentation/hapi.js +37 -37
- package/lib/instrumentation/ioredis.js +8 -9
- package/lib/instrumentation/memcached.js +41 -45
- package/lib/instrumentation/mongodb/common.js +221 -0
- package/lib/instrumentation/mongodb/constants.js +87 -0
- package/lib/instrumentation/mongodb/v2-mongo.js +110 -0
- package/lib/instrumentation/mongodb/v3-mongo.js +80 -0
- package/lib/instrumentation/mongodb/v4-mongo.js +90 -0
- package/lib/instrumentation/mongodb.js +20 -312
- package/lib/instrumentation/mysql.js +51 -44
- package/lib/instrumentation/oracle.js +24 -28
- package/lib/instrumentation/pg.js +34 -25
- package/lib/instrumentation/promise.js +65 -62
- package/lib/instrumentation/q.js +2 -2
- package/lib/instrumentation/redis.js +38 -38
- package/lib/instrumentation/restify.js +1 -1
- package/lib/instrumentation/vision.js +4 -4
- package/lib/instrumentation/when.js +12 -4
- package/lib/instrumentations.js +25 -25
- package/lib/logger.js +6 -6
- package/lib/metrics/index.js +50 -30
- package/lib/metrics/mapper.js +15 -15
- package/lib/metrics/metric-aggregator.js +5 -10
- package/lib/metrics/names.js +8 -7
- package/lib/metrics/normalizer/rule.js +14 -15
- package/lib/metrics/normalizer/tx_segment.js +33 -29
- package/lib/metrics/normalizer.js +51 -54
- package/lib/metrics/recorders/custom.js +8 -6
- package/lib/metrics/recorders/distributed-trace.js +3 -18
- package/lib/metrics/recorders/generic.js +6 -5
- package/lib/metrics/recorders/http.js +11 -13
- package/lib/metrics/recorders/http_external.js +8 -10
- package/lib/metrics/recorders/message-transaction.js +7 -18
- package/lib/metrics/recorders/other.js +7 -17
- package/lib/parse-proc-cpuinfo.js +26 -31
- package/lib/parse-proc-meminfo.js +5 -3
- package/lib/prioritized-attributes.js +14 -19
- package/lib/priority-queue.js +11 -11
- package/lib/proxy/grpc.js +1 -1
- package/lib/reservoir.js +12 -6
- package/lib/sampler.js +33 -34
- package/lib/serverless/api-gateway.js +3 -3
- package/lib/serverless/aws-lambda.js +28 -37
- package/lib/shim/conglomerate-shim.js +4 -4
- package/lib/shim/datastore-shim.js +61 -67
- package/lib/shim/index.js +10 -11
- package/lib/shim/message-shim.js +149 -151
- package/lib/shim/promise-shim.js +19 -14
- package/lib/shim/shim.js +131 -125
- package/lib/shim/specs/index.js +21 -22
- package/lib/shim/transaction-shim.js +52 -210
- package/lib/shim/webframework-shim.js +75 -85
- package/lib/shimmer.js +184 -166
- package/lib/spans/create-span-event-aggregator.js +11 -8
- package/lib/spans/span-context.js +4 -10
- package/lib/spans/span-event-aggregator.js +68 -13
- package/lib/spans/span-event.js +6 -8
- package/lib/spans/span-streamer.js +10 -18
- package/lib/spans/streaming-span-attributes.js +1 -1
- package/lib/spans/streaming-span-event-aggregator.js +1 -1
- package/lib/spans/streaming-span-event.js +4 -4
- package/lib/stats/apdex.js +7 -13
- package/lib/stats/index.js +14 -19
- package/lib/system-info.js +29 -25
- package/lib/timer.js +35 -21
- package/lib/transaction/dt-payload.js +1 -1
- package/lib/transaction/handle.js +19 -19
- package/lib/transaction/index.js +133 -151
- package/lib/transaction/name-state.js +18 -19
- package/lib/transaction/trace/aggregator.js +78 -73
- package/lib/transaction/trace/exclusive-time-calculator.js +9 -13
- package/lib/transaction/trace/index.js +37 -35
- package/lib/transaction/trace/segment.js +56 -73
- package/lib/transaction/tracecontext.js +38 -46
- package/lib/transaction/tracer/index.js +130 -91
- package/lib/transaction/transaction-event-aggregator.js +29 -31
- package/lib/uninstrumented.js +11 -12
- package/lib/util/arity.js +2 -2
- package/lib/util/attribute-types.js +1 -5
- package/lib/util/byte-limit.js +4 -5
- package/lib/util/cat.js +270 -33
- package/lib/util/codec.js +10 -6
- package/lib/util/copy.js +2 -2
- package/lib/util/deep-equal.js +51 -21
- package/lib/util/flatten.js +9 -6
- package/lib/util/hashes.js +16 -16
- package/lib/util/label-parser.js +22 -28
- package/lib/util/logger.js +53 -35
- package/lib/util/process-version.js +3 -3
- package/lib/util/properties.js +5 -5
- package/lib/util/sql/obfuscate.js +21 -31
- package/lib/util/stream-sink.js +5 -6
- package/lib/util/unwrapped-core.js +2 -2
- package/lib/util/urltils.js +26 -30
- package/lib/utilization/aws-info.js +8 -9
- package/lib/utilization/azure-info.js +37 -35
- package/lib/utilization/common.js +17 -16
- package/lib/utilization/docker-info.js +14 -16
- package/lib/utilization/gcp-info.js +38 -37
- package/lib/utilization/index.js +5 -5
- package/lib/utilization/kubernetes-info.js +2 -2
- package/lib/utilization/pcf-info.js +12 -12
- package/package.json +23 -6
- package/stub_api.js +16 -14
package/lib/util/cat.js
CHANGED
|
@@ -5,59 +5,296 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
+
const cat = module.exports
|
|
8
9
|
const hashes = require('./hashes')
|
|
9
|
-
const logger = require('../logger').child({component: 'cat'})
|
|
10
|
+
const logger = require('../logger').child({ component: 'cat' })
|
|
11
|
+
const NAMES = require('../metrics/names')
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
const HTTP_CAT_ID_HEADER = 'X-NewRelic-Id'
|
|
14
|
+
const MQ_CAT_ID_HEADER = 'NewRelicID'
|
|
15
|
+
const MATCH_CAT_ID_HEADER = new RegExp(
|
|
16
|
+
'^(?:' + HTTP_CAT_ID_HEADER + '|' + MQ_CAT_ID_HEADER + ')$',
|
|
17
|
+
'i'
|
|
18
|
+
)
|
|
19
|
+
const HTTP_CAT_TRANSACTION_HEADER = 'X-NewRelic-Transaction'
|
|
20
|
+
const MQ_CAT_TRANSACTION_HEADER = 'NewRelicTransaction'
|
|
21
|
+
const MATCH_CAT_TRANSACTION_HEADER = new RegExp(
|
|
22
|
+
'^(?:' + HTTP_CAT_TRANSACTION_HEADER + '|' + MQ_CAT_TRANSACTION_HEADER + ')$',
|
|
23
|
+
'i'
|
|
24
|
+
)
|
|
25
|
+
const HTTP_CAT_APP_DATA_HEADER = 'X-NewRelic-App-Data'
|
|
26
|
+
const MQ_CAT_APP_DATA_HEADER = 'NewRelicAppData'
|
|
27
|
+
const MATCH_CAT_APP_DATA_HEADER = new RegExp(
|
|
28
|
+
'^(?:' + HTTP_CAT_APP_DATA_HEADER + '|' + MQ_CAT_APP_DATA_HEADER + ')$',
|
|
29
|
+
'i'
|
|
30
|
+
)
|
|
13
31
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Decodes the CAT id and transaction headers from incoming request
|
|
34
|
+
*
|
|
35
|
+
* @param {Object} headers incoming headers
|
|
36
|
+
* @param {string} encKey config.encoding_key used to decode CAT headers
|
|
37
|
+
* @param {Object} { externalId, externalTransaction }
|
|
38
|
+
*/
|
|
39
|
+
cat.parseCatData = function parseCatData(id, transactionId, encKey) {
|
|
40
|
+
if (!encKey) {
|
|
41
|
+
logger.warn('Missing encoding key, not extract CAT headers!')
|
|
42
|
+
return {}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let externalId = null
|
|
46
|
+
|
|
47
|
+
if (id) {
|
|
48
|
+
externalId = hashes.deobfuscateNameUsingKey(id, encKey)
|
|
21
49
|
}
|
|
22
50
|
|
|
23
|
-
|
|
24
|
-
if (
|
|
51
|
+
let externalTransaction = null
|
|
52
|
+
if (transactionId) {
|
|
25
53
|
try {
|
|
26
|
-
|
|
27
|
-
hashes.deobfuscateNameUsingKey(obfTransaction, encKey)
|
|
28
|
-
)
|
|
54
|
+
externalTransaction = JSON.parse(hashes.deobfuscateNameUsingKey(transactionId, encKey))
|
|
29
55
|
} catch (e) {
|
|
30
|
-
logger.trace(
|
|
31
|
-
'Got an unparsable CAT header x-newrelic-transaction: %s',
|
|
32
|
-
obfTransaction
|
|
33
|
-
)
|
|
56
|
+
logger.trace(`Got an unparsable CAT header ${HTTP_CAT_ID_HEADER} %s`, transactionId)
|
|
34
57
|
}
|
|
35
58
|
}
|
|
36
59
|
|
|
37
|
-
|
|
60
|
+
return { externalId, externalTransaction }
|
|
38
61
|
}
|
|
39
62
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
63
|
+
/**
|
|
64
|
+
* Adds the appropriate keys to transaction based on the incoming parsed CAT data
|
|
65
|
+
*
|
|
66
|
+
* @param {string} externalId decoded CAT id
|
|
67
|
+
* @param {Array} externalTransaction CAT transaction
|
|
68
|
+
* @param {Transaction} transaction active transaction
|
|
69
|
+
*/
|
|
70
|
+
cat.assignCatToTransaction = function assignCatToTransaction(
|
|
71
|
+
externalId,
|
|
72
|
+
externalTransaction,
|
|
73
|
+
transaction
|
|
74
|
+
) {
|
|
75
|
+
if (typeof externalId === 'string') {
|
|
76
|
+
transaction.incomingCatId = externalId
|
|
43
77
|
}
|
|
44
78
|
|
|
45
|
-
if (Array.isArray(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
79
|
+
if (Array.isArray(externalTransaction)) {
|
|
80
|
+
const [referringGuid, , tripId, referringPathHash] = externalTransaction
|
|
81
|
+
transaction.referringTransactionGuid = referringGuid
|
|
82
|
+
|
|
83
|
+
if (typeof tripId === 'string') {
|
|
84
|
+
transaction.tripId = tripId
|
|
85
|
+
} else if (tripId) {
|
|
50
86
|
transaction.invalidIncomingExternalTransaction = true
|
|
51
87
|
}
|
|
52
88
|
|
|
53
|
-
if (
|
|
54
|
-
transaction.referringPathHash =
|
|
55
|
-
} else if (
|
|
89
|
+
if (typeof referringPathHash === 'string') {
|
|
90
|
+
transaction.referringPathHash = referringPathHash
|
|
91
|
+
} else if (referringPathHash) {
|
|
56
92
|
transaction.invalidIncomingExternalTransaction = true
|
|
57
93
|
}
|
|
58
94
|
}
|
|
95
|
+
|
|
96
|
+
if (transaction.incomingCatId) {
|
|
97
|
+
logger.trace(
|
|
98
|
+
'Got inbound CAT headers in transaction %s from %s',
|
|
99
|
+
transaction.id,
|
|
100
|
+
transaction.incomingCatId
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Encodes the data to be set on the CAT app data header
|
|
107
|
+
* for incoming requests
|
|
108
|
+
*
|
|
109
|
+
* @param {Object} config agent config
|
|
110
|
+
* @param {Transaction} transaction
|
|
111
|
+
* @param {string} contentLength
|
|
112
|
+
* @param {Boolean} useMqHeaders flag to return proper headers for MQ compliance
|
|
113
|
+
* @return {Object} { key, data} to add as header
|
|
114
|
+
*/
|
|
115
|
+
cat.encodeAppData = function encodeAppData(config, transaction, contentLength, useMqHeaders) {
|
|
116
|
+
let appData = null
|
|
117
|
+
const transactionName = transaction.getFullName() || ''
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
appData = JSON.stringify([
|
|
121
|
+
config.cross_process_id, // cross_process_id
|
|
122
|
+
transactionName, // transaction name
|
|
123
|
+
transaction.queueTime / 1000, // queue time (s)
|
|
124
|
+
transaction.catResponseTime / 1000, // response time (s)
|
|
125
|
+
contentLength, // content length (if content-length header is also being sent)
|
|
126
|
+
transaction.id, // TransactionGuid
|
|
127
|
+
false // force a transaction trace to be recorded
|
|
128
|
+
])
|
|
129
|
+
} catch (err) {
|
|
130
|
+
logger.trace(
|
|
131
|
+
err,
|
|
132
|
+
'Failed to serialize transaction: %s - not adding CAT response headers',
|
|
133
|
+
transactionName
|
|
134
|
+
)
|
|
135
|
+
return
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const encKey = config.encoding_key
|
|
139
|
+
const obfAppData = hashes.obfuscateNameUsingKey(appData, encKey)
|
|
140
|
+
const key = useMqHeaders ? MQ_CAT_APP_DATA_HEADER : HTTP_CAT_APP_DATA_HEADER
|
|
141
|
+
return { key, data: obfAppData }
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Adds CAT headers to outbound request.
|
|
146
|
+
*
|
|
147
|
+
* @param {Object} config agent config
|
|
148
|
+
* @param {Transaction} transaction
|
|
149
|
+
* @param {Object} headers object that contains headers the agent is adding to client request
|
|
150
|
+
* @param {Boolean} useMqHeaders flag to return proper headers for MQ compliance
|
|
151
|
+
*/
|
|
152
|
+
cat.addCatHeaders = function addCatHeaders(config, transaction, headers, useMqHeaders) {
|
|
153
|
+
if (!config.encoding_key) {
|
|
154
|
+
logger.warn('Missing encoding key, not adding CAT headers!')
|
|
155
|
+
return
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const idHeader = useMqHeaders ? MQ_CAT_ID_HEADER : HTTP_CAT_ID_HEADER
|
|
159
|
+
const transactionHeader = useMqHeaders ? MQ_CAT_TRANSACTION_HEADER : HTTP_CAT_TRANSACTION_HEADER
|
|
160
|
+
|
|
161
|
+
// Add in the application ID
|
|
162
|
+
if (config.obfuscatedId) {
|
|
163
|
+
headers[idHeader] = config.obfuscatedId
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const transactionName = transaction.getFullName() || ''
|
|
167
|
+
|
|
168
|
+
const pathHash = hashes.calculatePathHash(
|
|
169
|
+
config.applications()[0],
|
|
170
|
+
transactionName,
|
|
171
|
+
transaction.referringPathHash
|
|
172
|
+
)
|
|
173
|
+
transaction.pushPathHash(pathHash)
|
|
174
|
+
|
|
175
|
+
try {
|
|
176
|
+
const transactionData = hashes.obfuscateNameUsingKey(
|
|
177
|
+
JSON.stringify([transaction.id, false, transaction.tripId || transaction.id, pathHash]),
|
|
178
|
+
config.encoding_key
|
|
179
|
+
)
|
|
180
|
+
headers[transactionHeader] = transactionData
|
|
181
|
+
|
|
182
|
+
logger.trace('Added outbound request CAT headers in transaction %s', transaction.id)
|
|
183
|
+
} catch (err) {
|
|
184
|
+
logger.trace(err, 'Failed to create CAT payload')
|
|
185
|
+
}
|
|
59
186
|
}
|
|
60
187
|
|
|
61
|
-
|
|
62
|
-
|
|
188
|
+
/**
|
|
189
|
+
* Find the CAT id, transaction, app data headers
|
|
190
|
+
* from the headers of either HTTP or MQ request
|
|
191
|
+
*
|
|
192
|
+
* @param {Object} headers
|
|
193
|
+
* @return {Object} { id, transactionId, appData }
|
|
194
|
+
*/
|
|
195
|
+
cat.extractCatHeaders = function extractCatHeaders(headers) {
|
|
196
|
+
// Hunt down the CAT headers.
|
|
197
|
+
let id = null
|
|
198
|
+
let transactionId = null
|
|
199
|
+
let appData = null
|
|
200
|
+
// eslint-disable-next-line guard-for-in
|
|
201
|
+
for (const key in headers) {
|
|
202
|
+
if (MATCH_CAT_ID_HEADER.test(key)) {
|
|
203
|
+
id = headers[key]
|
|
204
|
+
} else if (MATCH_CAT_TRANSACTION_HEADER.test(key)) {
|
|
205
|
+
transactionId = headers[key]
|
|
206
|
+
} else if (MATCH_CAT_APP_DATA_HEADER.test(key)) {
|
|
207
|
+
appData = headers[key]
|
|
208
|
+
}
|
|
209
|
+
if (id && transactionId && appData) {
|
|
210
|
+
break
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return { id, transactionId, appData }
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Extracts the account Id from CAT data and verifies if it is
|
|
219
|
+
* a trusted account id
|
|
220
|
+
*
|
|
221
|
+
* @param {Object} CAT data
|
|
222
|
+
* @param {Array} trustedAccounts from config
|
|
223
|
+
* @return {Boolean}
|
|
224
|
+
*/
|
|
225
|
+
cat.isTrustedAccountId = function isTrustedAccountId(data, trustedAccounts) {
|
|
226
|
+
const accountId = parseInt(data.split('#')[0], 10)
|
|
227
|
+
const trusted = trustedAccounts.includes(accountId)
|
|
228
|
+
if (!trusted) {
|
|
229
|
+
logger.trace('Response from untrusted CAT header account id: %s', accountId)
|
|
230
|
+
}
|
|
231
|
+
return trusted
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Decodes the CAT App Data header and extracts the downstream
|
|
236
|
+
* CAT id, transaction id
|
|
237
|
+
*
|
|
238
|
+
* @param {Object} config agent config
|
|
239
|
+
* @param {string} obfAppData encoded app data to parse and use
|
|
240
|
+
* @param {Array} decoded app data header
|
|
241
|
+
*/
|
|
242
|
+
cat.parseAppData = function parseAppData(config, obfAppData) {
|
|
243
|
+
if (!config.encoding_key) {
|
|
244
|
+
logger.trace('config.encoding_key is not set - not parsing response CAT headers')
|
|
245
|
+
return
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (!config.trusted_account_ids) {
|
|
249
|
+
logger.trace('config.trusted_account_ids is not set - not parsing response CAT headers')
|
|
250
|
+
return
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
let appData = null
|
|
254
|
+
try {
|
|
255
|
+
appData = JSON.parse(hashes.deobfuscateNameUsingKey(obfAppData, config.encoding_key))
|
|
256
|
+
} catch (e) {
|
|
257
|
+
logger.warn(`Got an unparsable CAT header ${HTTP_CAT_APP_DATA_HEADER}: %s`, obfAppData)
|
|
258
|
+
return
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Make sure it is a trusted account
|
|
262
|
+
if (!cat.isTrustedAccountId(appData && appData[0], config.trusted_account_ids)) {
|
|
263
|
+
return
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return appData
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Assigns the CAT id, transaction to segment and adds `transaction_guid` when it exists.
|
|
271
|
+
* It also renames the segment name based on the newly decoded app data when host is present
|
|
272
|
+
*
|
|
273
|
+
* @param {Array} appData decodes CAT app data
|
|
274
|
+
* @param {TraceSegment} segment
|
|
275
|
+
* @param {string} [host] if host is present it will rename segment with app data and host
|
|
276
|
+
*/
|
|
277
|
+
cat.assignCatToSegment = function assignCatToSegment(appData, segment, host) {
|
|
278
|
+
if (!Array.isArray(appData) || typeof appData[0] !== 'string') {
|
|
279
|
+
logger.trace(`Unknown format for CAT header ${HTTP_CAT_APP_DATA_HEADER}.`)
|
|
280
|
+
return
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
segment.catId = appData[0]
|
|
284
|
+
segment.catTransaction = appData[1]
|
|
285
|
+
|
|
286
|
+
if (host) {
|
|
287
|
+
segment.name = `${NAMES.EXTERNAL.TRANSACTION}${host}/${segment.catId}/${segment.catTransaction}`
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
let transactionGuid
|
|
291
|
+
if (appData.length >= 6) {
|
|
292
|
+
transactionGuid = appData[5]
|
|
293
|
+
segment.addAttribute('transaction_guid', transactionGuid)
|
|
294
|
+
}
|
|
295
|
+
logger.trace(
|
|
296
|
+
'Got inbound response CAT headers in transaction %s from %s',
|
|
297
|
+
segment.transaction.id,
|
|
298
|
+
transactionGuid
|
|
299
|
+
)
|
|
63
300
|
}
|
package/lib/util/codec.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const stringify = require('json-stringify-safe')
|
|
9
|
+
const zlib = require('zlib')
|
|
10
10
|
|
|
11
11
|
module.exports = {
|
|
12
12
|
/**
|
|
@@ -23,8 +23,10 @@ module.exports = {
|
|
|
23
23
|
*/
|
|
24
24
|
encode: function encode(data, callback) {
|
|
25
25
|
try {
|
|
26
|
-
zlib.deflate(stringify(data), function
|
|
27
|
-
if (err)
|
|
26
|
+
zlib.deflate(stringify(data), function cbDeflate(err, raw) {
|
|
27
|
+
if (err) {
|
|
28
|
+
return callback(err)
|
|
29
|
+
}
|
|
28
30
|
|
|
29
31
|
return callback(null, raw.toString('base64'))
|
|
30
32
|
})
|
|
@@ -47,8 +49,10 @@ module.exports = {
|
|
|
47
49
|
* decoding, and the second parameter is the decoded data object.
|
|
48
50
|
*/
|
|
49
51
|
decode: function decode(encoded, callback) {
|
|
50
|
-
zlib.inflate(Buffer.from(encoded, 'base64'), function
|
|
51
|
-
if (err)
|
|
52
|
+
zlib.inflate(Buffer.from(encoded, 'base64'), function cbInflate(err, raw) {
|
|
53
|
+
if (err) {
|
|
54
|
+
return callback(err)
|
|
55
|
+
}
|
|
52
56
|
|
|
53
57
|
let json
|
|
54
58
|
try {
|
package/lib/util/copy.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const hasOwnProperty = require('./properties').hasOwn
|
|
9
9
|
|
|
10
10
|
exports.shallow = shallowCopy
|
|
11
11
|
|
|
@@ -19,7 +19,7 @@ exports.shallow = shallowCopy
|
|
|
19
19
|
*/
|
|
20
20
|
function shallowCopy(source, dest) {
|
|
21
21
|
dest = dest || Object.create(null)
|
|
22
|
-
for (
|
|
22
|
+
for (const k in source) {
|
|
23
23
|
if (hasOwnProperty(source, k)) {
|
|
24
24
|
dest[k] = source[k]
|
|
25
25
|
}
|
package/lib/util/deep-equal.js
CHANGED
|
@@ -11,7 +11,9 @@ function isArguments(object) {
|
|
|
11
11
|
|
|
12
12
|
function slice(args) {
|
|
13
13
|
// Array.prototype.slice on arguments array-like is expensive
|
|
14
|
-
|
|
14
|
+
const l = args.length
|
|
15
|
+
const a = []
|
|
16
|
+
let i
|
|
15
17
|
for (i = 0; i < l; i++) {
|
|
16
18
|
a[i] = args[i]
|
|
17
19
|
}
|
|
@@ -71,45 +73,73 @@ function deeper(a, b, ca, cb) {
|
|
|
71
73
|
} else if (a === null || b === null) {
|
|
72
74
|
return false
|
|
73
75
|
} else if (Buffer.isBuffer(a) && Buffer.isBuffer(b)) {
|
|
74
|
-
if (a.length !== b.length)
|
|
76
|
+
if (a.length !== b.length) {
|
|
77
|
+
return false
|
|
78
|
+
}
|
|
75
79
|
|
|
76
80
|
// potentially incredibly expensive
|
|
77
|
-
for (
|
|
81
|
+
for (let i = 0; i < a.length; i++) {
|
|
82
|
+
if (a[i] !== b[i]) {
|
|
83
|
+
return false
|
|
84
|
+
}
|
|
85
|
+
}
|
|
78
86
|
|
|
79
87
|
return true
|
|
80
88
|
} else if (a instanceof Date && b instanceof Date) {
|
|
81
89
|
return a.getTime() === b.getTime()
|
|
82
90
|
} else if (a instanceof RegExp && b instanceof RegExp) {
|
|
83
|
-
return
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
91
|
+
return (
|
|
92
|
+
a.source === b.source &&
|
|
93
|
+
a.global === b.global &&
|
|
94
|
+
a.multiline === b.multiline &&
|
|
95
|
+
a.lastIndex === b.lastIndex &&
|
|
96
|
+
a.ignoreCase === b.ignoreCase
|
|
97
|
+
)
|
|
88
98
|
} else if (isArguments(a) || isArguments(b)) {
|
|
89
|
-
if (!(isArguments(a) && isArguments(b)))
|
|
99
|
+
if (!(isArguments(a) && isArguments(b))) {
|
|
100
|
+
return false
|
|
101
|
+
}
|
|
90
102
|
|
|
91
103
|
return deeper(slice(a), slice(b), ca, cb)
|
|
92
104
|
}
|
|
93
105
|
|
|
94
|
-
if (a.constructor !== b.constructor)
|
|
106
|
+
if (a.constructor !== b.constructor) {
|
|
107
|
+
return false
|
|
108
|
+
}
|
|
95
109
|
|
|
96
|
-
|
|
97
|
-
|
|
110
|
+
const ka = Object.keys(a)
|
|
111
|
+
const kb = Object.keys(b)
|
|
112
|
+
if (ka.length !== kb.length) {
|
|
113
|
+
return false
|
|
114
|
+
}
|
|
98
115
|
|
|
99
|
-
|
|
100
|
-
while (cal--)
|
|
101
|
-
|
|
116
|
+
let cal = ca.length
|
|
117
|
+
while (cal--) {
|
|
118
|
+
if (ca[cal] === a) {
|
|
119
|
+
return cb[cal] === b
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
ca.push(a)
|
|
123
|
+
cb.push(b)
|
|
102
124
|
|
|
103
|
-
ka.sort()
|
|
104
|
-
|
|
125
|
+
ka.sort()
|
|
126
|
+
kb.sort()
|
|
127
|
+
for (let j = ka.length - 1; j >= 0; j--) {
|
|
128
|
+
if (ka[j] !== kb[j]) {
|
|
129
|
+
return false
|
|
130
|
+
}
|
|
131
|
+
}
|
|
105
132
|
|
|
106
|
-
|
|
107
|
-
for (
|
|
133
|
+
let key
|
|
134
|
+
for (let k = ka.length - 1; k >= 0; k--) {
|
|
108
135
|
key = ka[k]
|
|
109
|
-
if (!deeper(a[key], b[key], ca, cb))
|
|
136
|
+
if (!deeper(a[key], b[key], ca, cb)) {
|
|
137
|
+
return false
|
|
138
|
+
}
|
|
110
139
|
}
|
|
111
140
|
|
|
112
|
-
ca.pop()
|
|
141
|
+
ca.pop()
|
|
142
|
+
cb.pop()
|
|
113
143
|
|
|
114
144
|
return true
|
|
115
145
|
}
|
package/lib/util/flatten.js
CHANGED
|
@@ -25,13 +25,16 @@ function flatten(result, prefix, obj, seen) {
|
|
|
25
25
|
seen = seen || []
|
|
26
26
|
seen.push(obj)
|
|
27
27
|
|
|
28
|
-
for (
|
|
28
|
+
for (const key in obj) {
|
|
29
29
|
if (seen.indexOf(obj[key]) > -1) {
|
|
30
30
|
continue
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
if (obj[key] instanceof Object)
|
|
34
|
-
|
|
33
|
+
if (obj[key] instanceof Object) {
|
|
34
|
+
flatten(result, prefix + key + '.', obj[key], seen)
|
|
35
|
+
} else {
|
|
36
|
+
result[prefix + key] = obj[key]
|
|
37
|
+
}
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
return result
|
|
@@ -49,15 +52,15 @@ function flatten(result, prefix, obj, seen) {
|
|
|
49
52
|
* @return {array.<string>} An array of keys names.
|
|
50
53
|
*/
|
|
51
54
|
function flatKeys(obj, prefix, arrayIdxs) {
|
|
52
|
-
|
|
53
|
-
|
|
55
|
+
const keys = []
|
|
56
|
+
const seen = []
|
|
54
57
|
recurse(prefix || '', obj)
|
|
55
58
|
return keys
|
|
56
59
|
|
|
57
60
|
function recurse(p, o) {
|
|
58
61
|
seen.push(o)
|
|
59
62
|
|
|
60
|
-
for (
|
|
63
|
+
for (const key in o) {
|
|
61
64
|
if (seen.indexOf(o[key]) !== -1) {
|
|
62
65
|
continue
|
|
63
66
|
}
|
package/lib/util/hashes.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
const crypto = require('crypto')
|
|
9
9
|
|
|
10
10
|
function encode(bytes, keyBytes) {
|
|
11
|
-
for (
|
|
11
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
12
12
|
// This is really dense but happens commonly so I'm in-lining some of what
|
|
13
13
|
// could be tossed into variables. It takes the current byte of bytes, then
|
|
14
14
|
// XORs it with the current byte of the key (which uses modulo to make sure
|
|
@@ -19,37 +19,37 @@ function encode(bytes, keyBytes) {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
function obfuscateNameUsingKey(name, key) {
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
const encodedBytes = Buffer.from(name, 'utf-8')
|
|
23
|
+
const keyBytes = Buffer.from(key)
|
|
24
24
|
return encode(encodedBytes, keyBytes).toString('base64')
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
function deobfuscateNameUsingKey(name, key) {
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
const bytes = Buffer.from(name, 'base64')
|
|
29
|
+
const keyBytes = Buffer.from(key)
|
|
30
30
|
|
|
31
|
-
return encode(bytes, keyBytes).toString(
|
|
31
|
+
return encode(bytes, keyBytes).toString('utf-8')
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
function calculatePathHash(appName, pathName, referingPathHash) {
|
|
35
35
|
if (typeof referingPathHash === 'string') {
|
|
36
36
|
referingPathHash = parseInt(referingPathHash, 16)
|
|
37
37
|
}
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
const rotated = ((referingPathHash << 1) | (referingPathHash >>> 31)) >>> 0
|
|
39
|
+
const hash = getHash(appName, pathName)
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
const result = (rotated ^ hash) >>> 0
|
|
42
42
|
|
|
43
43
|
// This is a trick to pad it out to 8 chars regardless of length.
|
|
44
|
-
|
|
44
|
+
const retval = ('00000000' + result.toString(16)).substr(-8)
|
|
45
45
|
|
|
46
46
|
return retval
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
function getHash(appName, txName) {
|
|
50
|
-
|
|
50
|
+
const md5sum = crypto.createHash('md5')
|
|
51
51
|
md5sum.update(appName + ';' + txName, 'utf8')
|
|
52
|
-
|
|
52
|
+
let buf = md5sum.digest()
|
|
53
53
|
if (!(buf instanceof Buffer)) {
|
|
54
54
|
buf = Buffer.from(buf)
|
|
55
55
|
}
|
|
@@ -66,10 +66,10 @@ function randInt32() {
|
|
|
66
66
|
|
|
67
67
|
function int32ToByteArray(int32) {
|
|
68
68
|
// we want to represent the input as a 4-bytes array
|
|
69
|
-
|
|
69
|
+
const byteArray = new Uint8Array(4)
|
|
70
70
|
|
|
71
71
|
for (let i = 0; i < byteArray.length; i++) {
|
|
72
|
-
|
|
72
|
+
const byte = int32 & 0xff
|
|
73
73
|
byteArray[i] = byte
|
|
74
74
|
int32 = (int32 - byte) / 256
|
|
75
75
|
}
|
|
@@ -87,7 +87,7 @@ function makeId(length = 16) {
|
|
|
87
87
|
// length is number of hex characters, which multiplied by 4 is the number of
|
|
88
88
|
// bits, then divided by 8 is number of bytes. Or just divide by 2
|
|
89
89
|
const numBytes = Math.ceil(length / 2)
|
|
90
|
-
|
|
90
|
+
const randBytes = new Uint8Array(numBytes)
|
|
91
91
|
|
|
92
92
|
// Generate random bytes one 32-bit integer at a time
|
|
93
93
|
const numInts = Math.ceil(numBytes / 4) // 32 bit integers are 4 bytes
|
|
@@ -98,7 +98,7 @@ function makeId(length = 16) {
|
|
|
98
98
|
// This could "overflow" since we're iterating over the number of ints, which could
|
|
99
99
|
// be more data than needed. But out-of-bound index assignment on typed arrays are
|
|
100
100
|
// discarded
|
|
101
|
-
randBytes[
|
|
101
|
+
randBytes[i * 4 + j] = bytes[j]
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
|