newrelic 8.17.1 → 9.0.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 +5443 -5374
- package/THIRD_PARTY_NOTICES.md +6037 -373
- package/index.js +2 -2
- package/lib/collector/api.js +1 -1
- package/lib/collector/facts.js +79 -79
- package/lib/collector/http-agents.js +4 -21
- package/lib/collector/remote-method.js +3 -19
- package/lib/config/default.js +10 -0
- package/lib/config/env.js +1 -0
- package/lib/config/index.js +0 -8
- package/lib/db/query-trace-aggregator.js +20 -3
- package/lib/environment.js +152 -273
- package/lib/feature_flags.js +3 -3
- package/lib/instrumentation/core/async_hooks.js +1 -38
- package/lib/instrumentation/core/http-outbound.js +8 -12
- package/lib/instrumentation/hapi/{hapi-17.js → hapi.js} +0 -0
- package/lib/instrumentation/hapi.js +1 -23
- package/lib/instrumentation/pg.js +3 -18
- package/lib/instrumentations.js +0 -2
- package/lib/metrics/names.js +2 -9
- package/lib/transaction/trace/aggregator.js +19 -7
- package/lib/transaction/transaction-event-aggregator.js +18 -20
- package/lib/util/application-logging.js +14 -1
- package/lib/util/unwrapped-core.js +2 -0
- package/package.json +16 -19
- package/lib/collector/ssl/certificates.js +0 -1165
- package/lib/db/parse-sql.js +0 -62
- package/lib/instrumentation/oracle.js +0 -130
package/index.js
CHANGED
|
@@ -53,8 +53,8 @@ function initialize() {
|
|
|
53
53
|
throw new Error(message)
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
// TODO: Update this check when Node
|
|
57
|
-
if (psemver.satisfies('>=
|
|
56
|
+
// TODO: Update this check when Node v20 support is added
|
|
57
|
+
if (psemver.satisfies('>=19.0.0')) {
|
|
58
58
|
logger.warn(
|
|
59
59
|
'New Relic for Node.js %s has not been tested on Node.js %s. Please ' +
|
|
60
60
|
'update the agent or downgrade your version of Node.js',
|
package/lib/collector/api.js
CHANGED
|
@@ -525,7 +525,7 @@ function transactionSampleData(traces, callback) {
|
|
|
525
525
|
* @param logRecords
|
|
526
526
|
* @param {Function} callback The continuation / error handler.
|
|
527
527
|
*/
|
|
528
|
-
CollectorAPI.prototype.log_event_data = function
|
|
528
|
+
CollectorAPI.prototype.log_event_data = function logEventData(logRecords, callback) {
|
|
529
529
|
if (!callback) {
|
|
530
530
|
throw new TypeError('callback is required')
|
|
531
531
|
}
|
package/lib/collector/facts.js
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
const a = require('async')
|
|
9
8
|
const fetchSystemInfo = require('../system-info')
|
|
10
9
|
const logger = require('../logger').child({ component: 'facts' })
|
|
11
10
|
const os = require('os')
|
|
@@ -19,94 +18,95 @@ const LOG_LIBRARIES = ['winston', 'bunyan', 'pino', 'loglevel', 'npmlog', 'fancy
|
|
|
19
18
|
|
|
20
19
|
module.exports = facts
|
|
21
20
|
|
|
22
|
-
function facts(agent, callback) {
|
|
21
|
+
async function facts(agent, callback) {
|
|
23
22
|
const startTime = Date.now()
|
|
24
|
-
a.parallel(
|
|
25
|
-
{
|
|
26
|
-
systemInfo: a.apply(fetchSystemInfo, agent),
|
|
27
|
-
environment: agent.environment.getJSON
|
|
28
|
-
},
|
|
29
|
-
function factMapCb(err, data) {
|
|
30
|
-
logger.trace('Facts gathering finished in %dms', Date.now() - startTime)
|
|
31
23
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const environment = data.environment || []
|
|
38
|
-
|
|
39
|
-
countSupportabilityForLogLibraries(environment, agent)
|
|
40
|
-
|
|
41
|
-
const hostname = agent.config.getHostnameSafe()
|
|
42
|
-
const results = {
|
|
43
|
-
utilization: {
|
|
44
|
-
metadata_version: 5,
|
|
45
|
-
logical_processors: systemInfo.logicalProcessors || null,
|
|
46
|
-
total_ram_mib: systemInfo.memory || null,
|
|
47
|
-
hostname: hostname
|
|
48
|
-
},
|
|
49
|
-
pid: process.pid,
|
|
50
|
-
host: hostname,
|
|
51
|
-
display_host: agent.config.getDisplayHost() || hostname,
|
|
52
|
-
language: 'nodejs',
|
|
53
|
-
app_name: agent.config.applications(),
|
|
54
|
-
agent_version: agent.version,
|
|
55
|
-
environment: environment,
|
|
56
|
-
settings: agent.config.publicSettings(),
|
|
57
|
-
high_security: agent.config.high_security,
|
|
58
|
-
labels: parseLabels(agent.config.labels),
|
|
59
|
-
metadata: Object.keys(process.env).reduce((obj, key) => {
|
|
60
|
-
if (key.startsWith('NEW_RELIC_METADATA_')) {
|
|
61
|
-
obj[key] = process.env[key]
|
|
62
|
-
}
|
|
63
|
-
return obj
|
|
64
|
-
}, {})
|
|
65
|
-
}
|
|
24
|
+
const systemInfoPromise = new Promise((resolve) => {
|
|
25
|
+
fetchSystemInfo(agent, (_, data) => {
|
|
26
|
+
resolve(data)
|
|
27
|
+
})
|
|
28
|
+
})
|
|
66
29
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
* WARNING: This may not make sense if you are familiar with our config
|
|
71
|
-
* and updating of config from server. But the intention here is to always
|
|
72
|
-
* send the values from user config of harvest limits because on connect these
|
|
73
|
-
* values get reconfigured based on harvest cycle intervals. So if you originally
|
|
74
|
-
* had 1000 and a harvest of 5 seconds the new value of the harvest limit would be 83.
|
|
75
|
-
* Then every subsequent connect request it would continue to decrease until it eventually hit 0
|
|
76
|
-
* and we would never be sampling a certain piece of data.
|
|
77
|
-
*/
|
|
78
|
-
results.event_harvest_config = {
|
|
79
|
-
harvest_limits: {
|
|
80
|
-
analytic_event_data: agent.config.transaction_events.max_samples_stored,
|
|
81
|
-
custom_event_data: agent.config.custom_insights_events.max_samples_stored,
|
|
82
|
-
error_event_data: agent.config.error_collector.max_event_samples_stored,
|
|
83
|
-
span_event_data: agent.config.span_events.max_samples_stored,
|
|
84
|
-
log_event_data: agent.config.application_logging.forwarding.max_samples_stored
|
|
85
|
-
}
|
|
86
|
-
}
|
|
30
|
+
const environmentPromise = agent.environment.getJSON()
|
|
31
|
+
let [systemInfo, environment] = await Promise.all([systemInfoPromise, environmentPromise])
|
|
32
|
+
logger.trace('Facts gathering finished in %dms', Date.now() - startTime)
|
|
87
33
|
|
|
88
|
-
|
|
34
|
+
if (environment.failed) {
|
|
35
|
+
logger.debug(environment.err, 'Failed to load system facts!')
|
|
36
|
+
}
|
|
89
37
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
results.utilization.ip_address = ipAddresses
|
|
93
|
-
}
|
|
38
|
+
systemInfo = systemInfo || Object.create(null)
|
|
39
|
+
environment = environment || []
|
|
94
40
|
|
|
95
|
-
|
|
96
|
-
results.utilization.boot_id = systemInfo.bootId
|
|
97
|
-
}
|
|
41
|
+
countSupportabilityForLogLibraries(environment, agent)
|
|
98
42
|
|
|
99
|
-
|
|
100
|
-
|
|
43
|
+
const hostname = agent.config.getHostnameSafe()
|
|
44
|
+
const results = {
|
|
45
|
+
utilization: {
|
|
46
|
+
metadata_version: 5,
|
|
47
|
+
logical_processors: systemInfo.logicalProcessors || null,
|
|
48
|
+
total_ram_mib: systemInfo.memory || null,
|
|
49
|
+
hostname: hostname
|
|
50
|
+
},
|
|
51
|
+
pid: process.pid,
|
|
52
|
+
host: hostname,
|
|
53
|
+
display_host: agent.config.getDisplayHost() || hostname,
|
|
54
|
+
language: 'nodejs',
|
|
55
|
+
app_name: agent.config.applications(),
|
|
56
|
+
agent_version: agent.version,
|
|
57
|
+
environment: environment,
|
|
58
|
+
settings: agent.config.publicSettings(),
|
|
59
|
+
high_security: agent.config.high_security,
|
|
60
|
+
labels: parseLabels(agent.config.labels),
|
|
61
|
+
metadata: Object.keys(process.env).reduce((obj, key) => {
|
|
62
|
+
if (key.startsWith('NEW_RELIC_METADATA_')) {
|
|
63
|
+
obj[key] = process.env[key]
|
|
101
64
|
}
|
|
65
|
+
return obj
|
|
66
|
+
}, {})
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
logger.debug('New Relic metadata %o', results.metadata)
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* WARNING: This may not make sense if you are familiar with our config
|
|
73
|
+
* and updating of config from server. But the intention here is to always
|
|
74
|
+
* send the values from user config of harvest limits because on connect these
|
|
75
|
+
* values get reconfigured based on harvest cycle intervals. So if you originally
|
|
76
|
+
* had 1000 and a harvest of 5 seconds the new value of the harvest limit would be 83.
|
|
77
|
+
* Then every subsequent connect request it would continue to decrease until it eventually hit 0
|
|
78
|
+
* and we would never be sampling a certain piece of data.
|
|
79
|
+
*/
|
|
80
|
+
results.event_harvest_config = {
|
|
81
|
+
harvest_limits: {
|
|
82
|
+
analytic_event_data: agent.config.transaction_events.max_samples_stored,
|
|
83
|
+
custom_event_data: agent.config.custom_insights_events.max_samples_stored,
|
|
84
|
+
error_event_data: agent.config.error_collector.max_event_samples_stored,
|
|
85
|
+
span_event_data: agent.config.span_events.max_samples_stored,
|
|
86
|
+
log_event_data: agent.config.application_logging.forwarding.max_samples_stored
|
|
87
|
+
}
|
|
88
|
+
}
|
|
102
89
|
|
|
103
|
-
|
|
104
|
-
results.utilization.config = systemInfo.config
|
|
105
|
-
}
|
|
90
|
+
results.identifier = getIdentifierOverride(results.app_name)
|
|
106
91
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
92
|
+
const ipAddresses = getAllIPAddresses()
|
|
93
|
+
if (ipAddresses.length) {
|
|
94
|
+
results.utilization.ip_address = ipAddresses
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (systemInfo.bootId) {
|
|
98
|
+
results.utilization.boot_id = systemInfo.bootId
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (systemInfo.vendors) {
|
|
102
|
+
results.utilization.vendors = systemInfo.vendors
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (systemInfo.config) {
|
|
106
|
+
results.utilization.config = systemInfo.config
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
callback(results)
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
function getAllIPAddresses() {
|
|
@@ -8,8 +8,6 @@
|
|
|
8
8
|
const parse = require('url').parse
|
|
9
9
|
const ProxyAgent = require('https-proxy-agent')
|
|
10
10
|
const logger = require('../logger').child({ component: 'http-agent' })
|
|
11
|
-
const certificates = require('./ssl/certificates.js')
|
|
12
|
-
|
|
13
11
|
const https = require('https')
|
|
14
12
|
|
|
15
13
|
// poor person's single-instance-objects. We
|
|
@@ -21,6 +19,8 @@ let agentProxyWithKeepAlive = null
|
|
|
21
19
|
|
|
22
20
|
/**
|
|
23
21
|
* Returns an HTTP agent with keep-alive enabled
|
|
22
|
+
*
|
|
23
|
+
* @param config
|
|
24
24
|
*/
|
|
25
25
|
exports.keepAliveAgent = function keepAliveAgent(config) {
|
|
26
26
|
config = config ? config : {}
|
|
@@ -45,6 +45,8 @@ exports.keepAliveAgent = function keepAliveAgent(config) {
|
|
|
45
45
|
* Include keep-alive configuration, but ultimately its up
|
|
46
46
|
* to the proxy server as to how its connection is made
|
|
47
47
|
* with New Relic's servers.
|
|
48
|
+
*
|
|
49
|
+
* @param config
|
|
48
50
|
*/
|
|
49
51
|
exports.proxyAgent = function proxyAgent(config) {
|
|
50
52
|
if (null !== agentProxyWithKeepAlive) {
|
|
@@ -109,25 +111,6 @@ function proxyOptions(config) {
|
|
|
109
111
|
|
|
110
112
|
if (config.certificates && config.certificates.length > 0) {
|
|
111
113
|
opts.certificates = config.certificates
|
|
112
|
-
|
|
113
|
-
// merge user certificates with built-in certs
|
|
114
|
-
if (config.feature_flag.certificate_bundle) {
|
|
115
|
-
logger.info(
|
|
116
|
-
'Using a proxy with a special cert. This enables our cert bundle which, combined ' +
|
|
117
|
-
'with some versions of node, exacerbates a leak in node core TLS.'
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
const certWarningMessage = [
|
|
121
|
-
'Deprecation Warning: The certificate bundle included by New Relic will be ',
|
|
122
|
-
'disabled by default and then fully removed in later major versions. We recommend ',
|
|
123
|
-
'testing with the certificate_bundle feature flag set to `false` to determine if ',
|
|
124
|
-
'you will need to modify your environment or setup your own appropriate bundle. ',
|
|
125
|
-
'Example configuration: feature_flag: { certificate_bundle: false }.'
|
|
126
|
-
].join('')
|
|
127
|
-
logger.warnOnce('CERT_WARNING', certWarningMessage)
|
|
128
|
-
|
|
129
|
-
opts.certificates = config.certificates.concat(certificates)
|
|
130
|
-
}
|
|
131
114
|
}
|
|
132
115
|
|
|
133
116
|
return opts
|
|
@@ -14,7 +14,6 @@ const parse = require('./parse-response')
|
|
|
14
14
|
const stringify = require('json-stringify-safe')
|
|
15
15
|
const Sink = require('../util/stream-sink')
|
|
16
16
|
const agents = require('./http-agents')
|
|
17
|
-
const certificates = require('./ssl/certificates')
|
|
18
17
|
const isValidLength = require('../util/byte-limit').isValidLength
|
|
19
18
|
const { DATA_USAGE } = require('../metrics/names')
|
|
20
19
|
|
|
@@ -61,7 +60,7 @@ RemoteMethod.prototype.updateEndpoint = function updateEndpoint(endpoint) {
|
|
|
61
60
|
RemoteMethod.prototype.serialize = function serialize(payload, callback) {
|
|
62
61
|
let res
|
|
63
62
|
try {
|
|
64
|
-
res = stringify(payload)
|
|
63
|
+
res = stringify(payload, (key, value) => (typeof value === 'bigint' ? value.toString() : value))
|
|
65
64
|
} catch (error) {
|
|
66
65
|
logger.error(error, 'Unable to serialize payload for method %s.', this.name)
|
|
67
66
|
return process.nextTick(function onNextTick() {
|
|
@@ -153,8 +152,8 @@ RemoteMethod.prototype._post = function _post(data, nrHeaders, callback) {
|
|
|
153
152
|
if (options.compressed) {
|
|
154
153
|
// NOTE: gzip and deflate throw immediately in Node 14+ with an invalid argument
|
|
155
154
|
try {
|
|
156
|
-
const
|
|
157
|
-
const compressor =
|
|
155
|
+
const useDeflate = this._config.compressed_content_encoding === 'deflate'
|
|
156
|
+
const compressor = useDeflate ? zlib.deflate : zlib.gzip
|
|
158
157
|
compressor(data, function onCompress(err, compressed) {
|
|
159
158
|
if (err) {
|
|
160
159
|
logger.warn(err, 'Error compressing JSON for delivery. Not sending.')
|
|
@@ -306,21 +305,6 @@ RemoteMethod.prototype._request = function _request(options) {
|
|
|
306
305
|
} else {
|
|
307
306
|
if (this._config.certificates && this._config.certificates.length > 0) {
|
|
308
307
|
requestOptions.ca = this._config.certificates
|
|
309
|
-
|
|
310
|
-
if (this._config.feature_flag.certificate_bundle) {
|
|
311
|
-
logger.debug('Adding custom certificate to the cert bundle.')
|
|
312
|
-
|
|
313
|
-
const certWarningMessage = [
|
|
314
|
-
'Deprecation Warning: The certificate bundle included by New Relic will be ',
|
|
315
|
-
'disabled by default and then fully removed in later major versions. We recommend ',
|
|
316
|
-
'testing with the certificate_bundle feature flag set to `false` to determine if ',
|
|
317
|
-
'you will need to modify your environment or setup your own appropriate bundle. ',
|
|
318
|
-
'Example configuration: feature_flag: { certificate_bundle: false }.'
|
|
319
|
-
].join('')
|
|
320
|
-
logger.warnOnce('CERT_WARNING', certWarningMessage)
|
|
321
|
-
|
|
322
|
-
requestOptions.ca = this._config.certificates.concat(certificates)
|
|
323
|
-
}
|
|
324
308
|
}
|
|
325
309
|
request = https.request(requestOptions)
|
|
326
310
|
}
|
package/lib/config/default.js
CHANGED
|
@@ -139,6 +139,16 @@ exports.config = () => ({
|
|
|
139
139
|
*/
|
|
140
140
|
allow_all_headers: false,
|
|
141
141
|
|
|
142
|
+
/**
|
|
143
|
+
* If the data compression threshold is reached in the payload, the
|
|
144
|
+
* agent compresses data, using gzip compression by default. The
|
|
145
|
+
* config option `compressed_content_encoding` can be set to 'deflate'
|
|
146
|
+
* to use deflate compression.
|
|
147
|
+
*
|
|
148
|
+
* @env NEW_RELIC_COMPRESSED_CONTENT_ENCODING
|
|
149
|
+
*/
|
|
150
|
+
compressed_content_encoding: 'gzip',
|
|
151
|
+
|
|
142
152
|
/**
|
|
143
153
|
* Attributes are key-value pairs containing information that determines
|
|
144
154
|
* the properties of an event or transaction.
|
package/lib/config/env.js
CHANGED
|
@@ -22,6 +22,7 @@ const ENV_MAPPING = {
|
|
|
22
22
|
proxy_pass: 'NEW_RELIC_PROXY_PASS',
|
|
23
23
|
agent_enabled: 'NEW_RELIC_ENABLED',
|
|
24
24
|
allow_all_headers: 'NEW_RELIC_ALLOW_ALL_HEADERS',
|
|
25
|
+
compressed_content_encoding: 'NEW_RELIC_COMPRESSED_CONTENT_ENCODING',
|
|
25
26
|
attributes: {
|
|
26
27
|
enabled: 'NEW_RELIC_ATTRIBUTES_ENABLED',
|
|
27
28
|
exclude: 'NEW_RELIC_ATTRIBUTES_EXCLUDE',
|
package/lib/config/index.js
CHANGED
|
@@ -154,7 +154,6 @@ function Config(config) {
|
|
|
154
154
|
this.browser_monitoring.loader_version = ''
|
|
155
155
|
|
|
156
156
|
// Settings to play nice with DLPs (see NODE-1044).
|
|
157
|
-
this.compressed_content_encoding = 'deflate' // Deflate or gzip
|
|
158
157
|
this.simple_compression = false // Disables subcomponent compression
|
|
159
158
|
this.put_for_data_send = false // Changes http verb for harvest
|
|
160
159
|
|
|
@@ -858,13 +857,6 @@ Config.prototype.logUnknown = function logUnknown(json, key) {
|
|
|
858
857
|
logger.debug('New Relic sent unknown configuration parameter %s with value %s.', key, value)
|
|
859
858
|
}
|
|
860
859
|
|
|
861
|
-
/**
|
|
862
|
-
* Return the availability of async_hook for use by the agent.
|
|
863
|
-
*/
|
|
864
|
-
Config.prototype.checkAsyncHookStatus = function checkAsyncHookStatus() {
|
|
865
|
-
return this.feature_flag.await_support
|
|
866
|
-
}
|
|
867
|
-
|
|
868
860
|
/**
|
|
869
861
|
* Gets the user set host display name. If not provided, it returns the default value.
|
|
870
862
|
*
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
const a = require('async')
|
|
9
8
|
const logger = require('../logger').child({ component: 'query_tracer' })
|
|
10
9
|
const Aggregator = require('../aggregators/base-aggregator')
|
|
11
10
|
const SlowQuery = require('./slow-query')
|
|
@@ -132,8 +131,26 @@ class QueryTraceAggregator extends Aggregator {
|
|
|
132
131
|
this.samples = new Map()
|
|
133
132
|
}
|
|
134
133
|
|
|
135
|
-
prepareJSON(done) {
|
|
136
|
-
|
|
134
|
+
async prepareJSON(done) {
|
|
135
|
+
const samplePromises = []
|
|
136
|
+
for (const sample of this.samples.values()) {
|
|
137
|
+
const samplePromise = new Promise((resolve, reject) => {
|
|
138
|
+
sample.prepareJSON((err, data) => {
|
|
139
|
+
if (err) {
|
|
140
|
+
reject(err)
|
|
141
|
+
}
|
|
142
|
+
resolve(data)
|
|
143
|
+
})
|
|
144
|
+
})
|
|
145
|
+
samplePromises.push(samplePromise)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
try {
|
|
149
|
+
const data = await Promise.all(samplePromises)
|
|
150
|
+
done(null, data)
|
|
151
|
+
} catch (err) {
|
|
152
|
+
done(err)
|
|
153
|
+
}
|
|
137
154
|
}
|
|
138
155
|
|
|
139
156
|
prepareJSONSync() {
|