newrelic 9.7.0 → 9.7.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 +42 -18
- package/THIRD_PARTY_NOTICES.md +203 -2
- package/api.js +155 -103
- package/lib/agent.js +29 -82
- package/lib/collector/api.js +234 -201
- package/lib/config/attribute-filter.js +35 -25
- package/lib/config/default.js +45 -19
- package/lib/config/index.js +260 -199
- package/lib/environment.js +16 -12
- package/lib/errors/error-collector.js +124 -55
- package/lib/errors/index.js +59 -49
- package/lib/instrumentation/@hapi/hapi.js +56 -50
- package/lib/instrumentation/@node-redis/client.js +50 -41
- package/lib/instrumentation/amqplib.js +116 -151
- package/lib/instrumentation/core/{async_hooks.js → async-hooks.js} +26 -11
- package/lib/instrumentation/core/globals.js +1 -1
- package/lib/instrumentation/core/http-outbound.js +193 -78
- package/lib/instrumentation/core/timers.js +106 -59
- package/lib/instrumentation/grpc-js/grpc.js +20 -23
- package/lib/instrumentation/mongodb/common.js +87 -85
- package/lib/instrumentation/redis.js +112 -90
- package/lib/instrumentation/undici.js +204 -192
- package/lib/instrumentation/{when.js → when/constants.js} +13 -10
- package/lib/instrumentation/when/contextualizer.js +168 -0
- package/lib/instrumentation/when/index.js +354 -0
- package/lib/instrumentation/when/nr-hooks.js +15 -0
- package/lib/instrumentations.js +1 -1
- package/lib/shim/shim.js +2 -0
- package/lib/shim/webframework-shim.js +19 -0
- package/lib/symbols.js +1 -0
- package/lib/system-info.js +240 -163
- package/lib/util/async-each-limit.js +30 -0
- package/lib/util/attributes.js +159 -0
- package/lib/util/code-level-metrics.js +58 -0
- package/lib/util/deep-equal.js +11 -144
- package/package.json +5 -4
- package/lib/instrumentation/promise.js +0 -572
package/lib/system-info.js
CHANGED
|
@@ -5,113 +5,192 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const utilization = require('./utilization')
|
|
8
|
+
const util = require('util')
|
|
9
|
+
const execFile = util.promisify(require('child_process').execFile)
|
|
10
|
+
const readProc = util.promisify(require('./utilization/common').readProc)
|
|
11
|
+
const getBootId = util.promisify(require('./utilization/docker-info').getBootId)
|
|
12
|
+
const getVendors = util.promisify(require('./utilization').getVendors)
|
|
14
13
|
const logger = require('./logger.js').child({ component: 'system-info' })
|
|
15
14
|
const os = require('os')
|
|
16
15
|
const parseCpuInfo = require('./parse-proc-cpuinfo')
|
|
17
16
|
const parseMemInfo = require('./parse-proc-meminfo')
|
|
17
|
+
const Agent = require('./agent')
|
|
18
18
|
const platform = os.platform()
|
|
19
19
|
|
|
20
20
|
module.exports = fetchSystemInfo
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Helper method for determining if given value can be an integer
|
|
24
|
+
*
|
|
25
|
+
* @param {*} value the value to check
|
|
26
|
+
* @returns {boolean} whether or not the value can be coerced to an integer
|
|
27
|
+
*/
|
|
28
|
+
function isInteger(value) {
|
|
29
|
+
return value === parseInt(value, 10)
|
|
24
30
|
}
|
|
25
31
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Helper method for updating the utilization info with processor information from the config
|
|
34
|
+
*
|
|
35
|
+
* @param {*} processorConfig agent.config.utilization.logical_processors
|
|
36
|
+
* @param {object} utilizationConfig Utilization configuration object defined in #fetchSystemInfo
|
|
37
|
+
*/
|
|
38
|
+
function maybeAddProcessorUtilization(processorConfig, utilizationConfig) {
|
|
39
|
+
const parsedConfigProcessors = parseFloat(processorConfig, 10)
|
|
40
|
+
if (!isNaN(parsedConfigProcessors) && isInteger(parsedConfigProcessors)) {
|
|
41
|
+
utilizationConfig.logical_processors = parsedConfigProcessors
|
|
42
|
+
} else {
|
|
43
|
+
logger.info(
|
|
44
|
+
'%s supplied in config for utilization.logical_processors, expected a number',
|
|
45
|
+
processorConfig
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Helper method for updating the utilization info with RAM information from the config
|
|
52
|
+
*
|
|
53
|
+
* @param {*} ramConfig agent.config.utilization.total_ram_mib
|
|
54
|
+
* @param {object} utilizationConfig Utilization configuration object defined in #fetchSystemInfo
|
|
55
|
+
*/
|
|
56
|
+
function maybeAddRamUtilization(ramConfig, utilizationConfig) {
|
|
57
|
+
const parsedConfigRam = parseFloat(ramConfig, 10)
|
|
58
|
+
if (!isNaN(parsedConfigRam) && isInteger(parsedConfigRam)) {
|
|
59
|
+
utilizationConfig.total_ram_mib = parsedConfigRam
|
|
60
|
+
} else {
|
|
61
|
+
logger.info('%s supplied in config for utilization.total_ram_mib, expected a number', ramConfig)
|
|
30
62
|
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Helper method for updating the utilization info with hostname information from the config
|
|
67
|
+
*
|
|
68
|
+
* @param {*} configHostname agent.config.utilization.billing_hostname
|
|
69
|
+
* @param {object} utilizationConfig Utilization configuration object defined in #fetchSystemInfo
|
|
70
|
+
*/
|
|
71
|
+
function maybeAddHostUtilization(configHostname, utilizationConfig) {
|
|
72
|
+
if (typeof configHostname === 'string') {
|
|
73
|
+
utilizationConfig.hostname = configHostname
|
|
74
|
+
} else {
|
|
75
|
+
logger.info('%s supplied in config for utilization.Hostname, expected a string', configHostname)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
31
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Helper method for updating the system info with architecture dependent processor info
|
|
81
|
+
*
|
|
82
|
+
* @param {*} processorStats output of #getProcessorStats
|
|
83
|
+
* @param {object} systemInfo System Information object defined in #fetchSystemInfo
|
|
84
|
+
*/
|
|
85
|
+
function maybeSetProcessorStats(processorStats, systemInfo) {
|
|
86
|
+
if (processorStats) {
|
|
87
|
+
systemInfo.packages = processorStats.packages
|
|
88
|
+
systemInfo.logicalProcessors = processorStats.logical
|
|
89
|
+
systemInfo.cores = processorStats.cores
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Helper method for updating the system info with architecture dependent RAM info
|
|
95
|
+
*
|
|
96
|
+
* @param {*} memoryStats output of #getMemoryStats
|
|
97
|
+
* @param {object} systemInfo System Information object defined in #fetchSystemInfo
|
|
98
|
+
*/
|
|
99
|
+
function maybeSetMemoryStats(memoryStats, systemInfo) {
|
|
100
|
+
if (memoryStats) {
|
|
101
|
+
systemInfo.memory = memoryStats
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Helper method for updating the system info with architecture dependent Kernel info
|
|
107
|
+
*
|
|
108
|
+
* @param {*} kernelStats output of #getKernelVersion
|
|
109
|
+
* @param {object} systemInfo System Information object defined in #fetchSystemInfo
|
|
110
|
+
*/
|
|
111
|
+
function maybeSetKernelStats(kernelStats, systemInfo) {
|
|
112
|
+
if (kernelStats) {
|
|
113
|
+
systemInfo.kernelVersion = kernelStats
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Helper method for updating the system info with vendor info
|
|
119
|
+
*
|
|
120
|
+
* @param {*} vendorStats output of #utilization.getVendors
|
|
121
|
+
* @param {object} systemInfo System Information object defined in #fetchSystemInfo
|
|
122
|
+
*/
|
|
123
|
+
function maybeSetVendorStats(vendorStats, systemInfo) {
|
|
124
|
+
if (vendorStats) {
|
|
125
|
+
systemInfo.vendors = vendorStats
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Helper method for updating the system info with the Docker boot id
|
|
131
|
+
*
|
|
132
|
+
* @param {*} bootId output of #utilization/docker-info.getBootId
|
|
133
|
+
* @param {object} systemInfo System Information object defined in #fetchSystemInfo
|
|
134
|
+
*/
|
|
135
|
+
function maybeSetBootId(bootId, systemInfo) {
|
|
136
|
+
if (bootId) {
|
|
137
|
+
systemInfo.bootId = bootId
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Main method for retrieving system level statistics, used for fact gathering on Agent startup
|
|
143
|
+
*
|
|
144
|
+
* @param {Agent} agent Instantiation of Node.js agent
|
|
145
|
+
* @param {Function} callback Callback to fire after we've gathered all the necessary stats
|
|
146
|
+
*/
|
|
147
|
+
async function fetchSystemInfo(agent, callback) {
|
|
32
148
|
const utilizationConfig = Object.create(null)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const configHostname = config.utilization.billing_hostname
|
|
37
|
-
|
|
38
|
-
if (configProcessors) {
|
|
39
|
-
const parsedConfigProcessors = parseFloat(configProcessors, 10)
|
|
40
|
-
if (!isNaN(parsedConfigProcessors) && isInteger(parsedConfigProcessors)) {
|
|
41
|
-
utilizationConfig.logical_processors = parsedConfigProcessors
|
|
42
|
-
} else {
|
|
43
|
-
logger.info(
|
|
44
|
-
'%s supplied in config for utilization.logical_processors, expected a number',
|
|
45
|
-
configProcessors
|
|
46
|
-
)
|
|
47
|
-
}
|
|
48
|
-
}
|
|
149
|
+
const systemInfo = {
|
|
150
|
+
processorArch: os.arch()
|
|
151
|
+
}
|
|
49
152
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
} else {
|
|
55
|
-
logger.info(
|
|
56
|
-
'%s supplied in config for utilization.total_ram_mib, expected a number',
|
|
57
|
-
configRam
|
|
58
|
-
)
|
|
59
|
-
}
|
|
60
|
-
}
|
|
153
|
+
const processorConfig = agent.config.utilization?.logical_processors
|
|
154
|
+
if (processorConfig) {
|
|
155
|
+
maybeAddProcessorUtilization(processorConfig, utilizationConfig)
|
|
156
|
+
}
|
|
61
157
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
logger.info(
|
|
67
|
-
'%s supplied in config for utilization.Hostname, expected a string',
|
|
68
|
-
configHostname
|
|
69
|
-
)
|
|
70
|
-
}
|
|
71
|
-
}
|
|
158
|
+
const ramConfig = agent.config.utilization?.total_ram_mib
|
|
159
|
+
if (ramConfig) {
|
|
160
|
+
maybeAddRamUtilization(ramConfig, utilizationConfig)
|
|
161
|
+
}
|
|
72
162
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
163
|
+
const configHostname = agent.config.utilization?.billing_hostname
|
|
164
|
+
if (configHostname) {
|
|
165
|
+
maybeAddHostUtilization(configHostname, utilizationConfig)
|
|
76
166
|
}
|
|
77
167
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (++tasksDone === numTasks) {
|
|
81
|
-
callback(null, systemInfo)
|
|
82
|
-
}
|
|
168
|
+
if (Object.keys(utilizationConfig).length > 0) {
|
|
169
|
+
systemInfo.config = utilizationConfig
|
|
83
170
|
}
|
|
84
171
|
|
|
85
|
-
module.exports._getProcessorStats(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
})
|
|
99
|
-
utilization.getVendors(agent, function getVendorInfo(err, vendors) {
|
|
100
|
-
if (vendors) {
|
|
101
|
-
systemInfo.vendors = vendors
|
|
102
|
-
}
|
|
103
|
-
finishedResponse()
|
|
104
|
-
})
|
|
105
|
-
getBootId(agent, function reportBootId(err, bootId) {
|
|
106
|
-
if (bootId) {
|
|
107
|
-
systemInfo.bootId = bootId
|
|
108
|
-
}
|
|
109
|
-
finishedResponse()
|
|
110
|
-
})
|
|
172
|
+
const processorStats = await module.exports._getProcessorStats()
|
|
173
|
+
const memoryStats = await module.exports._getMemoryStats()
|
|
174
|
+
const kernelStats = await getKernelVersion()
|
|
175
|
+
const vendorStats = await getVendors(agent)
|
|
176
|
+
const bootId = await getBootId(agent)
|
|
177
|
+
|
|
178
|
+
maybeSetProcessorStats(processorStats, systemInfo)
|
|
179
|
+
maybeSetMemoryStats(memoryStats, systemInfo)
|
|
180
|
+
maybeSetKernelStats(kernelStats, systemInfo)
|
|
181
|
+
maybeSetVendorStats(vendorStats, systemInfo)
|
|
182
|
+
maybeSetBootId(bootId, systemInfo)
|
|
183
|
+
|
|
184
|
+
callback(null, systemInfo)
|
|
111
185
|
}
|
|
112
186
|
|
|
113
|
-
|
|
114
|
-
|
|
187
|
+
/**
|
|
188
|
+
* Helper method for getting detailed, architecture specific processor information from the system
|
|
189
|
+
* Exported for testing purposes
|
|
190
|
+
*
|
|
191
|
+
* @returns {*} null if unknown platform, otherwise the processor stats
|
|
192
|
+
*/
|
|
193
|
+
module.exports._getProcessorStats = async function getProcessorStats() {
|
|
115
194
|
const processorStats = {
|
|
116
195
|
logical: null,
|
|
117
196
|
cores: null,
|
|
@@ -119,101 +198,99 @@ module.exports._getProcessorStats = function getProcessorStats(callback) {
|
|
|
119
198
|
}
|
|
120
199
|
|
|
121
200
|
if (platform.match(/darwin/i)) {
|
|
122
|
-
getSysctlValue(['hw.packages']
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
for (const key in processorStats) {
|
|
132
|
-
if (!processorStats[key] || !isInteger(processorStats[key])) {
|
|
133
|
-
processorStats[key] = null
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
callback(processorStats)
|
|
138
|
-
}
|
|
139
|
-
)
|
|
140
|
-
})
|
|
141
|
-
})
|
|
201
|
+
const packages = await getSysctlValue(['hw.packages'])
|
|
202
|
+
const cores = await getSysctlValue(['hw.physicalcpu_max', 'hw.physicalcpu'])
|
|
203
|
+
const logical = await getSysctlValue(['hw.logicalcpu_max', 'hw.logicalcpu', 'hw.ncpu'])
|
|
204
|
+
|
|
205
|
+
processorStats.logical = isInteger(logical) ? parseFloat(logical, 10) : null
|
|
206
|
+
processorStats.cores = isInteger(cores) ? parseFloat(cores, 10) : null
|
|
207
|
+
processorStats.packages = isInteger(packages) ? parseFloat(packages, 10) : null
|
|
208
|
+
|
|
209
|
+
return processorStats
|
|
142
210
|
} else if (platform.match(/bsd/i)) {
|
|
143
|
-
getSysctlValue(['hw.ncpu']
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
211
|
+
const logical = await getSysctlValue(['hw.ncpu'])
|
|
212
|
+
|
|
213
|
+
processorStats.logical = logical
|
|
214
|
+
|
|
215
|
+
return processorStats
|
|
147
216
|
} else if (platform.match(/linux/i)) {
|
|
148
|
-
readProc('/proc/cpuinfo'
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
} else {
|
|
152
|
-
logger.debug('Unknown platform: %s; could not retrieve processor info', platform)
|
|
153
|
-
callback(processorStats)
|
|
217
|
+
const data = await readProc('/proc/cpuinfo')
|
|
218
|
+
|
|
219
|
+
return parseCpuInfo(data)
|
|
154
220
|
}
|
|
221
|
+
|
|
222
|
+
logger.debug('Unknown platform: %s; could not retrieve processor info', platform)
|
|
223
|
+
return processorStats
|
|
155
224
|
}
|
|
156
225
|
|
|
157
|
-
|
|
158
|
-
|
|
226
|
+
/**
|
|
227
|
+
* Helper method for getting detailed, architecture specific RAM information from the system
|
|
228
|
+
* Exported for testing purposes
|
|
229
|
+
*
|
|
230
|
+
* @returns {*} null if unknown platform, otherwise the RAM amount
|
|
231
|
+
*/
|
|
232
|
+
module.exports._getMemoryStats = async function getMemoryStats() {
|
|
159
233
|
if (platform.match(/darwin/i)) {
|
|
160
|
-
getSysctlValue(['hw.memsize']
|
|
161
|
-
|
|
162
|
-
})
|
|
234
|
+
const memory = await getSysctlValue(['hw.memsize'])
|
|
235
|
+
return parseInt(memory, 10) / (1024 * 1024)
|
|
163
236
|
} else if (platform.match(/bsd/i)) {
|
|
164
|
-
getSysctlValue(['hw.realmem']
|
|
165
|
-
|
|
166
|
-
})
|
|
237
|
+
const memory = await getSysctlValue(['hw.realmem'])
|
|
238
|
+
return parseInt(memory, 10) / (1024 * 1024)
|
|
167
239
|
} else if (platform.match(/linux/i)) {
|
|
168
|
-
readProc('/proc/meminfo'
|
|
169
|
-
|
|
170
|
-
})
|
|
171
|
-
} else {
|
|
172
|
-
logger.debug('Unknown platform: %s; could not retrieve memory info', platform)
|
|
173
|
-
callback(null)
|
|
240
|
+
const data = await readProc('/proc/meminfo')
|
|
241
|
+
return parseMemInfo(data)
|
|
174
242
|
}
|
|
243
|
+
|
|
244
|
+
logger.debug('Unknown platform: %s; could not retrieve memory info', platform)
|
|
245
|
+
return null
|
|
175
246
|
}
|
|
176
247
|
|
|
177
|
-
|
|
248
|
+
/**
|
|
249
|
+
* Helper method for retrieving Kernel version information for different platforms
|
|
250
|
+
*
|
|
251
|
+
* @returns {*} null if unknown platform, otherwise string representation of kernel version
|
|
252
|
+
*/
|
|
253
|
+
async function getKernelVersion() {
|
|
178
254
|
if (platform.match(/darwin/i) || platform.match(/bsd/i)) {
|
|
179
|
-
getSysctlValue(['kern.version']
|
|
180
|
-
callback(version)
|
|
181
|
-
})
|
|
255
|
+
return await getSysctlValue(['kern.version'])
|
|
182
256
|
} else if (platform.match(/linux/i)) {
|
|
183
|
-
readProc('/proc/version'
|
|
184
|
-
callback(data)
|
|
185
|
-
})
|
|
186
|
-
} else {
|
|
187
|
-
logger.debug('Unknown platform: %s; could not read kernel version', platform)
|
|
188
|
-
callback(null)
|
|
257
|
+
return await readProc('/proc/version')
|
|
189
258
|
}
|
|
259
|
+
|
|
260
|
+
logger.debug('Unknown platform: %s; could not read kernel version', platform)
|
|
261
|
+
return null
|
|
190
262
|
}
|
|
191
263
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
264
|
+
/**
|
|
265
|
+
* Helper method for getting sysctl information given a list of potential values to look up
|
|
266
|
+
* Returns the first successful sysctl's output
|
|
267
|
+
*
|
|
268
|
+
* @param {Array.<string>} names List of sysctl values to look up
|
|
269
|
+
* @returns {*} null if we failed to lookup any info (error or not), or the first successful sysctl's output
|
|
270
|
+
*/
|
|
271
|
+
async function getSysctlValue(names = []) {
|
|
272
|
+
let returnValue = null
|
|
200
273
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
if (++ran === names.length && !returned) {
|
|
214
|
-
logger.debug('No sysctl info found for names: %j', names)
|
|
215
|
-
callback(null)
|
|
274
|
+
for (const name of names) {
|
|
275
|
+
// returnValue being set means we already found what we were looking for, early exit for performance
|
|
276
|
+
if (returnValue) {
|
|
277
|
+
break
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
try {
|
|
281
|
+
const { stderr, stdout } = await execFile('sysctl', ['-n', name])
|
|
282
|
+
|
|
283
|
+
if (!stderr) {
|
|
284
|
+
returnValue = stdout
|
|
216
285
|
}
|
|
286
|
+
} catch (err) {
|
|
287
|
+
logger.debug('Error when trying to run: sysctl -n %s: %s', name, err.message)
|
|
217
288
|
}
|
|
218
|
-
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (returnValue === null) {
|
|
292
|
+
logger.debug('No sysctl info found for names: %j', names)
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return returnValue
|
|
219
296
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Helper method for limiting number of concurrent async executions to a certain limit
|
|
10
|
+
* Native replacement for async.eachLimit, fixes https://issues.newrelic.com/browse/NR-69739
|
|
11
|
+
*
|
|
12
|
+
* Shamelessly ripped off from https://github.com/nodejs/help/issues/2192#issuecomment-533730280
|
|
13
|
+
* and https://timtech.blog/posts/limiting-async-operations-promise-concurrency-javascript/
|
|
14
|
+
*
|
|
15
|
+
* @param {Array} items Array to iterate over
|
|
16
|
+
* @param {Function} fn the callback from Array.map you would normally write that contains an async operation
|
|
17
|
+
* @param {number} limit the maximum allowed concurrent invocations of `fn`
|
|
18
|
+
*/
|
|
19
|
+
async function eachLimit(items, fn, limit) {
|
|
20
|
+
const results = []
|
|
21
|
+
|
|
22
|
+
while (items.length) {
|
|
23
|
+
const resolved = await Promise.all(items.splice(0, limit).map(fn))
|
|
24
|
+
results.push(...resolved)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return results
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = eachLimit
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
const NAMES = require('../metrics/names')
|
|
9
|
+
const hashes = require('../util/hashes')
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Helper method for modifying attributes by reference if transaction has queue metrics
|
|
13
|
+
*
|
|
14
|
+
* @param {object} transaction The current transaction
|
|
15
|
+
* @param {object} attributes The attributes object to modify (by reference)
|
|
16
|
+
*/
|
|
17
|
+
function maybeAddQueueAttributes(transaction, attributes) {
|
|
18
|
+
const metric = transaction.metrics.getMetric(NAMES.QUEUETIME)
|
|
19
|
+
|
|
20
|
+
if (metric) {
|
|
21
|
+
attributes.queueDuration = metric.total
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Helper method for modifying attributes by reference if transaction has external call metrics
|
|
27
|
+
*
|
|
28
|
+
* @param {object} transaction The current transaction
|
|
29
|
+
* @param {object} attributes The attributes object to modify (by reference)
|
|
30
|
+
*/
|
|
31
|
+
function maybeAddExternalAttributes(transaction, attributes) {
|
|
32
|
+
const metric = transaction.metrics.getMetric(NAMES.EXTERNAL.ALL)
|
|
33
|
+
|
|
34
|
+
if (metric) {
|
|
35
|
+
attributes.externalDuration = metric.total
|
|
36
|
+
attributes.externalCallCount = metric.callCount
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Helper method for modifying attributes by reference if transaction has database metrics
|
|
42
|
+
*
|
|
43
|
+
* @param {object} transaction The current transaction
|
|
44
|
+
* @param {object} attributes The attributes object to modify (by reference)
|
|
45
|
+
*/
|
|
46
|
+
function maybeAddDatabaseAttributes(transaction, attributes) {
|
|
47
|
+
const metric = transaction.metrics.getMetric(NAMES.DB.ALL)
|
|
48
|
+
|
|
49
|
+
if (metric) {
|
|
50
|
+
attributes.databaseDuration = metric.total
|
|
51
|
+
attributes.databaseCallCount = metric.callCount
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Helper method for modifying attributes by reference if transaction has DT metrics
|
|
57
|
+
*
|
|
58
|
+
* @param {object} transaction The current transaction
|
|
59
|
+
* @param {object} attributes The attributes object to modify (by reference)
|
|
60
|
+
*/
|
|
61
|
+
function maybeAddParentAttributes(transaction, attributes) {
|
|
62
|
+
if (transaction.parentSpanId) {
|
|
63
|
+
attributes.parentSpanId = transaction.parentSpanId
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (transaction.parentId) {
|
|
67
|
+
attributes.parentId = transaction.parentId
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Helper method for modifying attributes by reference if transaction has CAT metrics
|
|
73
|
+
*
|
|
74
|
+
* @param {object} transaction The current transaction
|
|
75
|
+
* @param {object} attributes The attributes object to modify (by reference)
|
|
76
|
+
* @param {object} configuration Agent configuration options
|
|
77
|
+
*/
|
|
78
|
+
function addRequiredCATAttributes(transaction, attributes, configuration) {
|
|
79
|
+
attributes['nr.guid'] = transaction.id
|
|
80
|
+
attributes['nr.tripId'] = transaction.tripId || transaction.id
|
|
81
|
+
attributes['nr.pathHash'] = hashes.calculatePathHash(
|
|
82
|
+
configuration.applications()[0],
|
|
83
|
+
transaction.getFullName(),
|
|
84
|
+
transaction.referringPathHash
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Helper method for modifying attributes by reference if transaction has additional CAT metrics
|
|
90
|
+
*
|
|
91
|
+
* @param {object} transaction The current transaction
|
|
92
|
+
* @param {object} attributes The attributes object to modify (by reference)
|
|
93
|
+
* @param {object} configuration Agent configuration options
|
|
94
|
+
*/
|
|
95
|
+
function maybeAddExtraCATAttributes(transaction, attributes, configuration) {
|
|
96
|
+
if (transaction.referringPathHash) {
|
|
97
|
+
attributes['nr.referringPathHash'] = transaction.referringPathHash
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (transaction.referringTransactionGuid) {
|
|
101
|
+
const refId = transaction.referringTransactionGuid
|
|
102
|
+
attributes['nr.referringTransactionGuid'] = refId
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const alternatePathHashes = transaction.alternatePathHashes()
|
|
106
|
+
if (alternatePathHashes) {
|
|
107
|
+
attributes['nr.alternatePathHashes'] = alternatePathHashes
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (transaction.baseSegment && transaction.type === 'web') {
|
|
111
|
+
const apdex =
|
|
112
|
+
configuration.web_transactions_apdex[transaction.getFullName()] || configuration.apdex_t
|
|
113
|
+
const duration = transaction.baseSegment.getDurationInMillis() / 1000
|
|
114
|
+
attributes['nr.apdexPerfZone'] = calculateApdexZone(duration, apdex)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Helper method for determining a transaction's apdex score based on an apdex threshold and transaction duration
|
|
120
|
+
*
|
|
121
|
+
* @param {number} duration number of seconds the transaction took
|
|
122
|
+
* @param {number} apdexT the apdex threshold
|
|
123
|
+
* @returns {string} String representation of apdex "zone"
|
|
124
|
+
*/
|
|
125
|
+
function calculateApdexZone(duration, apdexT) {
|
|
126
|
+
if (duration <= apdexT) {
|
|
127
|
+
return 'S' // satisfied
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (duration <= apdexT * 4) {
|
|
131
|
+
return 'T' // tolerating
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return 'F' // frustrated
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Helper method for modifying attributes by reference if transaction has Synthetics metrics
|
|
139
|
+
*
|
|
140
|
+
* @param {object} transaction The current transaction
|
|
141
|
+
* @param {object} attributes The attributes object to modify (by reference)
|
|
142
|
+
*/
|
|
143
|
+
function maybeAddSyntheticAttributes(transaction, attributes) {
|
|
144
|
+
if (transaction.syntheticsData) {
|
|
145
|
+
attributes['nr.syntheticsResourceId'] = transaction.syntheticsData.resourceId
|
|
146
|
+
attributes['nr.syntheticsJobId'] = transaction.syntheticsData.jobId
|
|
147
|
+
attributes['nr.syntheticsMonitorId'] = transaction.syntheticsData.monitorId
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
module.exports = {
|
|
152
|
+
maybeAddQueueAttributes,
|
|
153
|
+
maybeAddExternalAttributes,
|
|
154
|
+
maybeAddDatabaseAttributes,
|
|
155
|
+
maybeAddParentAttributes,
|
|
156
|
+
addRequiredCATAttributes,
|
|
157
|
+
maybeAddExtraCATAttributes,
|
|
158
|
+
maybeAddSyntheticAttributes
|
|
159
|
+
}
|