newrelic 8.3.0 → 8.5.2
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 +76 -0
- package/README.md +7 -6
- package/THIRD_PARTY_NOTICES.md +95 -35
- package/api.js +74 -68
- package/bin/test-naming-rules.js +22 -22
- package/lib/agent.js +4 -4
- package/lib/attributes.js +2 -2
- package/lib/collector/api.js +12 -12
- package/lib/collector/facts.js +1 -1
- package/lib/collector/http-agents.js +12 -11
- package/lib/collector/key-parser.js +1 -1
- package/lib/collector/remote-method.js +27 -26
- package/lib/config/attribute-filter.js +23 -23
- package/lib/config/default.js +12 -10
- package/lib/config/hsm.js +1 -1
- package/lib/config/index.js +82 -66
- package/lib/config/lasp.js +3 -3
- package/lib/config/merge-server-config.js +1 -1
- package/lib/db/parse-sql.js +8 -8
- package/lib/db/parsed-statement.js +9 -8
- package/lib/db/query-parsers/sql.js +7 -7
- package/lib/db/query-sample.js +9 -9
- package/lib/db/query-trace-aggregator.js +4 -4
- package/lib/db/statement-matcher.js +5 -5
- package/lib/db/utils.js +1 -1
- package/lib/environment.js +43 -43
- package/lib/errors/error-collector.js +2 -2
- package/lib/errors/error-trace-aggregator.js +1 -1
- package/lib/errors/helper.js +3 -3
- package/lib/errors/index.js +17 -17
- package/lib/feature_flags.js +7 -5
- package/lib/header-attributes.js +6 -6
- package/lib/header-processing.js +1 -1
- package/lib/instrumentation/amqplib.js +26 -26
- package/lib/instrumentation/bluebird.js +3 -3
- package/lib/instrumentation/cassandra-driver.js +7 -3
- package/lib/instrumentation/connect.js +4 -4
- package/lib/instrumentation/core/async_hooks.js +6 -6
- package/lib/instrumentation/core/domain.js +2 -2
- package/lib/instrumentation/core/globals.js +1 -1
- package/lib/instrumentation/core/http-outbound.js +15 -84
- package/lib/instrumentation/core/http.js +34 -67
- package/lib/instrumentation/core/inspector.js +2 -2
- package/lib/instrumentation/core/timers.js +7 -7
- package/lib/instrumentation/core/zlib.js +2 -2
- package/lib/instrumentation/director.js +4 -4
- package/lib/instrumentation/express.js +8 -8
- package/lib/instrumentation/fastify/spec-builders.js +57 -47
- package/lib/instrumentation/fastify.js +85 -24
- package/lib/instrumentation/generic-pool.js +1 -1
- package/lib/instrumentation/hapi/hapi-17.js +11 -11
- package/lib/instrumentation/hapi/shared.js +1 -1
- package/lib/instrumentation/hapi.js +22 -22
- package/lib/instrumentation/ioredis.js +7 -7
- package/lib/instrumentation/memcached.js +7 -7
- package/lib/instrumentation/mongodb/common.js +16 -5
- package/lib/instrumentation/mysql.js +19 -19
- package/lib/instrumentation/oracle.js +15 -15
- package/lib/instrumentation/pg.js +4 -4
- package/lib/instrumentation/promise.js +46 -46
- package/lib/instrumentation/q.js +2 -2
- package/lib/instrumentation/redis.js +11 -11
- package/lib/instrumentation/restify.js +1 -1
- package/lib/instrumentation/undici.js +242 -0
- package/lib/instrumentation/vision.js +4 -4
- package/lib/instrumentation/when.js +3 -3
- package/lib/instrumentations.js +2 -1
- package/lib/logger.js +5 -5
- package/lib/metrics/index.js +15 -15
- package/lib/metrics/mapper.js +7 -7
- package/lib/metrics/normalizer/rule.js +9 -9
- package/lib/metrics/normalizer/tx_segment.js +17 -17
- package/lib/metrics/normalizer.js +22 -22
- package/lib/metrics/recorders/custom.js +5 -5
- package/lib/metrics/recorders/generic.js +3 -3
- package/lib/metrics/recorders/http.js +7 -7
- package/lib/metrics/recorders/http_external.js +7 -7
- package/lib/metrics/recorders/message-transaction.js +5 -6
- package/lib/metrics/recorders/other.js +5 -5
- package/lib/parse-proc-cpuinfo.js +25 -19
- package/lib/parse-proc-meminfo.js +8 -2
- package/lib/prioritized-attributes.js +2 -2
- package/lib/priority-queue.js +10 -10
- package/lib/reservoir.js +3 -3
- package/lib/sampler.js +26 -26
- package/lib/serverless/aws-lambda.js +8 -2
- package/lib/shim/datastore-shim.js +35 -32
- package/lib/shim/index.js +2 -2
- package/lib/shim/message-shim.js +47 -47
- package/lib/shim/promise-shim.js +1 -1
- package/lib/shim/shim.js +61 -61
- package/lib/shim/specs/index.js +3 -3
- package/lib/shim/transaction-shim.js +44 -192
- package/lib/shim/webframework-shim.js +52 -52
- package/lib/spans/span-event.js +1 -1
- package/lib/spans/streaming-span-attributes.js +1 -1
- package/lib/stats/apdex.js +2 -2
- package/lib/stats/index.js +2 -2
- package/lib/system-info.js +23 -23
- package/lib/timer.js +5 -5
- package/lib/transaction/dt-payload.js +1 -1
- package/lib/transaction/index.js +40 -40
- package/lib/transaction/name-state.js +14 -14
- package/lib/transaction/trace/exclusive-time-calculator.js +6 -6
- package/lib/transaction/trace/index.js +14 -14
- package/lib/transaction/trace/segment.js +18 -18
- package/lib/transaction/tracecontext.js +1 -1
- package/lib/transaction/tracer/index.js +53 -49
- package/lib/uninstrumented.js +7 -7
- package/lib/util/arity.js +2 -2
- package/lib/util/byte-limit.js +4 -4
- package/lib/util/cat.js +269 -24
- package/lib/util/codec.js +2 -2
- package/lib/util/copy.js +2 -2
- package/lib/util/deep-equal.js +10 -10
- package/lib/util/flatten.js +4 -4
- package/lib/util/hashes.js +14 -14
- package/lib/util/label-parser.js +17 -17
- package/lib/util/logger.js +24 -24
- package/lib/util/process-version.js +2 -2
- package/lib/util/properties.js +4 -4
- package/lib/util/sql/obfuscate.js +15 -15
- package/lib/util/stream-sink.js +3 -3
- package/lib/util/unwrapped-core.js +2 -2
- package/lib/util/urltils.js +16 -16
- package/lib/utilization/aws-info.js +7 -7
- package/lib/utilization/azure-info.js +6 -6
- package/lib/utilization/common.js +13 -13
- package/lib/utilization/docker-info.js +11 -11
- package/lib/utilization/gcp-info.js +4 -4
- package/lib/utilization/index.js +5 -5
- package/lib/utilization/pcf-info.js +9 -9
- package/package.json +13 -6
- package/stub_api.js +8 -8
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2021 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
const cat = require('../util/cat')
|
|
9
|
+
const recordExternal = require('../metrics/recorders/http_external')
|
|
10
|
+
const logger = require('../logger').child({ component: 'undici' })
|
|
11
|
+
const NAMES = require('../metrics/names')
|
|
12
|
+
const NEWRELIC_SYNTHETICS_HEADER = 'x-newrelic-synthetics'
|
|
13
|
+
const SYMBOLS = {
|
|
14
|
+
SEGMENT: Symbol('__NR_segment'),
|
|
15
|
+
PARENT_SEGMENT: Symbol('__NR_parent_segment')
|
|
16
|
+
}
|
|
17
|
+
const { executionAsyncResource } = require('async_hooks')
|
|
18
|
+
|
|
19
|
+
let diagnosticsChannel = null
|
|
20
|
+
try {
|
|
21
|
+
diagnosticsChannel = require('diagnostics_channel')
|
|
22
|
+
} catch (e) {
|
|
23
|
+
// quick check to see if module exists
|
|
24
|
+
// module was not added until v15.x
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = function addUndiciChannels(agent, undici, modName, shim) {
|
|
28
|
+
if (!diagnosticsChannel || !agent.config.feature_flag.undici_instrumentation) {
|
|
29
|
+
logger.warn(
|
|
30
|
+
'diagnostics_channel or feature_flag.undici_instrumentation = false. Skipping undici instrumentation.'
|
|
31
|
+
)
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Retrieves the current segment in transaction(parent in our context) from executionAsyncResource
|
|
37
|
+
* or from `shim.getSegment()` then adds to the executionAsyncResource for future
|
|
38
|
+
* undici requests within same async context.
|
|
39
|
+
*
|
|
40
|
+
* It was found that when running concurrent undici requests
|
|
41
|
+
* within a transaction that the parent segment would get out of sync
|
|
42
|
+
* depending on the async context of the transaction. By using
|
|
43
|
+
* `async_hooks.executionResource` it is more reliable.
|
|
44
|
+
*
|
|
45
|
+
* Note: However, if you have concurrent undici requests in a transaction
|
|
46
|
+
* and the request to the transaction is using a keep alive there is a chance the
|
|
47
|
+
* executionAsyncResource may be incorrect because of shared connections. To revert to a more
|
|
48
|
+
* naive tracking of parent set `config.feature_flag.undici_async_tracking: false` and
|
|
49
|
+
* it will just call `shim.getSegment()`
|
|
50
|
+
*/
|
|
51
|
+
function getParentSegment() {
|
|
52
|
+
if (agent.config.feature_flag.undici_async_tracking) {
|
|
53
|
+
const resource = executionAsyncResource()
|
|
54
|
+
|
|
55
|
+
if (!resource[SYMBOLS.PARENT_SEGMENT]) {
|
|
56
|
+
const parent = shim.getSegment()
|
|
57
|
+
resource[SYMBOLS.PARENT_SEGMENT] = parent
|
|
58
|
+
}
|
|
59
|
+
return resource[SYMBOLS.PARENT_SEGMENT]
|
|
60
|
+
}
|
|
61
|
+
return shim.getSegment()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* This event occurs after the Undici Request is created
|
|
66
|
+
* We will check current segment for opaque and also attach
|
|
67
|
+
* relevant headers to outgoing http request
|
|
68
|
+
*
|
|
69
|
+
* @param {object} params
|
|
70
|
+
* @param {object} params.request undici request object
|
|
71
|
+
*/
|
|
72
|
+
diagnosticsChannel.channel('undici:request:create').subscribe(({ request }) => {
|
|
73
|
+
const parent = getParentSegment()
|
|
74
|
+
request[SYMBOLS.PARENT_SEGMENT] = parent
|
|
75
|
+
if (!parent || (parent && parent.opaque)) {
|
|
76
|
+
logger.trace(
|
|
77
|
+
'Not capturing data for outbound request (%s) because parent segment opaque (%s)',
|
|
78
|
+
request.path,
|
|
79
|
+
parent && parent.name
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const transaction = parent.transaction
|
|
86
|
+
const outboundHeaders = Object.create(null)
|
|
87
|
+
if (agent.config.encoding_key && transaction.syntheticsHeader) {
|
|
88
|
+
outboundHeaders[NEWRELIC_SYNTHETICS_HEADER] = transaction.syntheticsHeader
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (agent.config.distributed_tracing.enabled) {
|
|
92
|
+
transaction.insertDistributedTraceHeaders(outboundHeaders)
|
|
93
|
+
} else if (agent.config.cross_application_tracer.enabled) {
|
|
94
|
+
cat.addCatHeaders(agent.config, transaction, outboundHeaders)
|
|
95
|
+
} else {
|
|
96
|
+
logger.trace('Both DT and CAT are disabled, not adding headers!')
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// eslint-disable-next-line guard-for-in
|
|
100
|
+
for (const key in outboundHeaders) {
|
|
101
|
+
request.addHeader(key, outboundHeaders[key])
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* This event occurs right before the data is written to the socket.
|
|
107
|
+
* Undici has some abstracted headers that are only created at this time, one
|
|
108
|
+
* is the `host` header which we need to name the Undici segment. So in this
|
|
109
|
+
* handler we create, start and set the segment active, name it, and
|
|
110
|
+
* attach the url/procedure/request.parameters
|
|
111
|
+
*
|
|
112
|
+
* @param {object} params
|
|
113
|
+
* @param {object} params.request undicie request object
|
|
114
|
+
* @param {TLSSocket | net.Socket} socket active socket connection
|
|
115
|
+
*/
|
|
116
|
+
diagnosticsChannel.channel('undici:client:sendHeaders').subscribe(({ request, socket }) => {
|
|
117
|
+
const parentSegment = request[SYMBOLS.PARENT_SEGMENT]
|
|
118
|
+
if (!parentSegment || (parentSegment && parentSegment.opaque)) {
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const port = socket.remotePort
|
|
123
|
+
const isHttps = socket.servername
|
|
124
|
+
let urlString
|
|
125
|
+
if (isHttps) {
|
|
126
|
+
urlString = `https://${socket.servername}`
|
|
127
|
+
urlString += port === 443 ? request.path : `:${port}${request.path}`
|
|
128
|
+
} else {
|
|
129
|
+
urlString = `http://${socket._host}`
|
|
130
|
+
urlString += port === 80 ? request.path : `:${port}${request.path}`
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const url = new URL(urlString)
|
|
134
|
+
|
|
135
|
+
const name = NAMES.EXTERNAL.PREFIX + url.host + url.pathname
|
|
136
|
+
const segment = shim.createSegment(name, recordExternal(url.host, 'undici'), parentSegment)
|
|
137
|
+
if (segment) {
|
|
138
|
+
segment.start()
|
|
139
|
+
shim.setActiveSegment(segment)
|
|
140
|
+
segment.addAttribute('url', `${url.protocol}//${url.host}${url.pathname}`)
|
|
141
|
+
|
|
142
|
+
url.searchParams.forEach((value, key) => {
|
|
143
|
+
segment.addSpanAttribute(`request.parameters.${key}`, value)
|
|
144
|
+
})
|
|
145
|
+
segment.addAttribute('procedure', request.method || 'GET')
|
|
146
|
+
request[SYMBOLS.SEGMENT] = segment
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* This event occurs after the response headers have been received.
|
|
152
|
+
* We will add the relevant http response attributes to active segment.
|
|
153
|
+
* Also add CAT specific keys to active segment.
|
|
154
|
+
*
|
|
155
|
+
* @param {object} params
|
|
156
|
+
* @param {object} params.request undici request object
|
|
157
|
+
* @param {object} params.response { statusCode, headers, statusText }
|
|
158
|
+
*/
|
|
159
|
+
diagnosticsChannel.channel('undici:request:headers').subscribe(({ request, response }) => {
|
|
160
|
+
const activeSegment = request[SYMBOLS.SEGMENT]
|
|
161
|
+
if (!activeSegment) {
|
|
162
|
+
return
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
activeSegment.addSpanAttribute('http.statusCode', response.statusCode)
|
|
166
|
+
activeSegment.addSpanAttribute('http.statusText', response.statusText)
|
|
167
|
+
|
|
168
|
+
if (
|
|
169
|
+
agent.config.cross_application_tracer.enabled &&
|
|
170
|
+
!agent.config.distributed_tracing.enabled
|
|
171
|
+
) {
|
|
172
|
+
try {
|
|
173
|
+
const { appData } = cat.extractCatHeaders(response.headers)
|
|
174
|
+
const decodedAppData = cat.parseAppData(agent.config, appData)
|
|
175
|
+
const attrs = activeSegment.getAttributes()
|
|
176
|
+
const url = new URL(attrs.url)
|
|
177
|
+
cat.assignCatToSegment(decodedAppData, activeSegment, url.host)
|
|
178
|
+
} catch (err) {
|
|
179
|
+
logger.warn(err, 'Cannot add CAT data to segment')
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* This event occurs after the response body has been received.
|
|
186
|
+
* We will end the active segment and set the active back to parent before request
|
|
187
|
+
*
|
|
188
|
+
* @param {object} params.request undici request object
|
|
189
|
+
*/
|
|
190
|
+
diagnosticsChannel.channel('undici:request:trailers').subscribe(({ request }) => {
|
|
191
|
+
endAndRestoreSegment(request)
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* This event occurs right before the request emits an error.
|
|
196
|
+
* We will end the active segment and set the active back to parent before request.
|
|
197
|
+
* We will also log errors to NR
|
|
198
|
+
*
|
|
199
|
+
* Note: This event occurs before the error handler so we will always log it for now.
|
|
200
|
+
*/
|
|
201
|
+
diagnosticsChannel.channel('undici:request:error').subscribe(({ request, error }) => {
|
|
202
|
+
endAndRestoreSegment(request, error)
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Gets the active and parent from given ctx(request, client connector)
|
|
207
|
+
* and ends active and restores parent to active. If an error exists
|
|
208
|
+
* it will add the error to the transaction
|
|
209
|
+
*
|
|
210
|
+
* @param {object} ctx request or client connector
|
|
211
|
+
* @param {Error} error
|
|
212
|
+
*/
|
|
213
|
+
function endAndRestoreSegment(ctx, error) {
|
|
214
|
+
const activeSegment = ctx[SYMBOLS.SEGMENT]
|
|
215
|
+
const parentSegment = ctx[SYMBOLS.PARENT_SEGMENT]
|
|
216
|
+
if (activeSegment) {
|
|
217
|
+
activeSegment.end()
|
|
218
|
+
|
|
219
|
+
if (error) {
|
|
220
|
+
handleError(activeSegment, error)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (parentSegment) {
|
|
224
|
+
shim.setActiveSegment(parentSegment)
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Adds the error to the active transaction
|
|
231
|
+
*
|
|
232
|
+
* @param {TraceSegment} activeSegment
|
|
233
|
+
* @param {Error} error
|
|
234
|
+
*/
|
|
235
|
+
function handleError(activeSegment, error) {
|
|
236
|
+
logger.trace(error, 'Captured outbound error on behalf of the user.')
|
|
237
|
+
const tx = activeSegment.transaction
|
|
238
|
+
shim.agent.errors.add(tx, error)
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
module.exports.SYMBOLS = SYMBOLS
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const semver = require('semver')
|
|
9
9
|
|
|
10
10
|
module.exports = function initialize(agent, vision, moduleName, shim) {
|
|
11
|
-
|
|
11
|
+
const plugin = vision.plugin
|
|
12
12
|
|
|
13
13
|
if (!plugin || !plugin.pkg || semver.lt(plugin.pkg.version, '5.0.0')) {
|
|
14
14
|
shim.logger.debug('Vision instrumentation requires v5 or greater, not instrumenting')
|
|
@@ -22,7 +22,7 @@ module.exports = function initialize(agent, vision, moduleName, shim) {
|
|
|
22
22
|
return function wrappedRegister(server) {
|
|
23
23
|
shim.wrap(server, 'decorate', wrapDecorate)
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
const ret = register.apply(this, arguments)
|
|
26
26
|
|
|
27
27
|
shim.unwrapOnce(server, 'decorate')
|
|
28
28
|
|
|
@@ -37,7 +37,7 @@ function wrapDecorate(shim, decorate) {
|
|
|
37
37
|
return decorate.apply(this, arguments)
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
const args = shim.argsToArray.apply(shim, arguments)
|
|
41
41
|
args[2] = shim.recordRender(handler, { promise: true })
|
|
42
42
|
|
|
43
43
|
return decorate.apply(this, args)
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const promInit = require('./promise')
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
const STATIC_PROMISE_METHODS = [
|
|
11
11
|
'reject',
|
|
12
12
|
'resolve',
|
|
13
13
|
'all',
|
|
@@ -19,7 +19,7 @@ var STATIC_PROMISE_METHODS = [
|
|
|
19
19
|
'reduceRight'
|
|
20
20
|
]
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
const WHEN_SPEC = {
|
|
23
23
|
name: 'when',
|
|
24
24
|
constructor: 'Promise',
|
|
25
25
|
executor: true,
|
package/lib/instrumentations.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const MODULE_TYPE = require('./shim/constants').MODULE_TYPE
|
|
9
9
|
|
|
10
10
|
// Return a new copy of this array every time we're called
|
|
11
11
|
module.exports = function instrumentations() {
|
|
@@ -31,6 +31,7 @@ module.exports = function instrumentations() {
|
|
|
31
31
|
'redis': { type: MODULE_TYPE.DATASTORE },
|
|
32
32
|
'restify': { type: MODULE_TYPE.WEB_FRAMEWORK },
|
|
33
33
|
'superagent': { module: '@newrelic/superagent' },
|
|
34
|
+
'undici': { type: MODULE_TYPE.TRANSACTION },
|
|
34
35
|
'oracle': { type: null },
|
|
35
36
|
'vision': { type: MODULE_TYPE.WEB_FRAMEWORK },
|
|
36
37
|
'when': { type: null }
|
package/lib/logger.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const Logger = require('./util/logger')
|
|
9
|
+
const fs = require('./util/unwrapped-core').fs
|
|
10
10
|
|
|
11
11
|
// create bootstrapping logger
|
|
12
12
|
module.exports = new Logger({
|
|
@@ -20,9 +20,9 @@ module.exports = new Logger({
|
|
|
20
20
|
* module, and if it gets loaded too early, module.exports will have no
|
|
21
21
|
* value.
|
|
22
22
|
*/
|
|
23
|
-
|
|
23
|
+
const config = require('./config').getOrCreateInstance()
|
|
24
24
|
if (config) {
|
|
25
|
-
|
|
25
|
+
const options = {
|
|
26
26
|
name: 'newrelic',
|
|
27
27
|
level: config.logging.level,
|
|
28
28
|
enabled: config.logging.enabled
|
|
@@ -32,7 +32,7 @@ if (config) {
|
|
|
32
32
|
module.exports = new Logger(options)
|
|
33
33
|
|
|
34
34
|
if (config.logging.enabled) {
|
|
35
|
-
|
|
35
|
+
let stream
|
|
36
36
|
switch (config.logging.filepath) {
|
|
37
37
|
case 'stdout':
|
|
38
38
|
stream = process.stdout
|
package/lib/metrics/index.js
CHANGED
|
@@ -82,7 +82,7 @@ function Metrics(apdexT, mapper, normalizer) {
|
|
|
82
82
|
Metrics.prototype.measureMilliseconds = measureMilliseconds
|
|
83
83
|
|
|
84
84
|
function measureMilliseconds(name, scope, duration, exclusive) {
|
|
85
|
-
|
|
85
|
+
const stats = this.getOrCreateMetric(name, scope)
|
|
86
86
|
stats.recordValueInMillis(duration, exclusive)
|
|
87
87
|
return stats
|
|
88
88
|
}
|
|
@@ -96,7 +96,7 @@ function measureMilliseconds(name, scope, duration, exclusive) {
|
|
|
96
96
|
* @return {Stats} The aggregated data related to this metric.
|
|
97
97
|
*/
|
|
98
98
|
Metrics.prototype.measureBytes = function measureBytes(name, size) {
|
|
99
|
-
|
|
99
|
+
const stats = this.getOrCreateMetric(name)
|
|
100
100
|
stats.recordValueInBytes(size)
|
|
101
101
|
return stats
|
|
102
102
|
}
|
|
@@ -110,8 +110,8 @@ Metrics.prototype.measureBytes = function measureBytes(name, size) {
|
|
|
110
110
|
* @return {Stats} The aggregated data for that name.
|
|
111
111
|
*/
|
|
112
112
|
Metrics.prototype.getOrCreateMetric = function getOrCreateMetric(name, scope) {
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
const resolved = this._resolve(scope)
|
|
114
|
+
let stats = resolved[name]
|
|
115
115
|
if (!stats) {
|
|
116
116
|
this.empty = false
|
|
117
117
|
stats = resolved[name] = new Stats()
|
|
@@ -141,14 +141,14 @@ function getOrCreateApdexMetric(name, scope, overrideApdex) {
|
|
|
141
141
|
throw new Error('Metrics must be named')
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
|
|
144
|
+
const resolved = this._resolve(scope)
|
|
145
145
|
|
|
146
146
|
if (!resolved[name]) {
|
|
147
147
|
this.empty = false
|
|
148
148
|
|
|
149
149
|
// Only use the given override to create the metric if this is not the
|
|
150
150
|
// global apdex AND we have a valid value.
|
|
151
|
-
|
|
151
|
+
const apdexT =
|
|
152
152
|
name !== NAMES.APDEX && overrideApdex > 0 ? overrideApdex * FROM_MILLIS : this.apdexT
|
|
153
153
|
resolved[name] = new ApdexStats(apdexT)
|
|
154
154
|
}
|
|
@@ -209,12 +209,12 @@ Metrics.prototype.merge = function merge(other, adjustStartTime) {
|
|
|
209
209
|
// Loop through all scopes and merge them. Since we know `.scoped` has a `null`
|
|
210
210
|
// prototype we don't need to worry about own property checks.
|
|
211
211
|
// eslint-disable-next-line guard-for-in
|
|
212
|
-
for (
|
|
212
|
+
for (const scope in other.scoped) {
|
|
213
213
|
_merge(this._resolve(scope), other.scoped[scope])
|
|
214
214
|
}
|
|
215
215
|
}
|
|
216
216
|
function _merge(a, b) {
|
|
217
|
-
for (
|
|
217
|
+
for (const name in b) {
|
|
218
218
|
if (a[name]) {
|
|
219
219
|
a[name].merge(b[name])
|
|
220
220
|
} else {
|
|
@@ -232,7 +232,7 @@ function _merge(a, b) {
|
|
|
232
232
|
* un-scoped metrics if the scope isn't set.
|
|
233
233
|
*/
|
|
234
234
|
Metrics.prototype._resolve = function _resolve(scope) {
|
|
235
|
-
|
|
235
|
+
let resolved = this.unscoped
|
|
236
236
|
|
|
237
237
|
if (scope) {
|
|
238
238
|
resolved = this.scoped[scope]
|
|
@@ -255,7 +255,7 @@ Metrics.prototype._getUnscopedData = function _getUnscopedData(name) {
|
|
|
255
255
|
return
|
|
256
256
|
}
|
|
257
257
|
|
|
258
|
-
|
|
258
|
+
const normalized = this.normalizer.normalize(name)
|
|
259
259
|
if (normalized.ignore || !normalized.value) {
|
|
260
260
|
return
|
|
261
261
|
}
|
|
@@ -274,7 +274,7 @@ Metrics.prototype._getScopedData = function _getScopedData(name, scope) {
|
|
|
274
274
|
return
|
|
275
275
|
}
|
|
276
276
|
|
|
277
|
-
|
|
277
|
+
const normalized = this.normalizer.normalize(name)
|
|
278
278
|
if (normalized.ignore || !normalized.value) {
|
|
279
279
|
return
|
|
280
280
|
}
|
|
@@ -287,10 +287,10 @@ Metrics.prototype._getScopedData = function _getScopedData(name, scope) {
|
|
|
287
287
|
* for use by toJSON.
|
|
288
288
|
*/
|
|
289
289
|
Metrics.prototype._toUnscopedData = function _toUnscopedData() {
|
|
290
|
-
|
|
290
|
+
const metricData = []
|
|
291
291
|
|
|
292
292
|
Object.keys(this.unscoped).forEach((name) => {
|
|
293
|
-
|
|
293
|
+
const data = this._getUnscopedData(name)
|
|
294
294
|
if (data) {
|
|
295
295
|
metricData.push(data)
|
|
296
296
|
}
|
|
@@ -304,11 +304,11 @@ Metrics.prototype._toUnscopedData = function _toUnscopedData() {
|
|
|
304
304
|
* use by toJSON.
|
|
305
305
|
*/
|
|
306
306
|
Metrics.prototype._toScopedData = function _toScopedData() {
|
|
307
|
-
|
|
307
|
+
const metricData = []
|
|
308
308
|
|
|
309
309
|
Object.keys(this.scoped).forEach(function forEachScope(scope) {
|
|
310
310
|
Object.keys(this.scoped[scope]).forEach(function forEachMetric(name) {
|
|
311
|
-
|
|
311
|
+
const data = this._getScopedData(name, scope)
|
|
312
312
|
if (data) {
|
|
313
313
|
metricData.push(data)
|
|
314
314
|
}
|
package/lib/metrics/mapper.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const logger = require('../logger').child({ component: 'mapper' })
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* To tighten up the metrics JSON, the collector will maintain a list of
|
|
@@ -41,12 +41,12 @@ MetricMapper.prototype.load = function load(raw) {
|
|
|
41
41
|
return
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
for (
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
for (let i = 0; i < raw.length; i++) {
|
|
45
|
+
const spec = raw[i][0]
|
|
46
|
+
const scope = spec.scope
|
|
47
|
+
const name = spec.name
|
|
48
|
+
const id = raw[i][1]
|
|
49
|
+
let resolved
|
|
50
50
|
|
|
51
51
|
if (scope) {
|
|
52
52
|
if (!this.scoped[scope]) {
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const logger = require('../../logger').child({ component: 'normalizer_rule' })
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* JavaScript just has to do things slightly differently.
|
|
12
12
|
*/
|
|
13
|
-
|
|
13
|
+
const replaceReplacer = function replaceReplacer(input) {
|
|
14
14
|
return input.replace(/\\/g, '$')
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -37,7 +37,7 @@ function NormalizerRule(json) {
|
|
|
37
37
|
this.ignore = json.ignore || false
|
|
38
38
|
this.matched = false
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
let modifiers = 'i'
|
|
41
41
|
if (this.replaceAll) {
|
|
42
42
|
modifiers += 'g'
|
|
43
43
|
}
|
|
@@ -78,9 +78,9 @@ NormalizerRule.prototype.getSegments = function getSegments(input) {
|
|
|
78
78
|
* @return {bool} - True if this rule matches the given input, otherwise false.
|
|
79
79
|
*/
|
|
80
80
|
NormalizerRule.prototype.matches = function matches(input) {
|
|
81
|
-
|
|
81
|
+
const segments = this.getSegments(input)
|
|
82
82
|
|
|
83
|
-
for (
|
|
83
|
+
for (let i = 0; i < segments.length; ++i) {
|
|
84
84
|
if (this.pattern.test(segments[i])) {
|
|
85
85
|
return true
|
|
86
86
|
}
|
|
@@ -118,7 +118,7 @@ NormalizerRule.prototype.apply = function apply(input) {
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
this.matched = false
|
|
121
|
-
|
|
121
|
+
const result = this.getSegments(input)
|
|
122
122
|
.map(function applyMap(segment) {
|
|
123
123
|
// Discussion of why we use `lastIndex` in function documentation to
|
|
124
124
|
// prevent de-opt due to long function.
|
|
@@ -154,9 +154,9 @@ NormalizerRule.prototype.toJSON = function toJSON() {
|
|
|
154
154
|
* @return {RegExp} - A regular expression with all the given flags added.
|
|
155
155
|
*/
|
|
156
156
|
function _addRegExpFlags(re, flags) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
for (
|
|
157
|
+
let foundMissing = false
|
|
158
|
+
let reFlags = re.flags
|
|
159
|
+
for (let i = 0; i < flags.length; ++i) {
|
|
160
160
|
if (reFlags.indexOf(flags[i]) === -1) {
|
|
161
161
|
foundMissing = true
|
|
162
162
|
reFlags += flags[i]
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const logger = require('../../logger').child({ component: 'tx_segment_normalizer' })
|
|
9
9
|
|
|
10
10
|
module.exports = TxSegmentNormalizer
|
|
11
11
|
|
|
@@ -33,21 +33,21 @@ function TxSegmentNormalizer() {
|
|
|
33
33
|
* @return {NormalizationResults} - The results of normalizing the given path.
|
|
34
34
|
*/
|
|
35
35
|
TxSegmentNormalizer.prototype.normalize = function normalize(path) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
for (
|
|
36
|
+
let currentTerm
|
|
37
|
+
let prefix
|
|
38
|
+
for (let i = 0; i < this.terms.length; i++) {
|
|
39
39
|
currentTerm = this.terms[i]
|
|
40
40
|
prefix = currentTerm.prefix
|
|
41
41
|
if (path.lastIndexOf(prefix, 0) === -1) {
|
|
42
42
|
continue
|
|
43
43
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
const fragment = path.slice(prefix.length)
|
|
45
|
+
const parts = fragment.split('/')
|
|
46
|
+
const result = []
|
|
47
|
+
let prev
|
|
48
|
+
let segment
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
for (var j = 0; j < parts.length; j++) {
|
|
50
|
+
for (let j = 0; j < parts.length; j++) {
|
|
51
51
|
segment = parts[j]
|
|
52
52
|
|
|
53
53
|
if (segment === '' && j + 1 === parts.length) {
|
|
@@ -87,10 +87,10 @@ TxSegmentNormalizer.prototype.load = function load(json) {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
function filterRules(rules) {
|
|
90
|
-
|
|
90
|
+
const map = Object.create(null)
|
|
91
91
|
|
|
92
|
-
for (
|
|
93
|
-
|
|
92
|
+
for (let i = 0, l = rules.length; i < l; ++i) {
|
|
93
|
+
let prefix = rules[i].prefix
|
|
94
94
|
|
|
95
95
|
if (!prefix || typeof prefix !== 'string') {
|
|
96
96
|
continue
|
|
@@ -101,7 +101,7 @@ function filterRules(rules) {
|
|
|
101
101
|
rules[i].prefix = prefix
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
const segments = prefix.split('/')
|
|
105
105
|
if (segments.length !== 3 || !segments[0] || !segments[1] || segments[3]) {
|
|
106
106
|
continue
|
|
107
107
|
}
|
|
@@ -111,10 +111,10 @@ function filterRules(rules) {
|
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
const keys = Object.keys(map)
|
|
115
|
+
const filtered = new Array(keys.length)
|
|
116
116
|
|
|
117
|
-
for (i = 0, l = keys.length; i < l; ++i) {
|
|
117
|
+
for (let i = 0, l = keys.length; i < l; ++i) {
|
|
118
118
|
filtered[i] = map[keys[i]]
|
|
119
119
|
}
|
|
120
120
|
|