newrelic 7.5.2 → 8.3.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 +4989 -4886
- package/THIRD_PARTY_NOTICES.md +625 -216
- package/api.js +105 -174
- package/bin/test-naming-rules.js +38 -32
- package/bin/tracetractor +0 -1
- package/index.js +12 -18
- package/lib/agent.js +108 -111
- package/lib/aggregators/base-aggregator.js +1 -1
- package/lib/aggregators/event-aggregator.js +6 -6
- package/lib/attributes.js +12 -13
- package/lib/collector/api.js +32 -42
- package/lib/collector/facts.js +67 -65
- package/lib/collector/http-agents.js +30 -27
- package/lib/collector/parse-response.js +1 -2
- package/lib/collector/remote-method.js +43 -36
- package/lib/collector/serverless.js +13 -18
- package/lib/collector/ssl/certificates.js +1056 -1056
- package/lib/config/attribute-filter.js +90 -82
- package/lib/config/default.js +30 -18
- package/lib/config/env.js +17 -12
- package/lib/config/harvest-config-validator.js +1 -1
- package/lib/config/index.js +160 -177
- package/lib/config/merge-server-config.js +7 -5
- package/lib/custom-events/custom-event-aggregator.js +1 -1
- package/lib/db/parse-sql.js +6 -9
- package/lib/db/parsed-statement.js +6 -13
- package/lib/db/query-parsers/sql.js +6 -9
- package/lib/db/query-sample.js +7 -3
- package/lib/db/query-trace-aggregator.js +12 -12
- package/lib/db/utils.js +1 -1
- package/lib/environment.js +173 -138
- package/lib/errors/error-collector.js +18 -31
- package/lib/errors/error-event-aggregator.js +1 -1
- package/lib/errors/error-trace-aggregator.js +2 -3
- package/lib/errors/helper.js +21 -30
- package/lib/errors/index.js +16 -28
- package/lib/feature_flags.js +5 -8
- package/lib/grpc/connection/states.js +6 -6
- package/lib/grpc/connection.js +35 -46
- package/lib/header-attributes.js +49 -53
- package/lib/instrumentation/amqplib.js +8 -17
- package/lib/instrumentation/bluebird.js +61 -20
- package/lib/instrumentation/cassandra-driver.js +2 -2
- package/lib/instrumentation/connect.js +4 -3
- package/lib/instrumentation/core/async_hooks.js +11 -4
- 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 +2 -8
- package/lib/instrumentation/core/fs.js +22 -37
- package/lib/instrumentation/core/globals.js +3 -7
- package/lib/instrumentation/core/http-outbound.js +15 -40
- package/lib/instrumentation/core/http.js +29 -63
- package/lib/instrumentation/core/inspector.js +6 -10
- package/lib/instrumentation/core/net.js +3 -1
- package/lib/instrumentation/core/timers.js +17 -24
- package/lib/instrumentation/core/zlib.js +2 -10
- package/lib/instrumentation/express.js +4 -2
- package/lib/instrumentation/fastify/spec-builders.js +5 -0
- package/lib/instrumentation/fastify.js +37 -10
- package/lib/instrumentation/hapi/hapi-17.js +9 -10
- package/lib/instrumentation/hapi.js +15 -15
- package/lib/instrumentation/ioredis.js +1 -2
- package/lib/instrumentation/memcached.js +39 -43
- package/lib/instrumentation/mongodb/common.js +218 -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 +33 -26
- package/lib/instrumentation/oracle.js +10 -14
- package/lib/instrumentation/pg.js +30 -21
- package/lib/instrumentation/promise.js +20 -17
- package/lib/instrumentation/redis.js +30 -30
- package/lib/instrumentation/when.js +9 -1
- package/lib/instrumentations.js +24 -24
- package/lib/logger.js +1 -1
- package/lib/metrics/index.js +37 -17
- package/lib/metrics/mapper.js +9 -9
- package/lib/metrics/metric-aggregator.js +5 -10
- package/lib/metrics/names.js +8 -7
- package/lib/metrics/normalizer/rule.js +6 -7
- package/lib/metrics/normalizer/tx_segment.js +17 -13
- package/lib/metrics/normalizer.js +30 -33
- package/lib/metrics/recorders/custom.js +3 -1
- package/lib/metrics/recorders/distributed-trace.js +3 -18
- package/lib/metrics/recorders/generic.js +3 -2
- package/lib/metrics/recorders/http.js +4 -6
- package/lib/metrics/recorders/http_external.js +1 -3
- package/lib/metrics/recorders/message-transaction.js +2 -12
- package/lib/metrics/recorders/other.js +2 -12
- package/lib/parse-proc-cpuinfo.js +11 -16
- package/lib/parse-proc-meminfo.js +5 -3
- package/lib/prioritized-attributes.js +12 -17
- package/lib/priority-queue.js +1 -1
- package/lib/proxy/grpc.js +1 -1
- package/lib/reservoir.js +9 -3
- package/lib/sampler.js +12 -13
- 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 +29 -38
- package/lib/shim/index.js +8 -9
- package/lib/shim/message-shim.js +111 -113
- package/lib/shim/promise-shim.js +18 -13
- package/lib/shim/shim.js +72 -66
- package/lib/shim/specs/index.js +18 -19
- package/lib/shim/transaction-shim.js +26 -36
- package/lib/shim/webframework-shim.js +25 -35
- package/lib/shimmer.js +184 -166
- package/lib/spans/create-span-event-aggregator.js +24 -44
- package/lib/spans/span-context.js +4 -10
- package/lib/spans/span-event-aggregator.js +68 -13
- package/lib/spans/span-event.js +5 -7
- package/lib/spans/span-streamer.js +10 -18
- package/lib/spans/streaming-span-event-aggregator.js +1 -1
- package/lib/spans/streaming-span-event.js +4 -4
- package/lib/stats/apdex.js +5 -11
- package/lib/stats/index.js +12 -17
- package/lib/system-info.js +7 -3
- package/lib/timer.js +30 -16
- package/lib/transaction/dt-payload.js +1 -1
- package/lib/transaction/handle.js +19 -19
- package/lib/transaction/index.js +94 -112
- package/lib/transaction/name-state.js +5 -6
- package/lib/transaction/trace/aggregator.js +78 -73
- package/lib/transaction/trace/exclusive-time-calculator.js +5 -9
- package/lib/transaction/trace/index.js +26 -24
- package/lib/transaction/trace/segment.js +39 -56
- package/lib/transaction/tracecontext.js +37 -45
- package/lib/transaction/tracer/index.js +79 -44
- package/lib/transaction/transaction-event-aggregator.js +29 -31
- package/lib/uninstrumented.js +4 -5
- package/lib/util/attribute-types.js +1 -5
- package/lib/util/byte-limit.js +0 -1
- package/lib/util/cat.js +5 -13
- package/lib/util/codec.js +8 -4
- package/lib/util/deep-equal.js +48 -18
- package/lib/util/flatten.js +5 -2
- package/lib/util/hashes.js +2 -2
- package/lib/util/label-parser.js +7 -13
- package/lib/util/logger.js +31 -13
- package/lib/util/process-version.js +1 -1
- package/lib/util/properties.js +1 -1
- package/lib/util/sql/obfuscate.js +7 -17
- package/lib/util/stream-sink.js +2 -3
- package/lib/util/urltils.js +9 -13
- package/lib/utilization/aws-info.js +2 -3
- package/lib/utilization/azure-info.js +32 -30
- package/lib/utilization/common.js +5 -4
- package/lib/utilization/docker-info.js +4 -6
- package/lib/utilization/gcp-info.js +36 -35
- package/lib/utilization/index.js +1 -1
- package/lib/utilization/kubernetes-info.js +2 -2
- package/lib/utilization/pcf-info.js +4 -4
- package/package.json +32 -18
- package/stub_api.js +8 -6
package/lib/attributes.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
8
|
const Config = require('./config')
|
|
9
|
-
const logger = require('./logger').child({component: 'attributes'})
|
|
9
|
+
const logger = require('./logger').child({ component: 'attributes' })
|
|
10
10
|
const isValidType = require('./util/attribute-types')
|
|
11
11
|
const byteUtils = require('./util/byte-limit')
|
|
12
12
|
const properties = require('./util/properties')
|
|
@@ -52,7 +52,7 @@ class Attributes {
|
|
|
52
52
|
* @param {boolean} truncateExempt - Flag marking value exempt from truncation
|
|
53
53
|
*/
|
|
54
54
|
_set(destinations, key, value, truncateExempt) {
|
|
55
|
-
this.attributes[key] = {value, destinations, truncateExempt}
|
|
55
|
+
this.attributes[key] = { value, destinations, truncateExempt }
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
/**
|
|
@@ -65,15 +65,17 @@ class Attributes {
|
|
|
65
65
|
*/
|
|
66
66
|
get(dest) {
|
|
67
67
|
const attrs = Object.create(null)
|
|
68
|
-
|
|
68
|
+
// eslint-disable-next-line guard-for-in
|
|
69
|
+
for (let key in this.attributes) {
|
|
69
70
|
const attr = this.attributes[key]
|
|
70
71
|
if (!(attr.destinations & dest)) {
|
|
71
72
|
continue
|
|
72
73
|
}
|
|
73
74
|
|
|
74
|
-
attrs[key] =
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
attrs[key] =
|
|
76
|
+
typeof attr.value === 'string' && !attr.truncateExempt
|
|
77
|
+
? byteUtils.truncate(attr.value, 255)
|
|
78
|
+
: attr.value
|
|
77
79
|
}
|
|
78
80
|
|
|
79
81
|
return attrs
|
|
@@ -116,18 +118,15 @@ class Attributes {
|
|
|
116
118
|
if (!isValidType(value)) {
|
|
117
119
|
return logger.debug(
|
|
118
120
|
'Not adding attribute %s with %s value type. This is expected for undefined' +
|
|
119
|
-
|
|
120
|
-
|
|
121
|
+
'attributes and only an issue if an attribute is not expected to be undefined' +
|
|
122
|
+
'or not of the type expected.',
|
|
121
123
|
key,
|
|
122
124
|
typeof value
|
|
123
125
|
)
|
|
124
126
|
}
|
|
125
127
|
|
|
126
128
|
if (!this.isValidLength(key)) {
|
|
127
|
-
return logger.warn(
|
|
128
|
-
'Length limit exceeded for attribute name, not adding: %s',
|
|
129
|
-
key
|
|
130
|
-
)
|
|
129
|
+
return logger.warn('Length limit exceeded for attribute name, not adding: %s', key)
|
|
131
130
|
}
|
|
132
131
|
|
|
133
132
|
// Only set the attribute if at least one destination passed
|
|
@@ -174,7 +173,7 @@ class Attributes {
|
|
|
174
173
|
* scope.
|
|
175
174
|
*/
|
|
176
175
|
function makeFilter(scope) {
|
|
177
|
-
const {attributeFilter} = Config.getInstance()
|
|
176
|
+
const { attributeFilter } = Config.getInstance()
|
|
178
177
|
if (scope === 'transaction') {
|
|
179
178
|
return (d, k) => attributeFilter.filterTransaction(d, k)
|
|
180
179
|
} else if (scope === 'segment') {
|
package/lib/collector/api.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
const CollectorResponse = require('./response')
|
|
9
9
|
const facts = require('./facts')
|
|
10
|
-
const logger = require('../logger').child({component: 'collector_api'})
|
|
10
|
+
const logger = require('../logger').child({ component: 'collector_api' })
|
|
11
11
|
const RemoteMethod = require('./remote-method')
|
|
12
12
|
|
|
13
13
|
const NAMES = require('../metrics/names')
|
|
@@ -19,21 +19,19 @@ const TO_MILLIS = 1e3
|
|
|
19
19
|
|
|
20
20
|
// taken directly from Python agent's newrelic.core.application
|
|
21
21
|
const BACKOFFS = [
|
|
22
|
-
{interval: 15, warn: false},
|
|
23
|
-
{interval: 15, warn: false},
|
|
24
|
-
{interval: 30, warn: false},
|
|
25
|
-
{interval: 60, warn: true},
|
|
26
|
-
{interval: 120, warn: false},
|
|
27
|
-
{interval: 300, warn: false}
|
|
22
|
+
{ interval: 15, warn: false },
|
|
23
|
+
{ interval: 15, warn: false },
|
|
24
|
+
{ interval: 30, warn: false },
|
|
25
|
+
{ interval: 60, warn: true },
|
|
26
|
+
{ interval: 120, warn: false },
|
|
27
|
+
{ interval: 300, warn: false }
|
|
28
28
|
]
|
|
29
29
|
|
|
30
30
|
// Expected collector response codes
|
|
31
31
|
const SUCCESS = new Set([200, 202])
|
|
32
32
|
const RESTART = new Set([401, 409])
|
|
33
33
|
const FAILURE_SAVE_DATA = new Set([408, 429, 500, 503])
|
|
34
|
-
const FAILURE_DISCARD_DATA = new Set(
|
|
35
|
-
[400, 403, 404, 405, 407, 411, 413, 414, 415, 417, 431]
|
|
36
|
-
)
|
|
34
|
+
const FAILURE_DISCARD_DATA = new Set([400, 403, 404, 405, 407, 411, 413, 414, 415, 417, 431])
|
|
37
35
|
|
|
38
36
|
const AGENT_RUN_BEHAVIOR = CollectorResponse.AGENT_RUN_BEHAVIOR
|
|
39
37
|
|
|
@@ -51,7 +49,6 @@ function dumpErrors(errors, name) {
|
|
|
51
49
|
})
|
|
52
50
|
}
|
|
53
51
|
|
|
54
|
-
|
|
55
52
|
function CollectorAPI(agent) {
|
|
56
53
|
this._agent = agent
|
|
57
54
|
this._reqHeadersMap = null
|
|
@@ -128,9 +125,13 @@ CollectorAPI.prototype.connect = function connect(callback) {
|
|
|
128
125
|
*/
|
|
129
126
|
function isProxyMisconfigured(error) {
|
|
130
127
|
const config = api._agent.config
|
|
131
|
-
return
|
|
128
|
+
return (
|
|
129
|
+
error &&
|
|
132
130
|
['EPROTO', 'ECONNRESET'].includes(error.code) &&
|
|
133
|
-
config.proxy_host &&
|
|
131
|
+
config.proxy_host &&
|
|
132
|
+
config.proxy_port &&
|
|
133
|
+
!config.proxy
|
|
134
|
+
)
|
|
134
135
|
}
|
|
135
136
|
|
|
136
137
|
function retry(error, response) {
|
|
@@ -154,26 +155,23 @@ CollectorAPI.prototype.connect = function connect(callback) {
|
|
|
154
155
|
logger.warn(
|
|
155
156
|
error,
|
|
156
157
|
'Your license key appears to be invalid. Reattempting connection to New' +
|
|
157
|
-
|
|
158
|
-
|
|
158
|
+
' Relic. If the problem persists, please contact support@newrelic.com.' +
|
|
159
|
+
' (status code %s)',
|
|
159
160
|
response.status
|
|
160
161
|
)
|
|
161
162
|
} else if (isProxyMisconfigured(error)) {
|
|
162
163
|
logger.warn(
|
|
163
164
|
error,
|
|
164
165
|
'Your proxy server appears to be configured to accept connections over http. ' +
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
166
|
+
'When setting `proxy_host` and `proxy_port` New Relic attempts to connect over ' +
|
|
167
|
+
'SSL(https). If your proxy is configured to accept connections over http, try ' +
|
|
168
|
+
'setting `proxy` to a fully qualified URL(e.g http://proxy-host:8080).'
|
|
168
169
|
)
|
|
169
170
|
}
|
|
170
171
|
|
|
171
172
|
let backoff = BACKOFFS[Math.min(attempts, max) - 1]
|
|
172
173
|
if (backoff.warn) {
|
|
173
|
-
logger.warn(
|
|
174
|
-
'No connection has been established to New Relic after %d attempts.',
|
|
175
|
-
attempts
|
|
176
|
-
)
|
|
174
|
+
logger.warn('No connection has been established to New Relic after %d attempts.', attempts)
|
|
177
175
|
}
|
|
178
176
|
|
|
179
177
|
logger.debug(
|
|
@@ -327,9 +325,13 @@ CollectorAPI.prototype.reportSettings = function reportSettings(callback) {
|
|
|
327
325
|
[this._agent.config.publicSettings()],
|
|
328
326
|
this._reqHeadersMap,
|
|
329
327
|
function onReportSettings(error, response) {
|
|
330
|
-
if (error)
|
|
328
|
+
if (error) {
|
|
329
|
+
dumpErrors([error], 'agent_settings')
|
|
330
|
+
}
|
|
331
331
|
|
|
332
|
-
if (callback)
|
|
332
|
+
if (callback) {
|
|
333
|
+
callback(error, response)
|
|
334
|
+
}
|
|
333
335
|
}
|
|
334
336
|
)
|
|
335
337
|
}
|
|
@@ -498,10 +500,7 @@ CollectorAPI.prototype.shutdown = function shutdown(callback) {
|
|
|
498
500
|
}
|
|
499
501
|
|
|
500
502
|
agent.setState('disconnected')
|
|
501
|
-
logger.info(
|
|
502
|
-
'Disconnected from New Relic; clearing run ID %s.',
|
|
503
|
-
agent.config.run_id
|
|
504
|
-
)
|
|
503
|
+
logger.info('Disconnected from New Relic; clearing run ID %s.', agent.config.run_id)
|
|
505
504
|
agent.config.run_id = undefined
|
|
506
505
|
|
|
507
506
|
callback(error, CollectorResponse.fatal(response && response.payload))
|
|
@@ -515,9 +514,8 @@ CollectorAPI.prototype.restart = function restart(callback) {
|
|
|
515
514
|
var api = this
|
|
516
515
|
this.shutdown(function reconnect() {
|
|
517
516
|
api.connect(function afterConnect() {
|
|
518
|
-
|
|
519
|
-
api._agent.
|
|
520
|
-
return callback.apply(null, arguments)
|
|
517
|
+
const shouldImmediatelyHarvest = false
|
|
518
|
+
api._agent.onConnect(shouldImmediatelyHarvest, callback)
|
|
521
519
|
})
|
|
522
520
|
})
|
|
523
521
|
}
|
|
@@ -573,7 +571,7 @@ CollectorAPI.prototype._sendData = function _sendData(method, data, callback) {
|
|
|
573
571
|
// // but don't really care about that *here*
|
|
574
572
|
// })
|
|
575
573
|
|
|
576
|
-
callback(null, {retainData: response.retainData})
|
|
574
|
+
callback(null, { retainData: response.retainData })
|
|
577
575
|
} else if (response.agentRun === AGENT_RUN_BEHAVIOR.RESTART) {
|
|
578
576
|
// TODO: almost seems better to leg aggregator finish (cb) then restart?
|
|
579
577
|
|
|
@@ -590,7 +588,7 @@ CollectorAPI.prototype._sendData = function _sendData(method, data, callback) {
|
|
|
590
588
|
logger.trace('Restart succeeded.')
|
|
591
589
|
}
|
|
592
590
|
|
|
593
|
-
callback(null, {retainData: response.retainData})
|
|
591
|
+
callback(null, { retainData: response.retainData })
|
|
594
592
|
// TODO: keep object or enum of actions? retain / split / other?
|
|
595
593
|
})
|
|
596
594
|
} else {
|
|
@@ -601,7 +599,6 @@ CollectorAPI.prototype._sendData = function _sendData(method, data, callback) {
|
|
|
601
599
|
})
|
|
602
600
|
}
|
|
603
601
|
|
|
604
|
-
|
|
605
602
|
CollectorAPI.prototype.isConnected = function isConnected() {
|
|
606
603
|
return !!this._agent.config.run_id
|
|
607
604
|
}
|
|
@@ -627,17 +624,14 @@ function _handleResponseCode(response, endpoint, cb) {
|
|
|
627
624
|
// The agent needs to disconnect and restart.
|
|
628
625
|
logFailure(endpoint, code, 'Restarting')
|
|
629
626
|
return setImmediate(cb, null, CollectorResponse.reconnect(0, null))
|
|
630
|
-
|
|
631
627
|
} else if (FAILURE_DISCARD_DATA.has(code)) {
|
|
632
628
|
// Something was wrong with our payload so we must delete our data.
|
|
633
629
|
logFailure(endpoint, code, 'Discarding harvest data')
|
|
634
630
|
return setImmediate(cb, null, CollectorResponse.discard(null))
|
|
635
|
-
|
|
636
631
|
} else if (FAILURE_SAVE_DATA.has(code)) {
|
|
637
632
|
// Something was wrong with the request, but it wasn't our fault. We'll try again.
|
|
638
633
|
logFailure(endpoint, code, 'Retaining data for next harvest')
|
|
639
634
|
return setImmediate(cb, null, CollectorResponse.error(response.payload))
|
|
640
|
-
|
|
641
635
|
} else if (code === 410) {
|
|
642
636
|
// New Relic doesn't like us and we shouldn't try to talk to them any more.
|
|
643
637
|
logFailure(endpoint, code, 'Disconnecting from New Relic')
|
|
@@ -650,11 +644,7 @@ function _handleResponseCode(response, endpoint, cb) {
|
|
|
650
644
|
|
|
651
645
|
// We're not sure what New Relic is trying to tell us. Let's get rid of our
|
|
652
646
|
// data just in case it is our fault.
|
|
653
|
-
logger.error(
|
|
654
|
-
'Agent endpoint %s returned unexpected status %s.',
|
|
655
|
-
endpoint,
|
|
656
|
-
code
|
|
657
|
-
)
|
|
647
|
+
logger.error('Agent endpoint %s returned unexpected status %s.', endpoint, code)
|
|
658
648
|
return setImmediate(cb, null, CollectorResponse.discard(null))
|
|
659
649
|
}
|
|
660
650
|
|
package/lib/collector/facts.js
CHANGED
|
@@ -7,86 +7,88 @@
|
|
|
7
7
|
|
|
8
8
|
const a = require('async')
|
|
9
9
|
const fetchSystemInfo = require('../system-info')
|
|
10
|
-
const logger = require('../logger').child({component: 'facts'})
|
|
10
|
+
const logger = require('../logger').child({ component: 'facts' })
|
|
11
11
|
const os = require('os')
|
|
12
|
-
const
|
|
13
|
-
const Config = require('../config/')
|
|
12
|
+
const parseLabels = require('../util/label-parser')
|
|
14
13
|
|
|
15
14
|
module.exports = facts
|
|
16
15
|
|
|
17
16
|
function facts(agent, callback) {
|
|
18
17
|
var startTime = Date.now()
|
|
19
|
-
a.parallel(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
18
|
+
a.parallel(
|
|
19
|
+
{
|
|
20
|
+
systemInfo: a.apply(fetchSystemInfo, agent),
|
|
21
|
+
environment: agent.environment.getJSON
|
|
22
|
+
},
|
|
23
|
+
function factMapCb(err, data) {
|
|
24
|
+
logger.trace('Facts gathering finished in %dms', Date.now() - startTime)
|
|
25
|
+
|
|
26
|
+
if (err) {
|
|
27
|
+
logger.debug(err, 'Failed to load system facts!')
|
|
28
|
+
}
|
|
29
|
+
data = data || Object.create(null)
|
|
30
|
+
const systemInfo = data.systemInfo || Object.create(null)
|
|
31
|
+
const environment = data.environment || []
|
|
32
|
+
|
|
33
|
+
const hostname = agent.config.getHostnameSafe()
|
|
34
|
+
const results = {
|
|
35
|
+
utilization: {
|
|
36
|
+
metadata_version: 5,
|
|
37
|
+
logical_processors: systemInfo.logicalProcessors || null,
|
|
38
|
+
total_ram_mib: systemInfo.memory || null,
|
|
39
|
+
hostname: hostname
|
|
40
|
+
},
|
|
41
|
+
pid: process.pid,
|
|
42
|
+
host: hostname,
|
|
43
|
+
display_host: agent.config.getDisplayHost() || hostname,
|
|
44
|
+
language: 'nodejs',
|
|
45
|
+
app_name: agent.config.applications(),
|
|
46
|
+
agent_version: agent.version,
|
|
47
|
+
environment: environment,
|
|
48
|
+
settings: agent.config.publicSettings(),
|
|
49
|
+
high_security: agent.config.high_security,
|
|
50
|
+
labels: parseLabels(agent.config.labels),
|
|
51
|
+
metadata: Object.keys(process.env).reduce((obj, key) => {
|
|
52
|
+
if (key.startsWith('NEW_RELIC_METADATA_')) {
|
|
53
|
+
obj[key] = process.env[key]
|
|
54
|
+
}
|
|
55
|
+
return obj
|
|
56
|
+
}, {})
|
|
57
|
+
}
|
|
57
58
|
|
|
58
|
-
|
|
59
|
+
logger.debug('New Relic metadata %o', results.metadata)
|
|
59
60
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
results.event_harvest_config = {
|
|
62
|
+
harvest_limits: {
|
|
63
|
+
analytic_event_data: agent.config.transaction_events.max_samples_stored,
|
|
64
|
+
custom_event_data: agent.config.custom_insights_events.max_samples_stored,
|
|
65
|
+
error_event_data: agent.config.error_collector.max_event_samples_stored,
|
|
66
|
+
span_event_data: agent.config.span_events.max_samples_stored
|
|
67
|
+
}
|
|
66
68
|
}
|
|
67
|
-
}
|
|
68
69
|
|
|
69
|
-
|
|
70
|
+
results.identifier = getIdentifierOverride(results.app_name)
|
|
70
71
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
const ipAddresses = getAllIPAddresses()
|
|
73
|
+
if (ipAddresses.length) {
|
|
74
|
+
results.utilization.ip_address = ipAddresses
|
|
75
|
+
}
|
|
75
76
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
if (systemInfo.bootId) {
|
|
78
|
+
results.utilization.boot_id = systemInfo.bootId
|
|
79
|
+
}
|
|
79
80
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
if (systemInfo.vendors) {
|
|
82
|
+
results.utilization.vendors = systemInfo.vendors
|
|
83
|
+
}
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
if (systemInfo.config) {
|
|
86
|
+
results.utilization.config = systemInfo.config
|
|
87
|
+
}
|
|
87
88
|
|
|
88
|
-
|
|
89
|
-
|
|
89
|
+
return callback(results)
|
|
90
|
+
}
|
|
91
|
+
)
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
function getAllIPAddresses() {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
var parse = require('url').parse
|
|
9
9
|
var ProxyAgent = require('https-proxy-agent')
|
|
10
|
-
var logger = require('../logger').child({component: 'http-agent'})
|
|
10
|
+
var logger = require('../logger').child({ component: 'http-agent' })
|
|
11
11
|
var certificates = require('./ssl/certificates.js')
|
|
12
12
|
|
|
13
13
|
const https = require('https')
|
|
@@ -51,56 +51,59 @@ exports.proxyAgent = function proxyAgent(config) {
|
|
|
51
51
|
return agentProxyWithKeepAlive
|
|
52
52
|
}
|
|
53
53
|
var opts = proxyOptions(config)
|
|
54
|
-
var
|
|
54
|
+
var proxyUrl = opts.proxy_url
|
|
55
55
|
|
|
56
|
-
var
|
|
57
|
-
host:
|
|
58
|
-
port:
|
|
59
|
-
protocol:
|
|
56
|
+
var proxyOpts = {
|
|
57
|
+
host: proxyUrl.host,
|
|
58
|
+
port: proxyUrl.port,
|
|
59
|
+
protocol: proxyUrl.protocol,
|
|
60
60
|
secureEndpoint: config.ssl,
|
|
61
|
-
auth:
|
|
61
|
+
auth: proxyUrl.auth,
|
|
62
62
|
ca: opts.certificates,
|
|
63
63
|
keepAlive: true
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
logger.info(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
66
|
+
logger.info(
|
|
67
|
+
{
|
|
68
|
+
host: proxyOpts.host,
|
|
69
|
+
port: proxyOpts.port,
|
|
70
|
+
auth: !!proxyOpts.auth,
|
|
71
|
+
protocol: proxyUrl.protocol
|
|
72
|
+
},
|
|
73
|
+
'using proxy'
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
agentProxyWithKeepAlive = new ProxyAgent(proxyOpts)
|
|
74
77
|
return agentProxyWithKeepAlive
|
|
75
78
|
}
|
|
76
79
|
|
|
77
80
|
function proxyOptions(config) {
|
|
78
81
|
if (config.proxy) {
|
|
79
|
-
var
|
|
82
|
+
var parsedUrl = parse(config.proxy)
|
|
80
83
|
|
|
81
|
-
var
|
|
82
|
-
protocol:
|
|
83
|
-
host:
|
|
84
|
-
port:
|
|
85
|
-
auth:
|
|
84
|
+
var proxyUrl = {
|
|
85
|
+
protocol: parsedUrl.protocol || 'https:',
|
|
86
|
+
host: parsedUrl.hostname,
|
|
87
|
+
port: parsedUrl.port || 80,
|
|
88
|
+
auth: parsedUrl.auth
|
|
86
89
|
}
|
|
87
90
|
} else {
|
|
88
|
-
var
|
|
91
|
+
var proxyAuth = config.proxy_user
|
|
89
92
|
if (config.proxy_pass !== '') {
|
|
90
|
-
|
|
93
|
+
proxyAuth += ':' + config.proxy_pass
|
|
91
94
|
}
|
|
92
95
|
|
|
93
96
|
// Unless a proxy config is provided, default to HTTP.
|
|
94
|
-
|
|
97
|
+
proxyUrl = {
|
|
95
98
|
protocol: 'https:',
|
|
96
99
|
host: config.proxy_host || 'localhost',
|
|
97
100
|
port: config.proxy_port || 80,
|
|
98
|
-
auth:
|
|
101
|
+
auth: proxyAuth
|
|
99
102
|
}
|
|
100
103
|
}
|
|
101
104
|
|
|
102
105
|
var opts = {
|
|
103
|
-
proxy_url:
|
|
106
|
+
proxy_url: proxyUrl
|
|
104
107
|
}
|
|
105
108
|
|
|
106
109
|
if (config.certificates && config.certificates.length > 0) {
|
|
@@ -110,7 +113,7 @@ function proxyOptions(config) {
|
|
|
110
113
|
if (config.feature_flag.certificate_bundle) {
|
|
111
114
|
logger.info(
|
|
112
115
|
'Using a proxy with a special cert. This enables our cert bundle which, combined ' +
|
|
113
|
-
|
|
116
|
+
'with some versions of node, exacerbates a leak in node core TLS.'
|
|
114
117
|
)
|
|
115
118
|
|
|
116
119
|
const certWarningMessage = [
|
|
@@ -9,7 +9,7 @@ var util = require('util')
|
|
|
9
9
|
var url = require('url')
|
|
10
10
|
var https = require('https')
|
|
11
11
|
var zlib = require('zlib')
|
|
12
|
-
var logger = require('../logger').child({component: 'remote_method'})
|
|
12
|
+
var logger = require('../logger').child({ component: 'remote_method' })
|
|
13
13
|
var parse = require('./parse-response')
|
|
14
14
|
var stringify = require('json-stringify-safe')
|
|
15
15
|
var Sink = require('../util/stream-sink')
|
|
@@ -76,13 +76,20 @@ RemoteMethod.prototype.invoke = function invoke(payload, nrHeaders, callback) {
|
|
|
76
76
|
nrHeaders = null
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
if (!payload)
|
|
79
|
+
if (!payload) {
|
|
80
|
+
payload = []
|
|
81
|
+
}
|
|
80
82
|
logger.trace('Invoking remote method %s', this.name)
|
|
81
83
|
|
|
82
|
-
this.serialize(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
this.serialize(
|
|
85
|
+
payload,
|
|
86
|
+
function onSerialize(err, serialized) {
|
|
87
|
+
if (err) {
|
|
88
|
+
return callback(err)
|
|
89
|
+
}
|
|
90
|
+
this._post(serialized, nrHeaders, callback)
|
|
91
|
+
}.bind(this)
|
|
92
|
+
)
|
|
86
93
|
}
|
|
87
94
|
|
|
88
95
|
/**
|
|
@@ -108,11 +115,7 @@ RemoteMethod.prototype._post = function _post(data, nrHeaders, callback) {
|
|
|
108
115
|
|
|
109
116
|
// Check trace enabled first since we're creating an object for this log message.
|
|
110
117
|
if (logger.traceEnabled()) {
|
|
111
|
-
logger.trace(
|
|
112
|
-
{data, compressed: options.compressed},
|
|
113
|
-
'Calling %s on collector API',
|
|
114
|
-
this.name
|
|
115
|
-
)
|
|
118
|
+
logger.trace({ data, compressed: options.compressed }, 'Calling %s on collector API', this.name)
|
|
116
119
|
}
|
|
117
120
|
|
|
118
121
|
if (options.compressed) {
|
|
@@ -150,10 +153,7 @@ RemoteMethod.prototype._post = function _post(data, nrHeaders, callback) {
|
|
|
150
153
|
// set up standard response handling
|
|
151
154
|
function onResponse(response) {
|
|
152
155
|
response.on('end', function onEnd() {
|
|
153
|
-
logger.debug(
|
|
154
|
-
'Finished receiving data back from the collector for %s.',
|
|
155
|
-
method.name
|
|
156
|
-
)
|
|
156
|
+
logger.debug('Finished receiving data back from the collector for %s.', method.name)
|
|
157
157
|
})
|
|
158
158
|
|
|
159
159
|
response.setEncoding('utf8')
|
|
@@ -175,13 +175,27 @@ RemoteMethod.prototype._post = function _post(data, nrHeaders, callback) {
|
|
|
175
175
|
* @param {object} options A dictionary of request parameters.
|
|
176
176
|
*/
|
|
177
177
|
RemoteMethod.prototype._safeRequest = function _safeRequest(options) {
|
|
178
|
-
if (!options)
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if (!options.
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
if (!options.
|
|
178
|
+
if (!options) {
|
|
179
|
+
throw new Error('Must include options to make request!')
|
|
180
|
+
}
|
|
181
|
+
if (!options.host) {
|
|
182
|
+
throw new Error('Must include collector hostname!')
|
|
183
|
+
}
|
|
184
|
+
if (!options.port) {
|
|
185
|
+
throw new Error('Must include collector port!')
|
|
186
|
+
}
|
|
187
|
+
if (!options.onError) {
|
|
188
|
+
throw new Error('Must include error handler!')
|
|
189
|
+
}
|
|
190
|
+
if (!options.onResponse) {
|
|
191
|
+
throw new Error('Must include response handler!')
|
|
192
|
+
}
|
|
193
|
+
if (!options.body) {
|
|
194
|
+
throw new Error('Must include body to send to collector!')
|
|
195
|
+
}
|
|
196
|
+
if (!options.path) {
|
|
197
|
+
throw new Error('Must include URL to request!')
|
|
198
|
+
}
|
|
185
199
|
|
|
186
200
|
var protocol = 'https'
|
|
187
201
|
var logConfig = this._config.logging
|
|
@@ -209,10 +223,9 @@ RemoteMethod.prototype._safeRequest = function _safeRequest(options) {
|
|
|
209
223
|
}
|
|
210
224
|
}
|
|
211
225
|
|
|
212
|
-
const logBody =
|
|
213
|
-
Buffer.isBuffer(options.body) ? 'Buffer ' + options.body.length : options.body
|
|
226
|
+
const logBody = Buffer.isBuffer(options.body) ? 'Buffer ' + options.body.length : options.body
|
|
214
227
|
logger[level](
|
|
215
|
-
{body: logBody},
|
|
228
|
+
{ body: logBody },
|
|
216
229
|
'Posting to %s://%s:%s%s',
|
|
217
230
|
protocol,
|
|
218
231
|
options.host,
|
|
@@ -241,21 +254,17 @@ RemoteMethod.prototype._safeRequest = function _safeRequest(options) {
|
|
|
241
254
|
RemoteMethod.prototype._request = function _request(options) {
|
|
242
255
|
var requestOptions = {
|
|
243
256
|
method: this._config.put_for_data_send ? 'PUT' : 'POST',
|
|
244
|
-
setHost: false,
|
|
245
|
-
host: options.host,
|
|
257
|
+
setHost: false, // See below
|
|
258
|
+
host: options.host, // Set explicitly in the headers
|
|
246
259
|
port: options.port,
|
|
247
260
|
path: options.path,
|
|
248
261
|
headers: this._headers(options),
|
|
249
262
|
agent: agents.keepAliveAgent(),
|
|
250
|
-
__NR__connection: true
|
|
263
|
+
__NR__connection: true // Who measures the metrics measurer?
|
|
251
264
|
}
|
|
252
265
|
var request
|
|
253
266
|
|
|
254
|
-
var isProxy = !!(
|
|
255
|
-
this._config.proxy ||
|
|
256
|
-
this._config.proxy_port ||
|
|
257
|
-
this._config.proxy_host
|
|
258
|
-
)
|
|
267
|
+
var isProxy = !!(this._config.proxy || this._config.proxy_port || this._config.proxy_host)
|
|
259
268
|
|
|
260
269
|
if (isProxy) {
|
|
261
270
|
// proxy
|
|
@@ -266,9 +275,7 @@ RemoteMethod.prototype._request = function _request(options) {
|
|
|
266
275
|
requestOptions.ca = this._config.certificates
|
|
267
276
|
|
|
268
277
|
if (this._config.feature_flag.certificate_bundle) {
|
|
269
|
-
logger.debug(
|
|
270
|
-
'Adding custom certificate to the cert bundle.'
|
|
271
|
-
)
|
|
278
|
+
logger.debug('Adding custom certificate to the cert bundle.')
|
|
272
279
|
|
|
273
280
|
const certWarningMessage = [
|
|
274
281
|
'Deprecation Warning: The certificate bundle included by New Relic will be ',
|