newrelic 8.0.0 → 8.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NEWS.md +5023 -4922
- package/THIRD_PARTY_NOTICES.md +618 -209
- package/api.js +156 -219
- package/bin/test-naming-rules.js +57 -51
- package/bin/tracetractor +0 -1
- package/index.js +7 -14
- package/lib/agent.js +111 -114
- package/lib/aggregators/base-aggregator.js +1 -1
- package/lib/aggregators/event-aggregator.js +6 -6
- package/lib/attributes.js +13 -14
- package/lib/collector/api.js +44 -54
- package/lib/collector/facts.js +68 -66
- package/lib/collector/http-agents.js +36 -32
- package/lib/collector/key-parser.js +1 -1
- package/lib/collector/parse-response.js +1 -2
- package/lib/collector/remote-method.js +69 -61
- package/lib/collector/serverless.js +13 -18
- package/lib/collector/ssl/certificates.js +1056 -1056
- package/lib/config/attribute-filter.js +109 -101
- package/lib/config/default.js +35 -21
- package/lib/config/env.js +17 -12
- package/lib/config/harvest-config-validator.js +1 -1
- package/lib/config/hsm.js +1 -1
- package/lib/config/index.js +240 -234
- package/lib/config/lasp.js +3 -3
- package/lib/config/merge-server-config.js +8 -6
- package/lib/custom-events/custom-event-aggregator.js +1 -1
- package/lib/db/parse-sql.js +13 -16
- package/lib/db/parsed-statement.js +13 -19
- package/lib/db/query-parsers/sql.js +12 -15
- package/lib/db/query-sample.js +16 -12
- package/lib/db/query-trace-aggregator.js +16 -16
- package/lib/db/statement-matcher.js +5 -5
- package/lib/db/utils.js +2 -2
- package/lib/environment.js +210 -175
- package/lib/errors/error-collector.js +20 -33
- package/lib/errors/error-event-aggregator.js +1 -1
- package/lib/errors/error-trace-aggregator.js +3 -4
- package/lib/errors/helper.js +23 -32
- package/lib/errors/index.js +31 -43
- package/lib/feature_flags.js +3 -4
- package/lib/grpc/connection/states.js +6 -6
- package/lib/grpc/connection.js +35 -46
- package/lib/header-attributes.js +55 -59
- package/lib/header-processing.js +1 -1
- package/lib/instrumentation/amqplib.js +34 -43
- package/lib/instrumentation/bluebird.js +63 -22
- package/lib/instrumentation/cassandra-driver.js +8 -4
- package/lib/instrumentation/connect.js +7 -6
- package/lib/instrumentation/core/async_hooks.js +16 -9
- package/lib/instrumentation/core/child_process.js +20 -28
- package/lib/instrumentation/core/crypto.js +1 -7
- package/lib/instrumentation/core/dns.js +3 -7
- package/lib/instrumentation/core/domain.js +4 -10
- package/lib/instrumentation/core/fs.js +22 -37
- package/lib/instrumentation/core/globals.js +4 -8
- package/lib/instrumentation/core/http-outbound.js +20 -114
- package/lib/instrumentation/core/http.js +61 -128
- package/lib/instrumentation/core/inspector.js +7 -11
- package/lib/instrumentation/core/net.js +3 -1
- package/lib/instrumentation/core/timers.js +21 -28
- package/lib/instrumentation/core/zlib.js +3 -11
- package/lib/instrumentation/director.js +4 -4
- package/lib/instrumentation/express.js +12 -10
- package/lib/instrumentation/fastify/spec-builders.js +5 -0
- package/lib/instrumentation/fastify.js +37 -10
- package/lib/instrumentation/generic-pool.js +1 -1
- package/lib/instrumentation/hapi/hapi-17.js +20 -21
- package/lib/instrumentation/hapi/shared.js +1 -1
- package/lib/instrumentation/hapi.js +37 -37
- package/lib/instrumentation/ioredis.js +8 -9
- package/lib/instrumentation/memcached.js +41 -45
- package/lib/instrumentation/mongodb/common.js +221 -0
- package/lib/instrumentation/mongodb/constants.js +87 -0
- package/lib/instrumentation/mongodb/v2-mongo.js +110 -0
- package/lib/instrumentation/mongodb/v3-mongo.js +80 -0
- package/lib/instrumentation/mongodb/v4-mongo.js +90 -0
- package/lib/instrumentation/mongodb.js +20 -312
- package/lib/instrumentation/mysql.js +51 -44
- package/lib/instrumentation/oracle.js +24 -28
- package/lib/instrumentation/pg.js +34 -25
- package/lib/instrumentation/promise.js +65 -62
- package/lib/instrumentation/q.js +2 -2
- package/lib/instrumentation/redis.js +38 -38
- package/lib/instrumentation/restify.js +1 -1
- package/lib/instrumentation/vision.js +4 -4
- package/lib/instrumentation/when.js +12 -4
- package/lib/instrumentations.js +25 -25
- package/lib/logger.js +6 -6
- package/lib/metrics/index.js +50 -30
- package/lib/metrics/mapper.js +15 -15
- package/lib/metrics/metric-aggregator.js +5 -10
- package/lib/metrics/names.js +8 -7
- package/lib/metrics/normalizer/rule.js +14 -15
- package/lib/metrics/normalizer/tx_segment.js +33 -29
- package/lib/metrics/normalizer.js +51 -54
- package/lib/metrics/recorders/custom.js +8 -6
- package/lib/metrics/recorders/distributed-trace.js +3 -18
- package/lib/metrics/recorders/generic.js +6 -5
- package/lib/metrics/recorders/http.js +11 -13
- package/lib/metrics/recorders/http_external.js +8 -10
- package/lib/metrics/recorders/message-transaction.js +7 -18
- package/lib/metrics/recorders/other.js +7 -17
- package/lib/parse-proc-cpuinfo.js +26 -31
- package/lib/parse-proc-meminfo.js +5 -3
- package/lib/prioritized-attributes.js +14 -19
- package/lib/priority-queue.js +11 -11
- package/lib/proxy/grpc.js +1 -1
- package/lib/reservoir.js +12 -6
- package/lib/sampler.js +33 -34
- package/lib/serverless/api-gateway.js +3 -3
- package/lib/serverless/aws-lambda.js +28 -37
- package/lib/shim/conglomerate-shim.js +4 -4
- package/lib/shim/datastore-shim.js +61 -67
- package/lib/shim/index.js +10 -11
- package/lib/shim/message-shim.js +149 -151
- package/lib/shim/promise-shim.js +19 -14
- package/lib/shim/shim.js +131 -125
- package/lib/shim/specs/index.js +21 -22
- package/lib/shim/transaction-shim.js +52 -210
- package/lib/shim/webframework-shim.js +75 -85
- package/lib/shimmer.js +184 -166
- package/lib/spans/create-span-event-aggregator.js +11 -8
- package/lib/spans/span-context.js +4 -10
- package/lib/spans/span-event-aggregator.js +68 -13
- package/lib/spans/span-event.js +6 -8
- package/lib/spans/span-streamer.js +10 -18
- package/lib/spans/streaming-span-attributes.js +1 -1
- package/lib/spans/streaming-span-event-aggregator.js +1 -1
- package/lib/spans/streaming-span-event.js +4 -4
- package/lib/stats/apdex.js +7 -13
- package/lib/stats/index.js +14 -19
- package/lib/system-info.js +29 -25
- package/lib/timer.js +35 -21
- package/lib/transaction/dt-payload.js +1 -1
- package/lib/transaction/handle.js +19 -19
- package/lib/transaction/index.js +133 -151
- package/lib/transaction/name-state.js +18 -19
- package/lib/transaction/trace/aggregator.js +78 -73
- package/lib/transaction/trace/exclusive-time-calculator.js +9 -13
- package/lib/transaction/trace/index.js +37 -35
- package/lib/transaction/trace/segment.js +56 -73
- package/lib/transaction/tracecontext.js +38 -46
- package/lib/transaction/tracer/index.js +130 -91
- package/lib/transaction/transaction-event-aggregator.js +29 -31
- package/lib/uninstrumented.js +11 -12
- package/lib/util/arity.js +2 -2
- package/lib/util/attribute-types.js +1 -5
- package/lib/util/byte-limit.js +4 -5
- package/lib/util/cat.js +270 -33
- package/lib/util/codec.js +10 -6
- package/lib/util/copy.js +2 -2
- package/lib/util/deep-equal.js +51 -21
- package/lib/util/flatten.js +9 -6
- package/lib/util/hashes.js +16 -16
- package/lib/util/label-parser.js +22 -28
- package/lib/util/logger.js +53 -35
- package/lib/util/process-version.js +3 -3
- package/lib/util/properties.js +5 -5
- package/lib/util/sql/obfuscate.js +21 -31
- package/lib/util/stream-sink.js +5 -6
- package/lib/util/unwrapped-core.js +2 -2
- package/lib/util/urltils.js +26 -30
- package/lib/utilization/aws-info.js +8 -9
- package/lib/utilization/azure-info.js +37 -35
- package/lib/utilization/common.js +17 -16
- package/lib/utilization/docker-info.js +14 -16
- package/lib/utilization/gcp-info.js +38 -37
- package/lib/utilization/index.js +5 -5
- package/lib/utilization/kubernetes-info.js +2 -2
- package/lib/utilization/pcf-info.js +12 -12
- package/package.json +23 -6
- package/stub_api.js +16 -14
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
8
|
const Aggregator = require('./base-aggregator')
|
|
9
|
-
const logger = require('../logger').child({component: 'event_aggregator'})
|
|
9
|
+
const logger = require('../logger').child({ component: 'event_aggregator' })
|
|
10
10
|
const PriorityQueue = require('../priority-queue')
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -49,7 +49,7 @@ class EventAggregator extends Aggregator {
|
|
|
49
49
|
|
|
50
50
|
const didAdd = this.addEvent.apply(this, arguments)
|
|
51
51
|
|
|
52
|
-
if (didAdd &&
|
|
52
|
+
if (didAdd && this._items.overflow() === 0) {
|
|
53
53
|
this._metrics.getOrCreateMetric(this._metricNames.SENT).incrementCallCount()
|
|
54
54
|
} else {
|
|
55
55
|
this._metrics.getOrCreateMetric(this._metricNames.DROPPED).incrementCallCount()
|
|
@@ -129,7 +129,9 @@ class EventAggregator extends Aggregator {
|
|
|
129
129
|
const toMerge = Math.min(events.length, this.limit - this.length)
|
|
130
130
|
logger.warn(
|
|
131
131
|
'Merging %d of %d events into %s for next harvest',
|
|
132
|
-
toMerge,
|
|
132
|
+
toMerge,
|
|
133
|
+
events.length,
|
|
134
|
+
this.constructor.name
|
|
133
135
|
)
|
|
134
136
|
|
|
135
137
|
const seen = events.length
|
|
@@ -140,9 +142,7 @@ class EventAggregator extends Aggregator {
|
|
|
140
142
|
this._metrics.getOrCreateMetric(this._metricNames.SENT).incrementCallCount(sent)
|
|
141
143
|
|
|
142
144
|
if (dropped > 0) {
|
|
143
|
-
this._metrics
|
|
144
|
-
.getOrCreateMetric(this._metricNames.DROPPED)
|
|
145
|
-
.incrementCallCount(dropped)
|
|
145
|
+
this._metrics.getOrCreateMetric(this._metricNames.DROPPED).incrementCallCount(dropped)
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
// merge modifies incoming events collection.
|
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 (const 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
|
|
@@ -145,7 +144,7 @@ class Attributes {
|
|
|
145
144
|
* @param {object} attrs - The attributes to add.
|
|
146
145
|
*/
|
|
147
146
|
addAttributes(destinations, attrs) {
|
|
148
|
-
for (
|
|
147
|
+
for (const key in attrs) {
|
|
149
148
|
if (properties.hasOwn(attrs, key)) {
|
|
150
149
|
this.addAttribute(destinations, key, attrs[key])
|
|
151
150
|
}
|
|
@@ -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,26 +19,24 @@ 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
|
|
|
40
38
|
function dumpErrors(errors, name) {
|
|
41
|
-
|
|
39
|
+
let index = 1
|
|
42
40
|
|
|
43
41
|
errors.forEach(function forEachError(error) {
|
|
44
42
|
logger.trace(error, 'Error %s during %s:', index++, name)
|
|
@@ -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
|
+
const 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(
|
|
@@ -194,9 +192,9 @@ CollectorAPI.prototype.connect = function connect(callback) {
|
|
|
194
192
|
}
|
|
195
193
|
|
|
196
194
|
CollectorAPI.prototype._login = function _login(callback) {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
195
|
+
const methods = this._methods
|
|
196
|
+
const agent = this._agent
|
|
197
|
+
const self = this
|
|
200
198
|
|
|
201
199
|
const preconnectData = { high_security: agent.config.high_security }
|
|
202
200
|
if (agent.config.security_policies_token) {
|
|
@@ -219,7 +217,7 @@ CollectorAPI.prototype._login = function _login(callback) {
|
|
|
219
217
|
agent.config.host
|
|
220
218
|
)
|
|
221
219
|
} else {
|
|
222
|
-
|
|
220
|
+
const parts = res.redirect_host.split(':')
|
|
223
221
|
if (parts.length > 2) {
|
|
224
222
|
logger.error(
|
|
225
223
|
"Requesting collector from %s returned bogus result '%s'; trying default.",
|
|
@@ -243,7 +241,7 @@ CollectorAPI.prototype._login = function _login(callback) {
|
|
|
243
241
|
}
|
|
244
242
|
}
|
|
245
243
|
|
|
246
|
-
|
|
244
|
+
const policies = res.security_policies || Object.create(null)
|
|
247
245
|
|
|
248
246
|
const laspResponse = agent.config.applyLasp(agent, policies)
|
|
249
247
|
if (laspResponse.shouldShutdownRun()) {
|
|
@@ -255,8 +253,8 @@ CollectorAPI.prototype._login = function _login(callback) {
|
|
|
255
253
|
}
|
|
256
254
|
|
|
257
255
|
CollectorAPI.prototype._getFacts = function _getFacts(lasp, callback) {
|
|
258
|
-
|
|
259
|
-
|
|
256
|
+
const agent = this._agent
|
|
257
|
+
const self = this
|
|
260
258
|
|
|
261
259
|
facts(agent, function getEnvDict(environmentDict) {
|
|
262
260
|
if (lasp) {
|
|
@@ -265,7 +263,7 @@ CollectorAPI.prototype._getFacts = function _getFacts(lasp, callback) {
|
|
|
265
263
|
|
|
266
264
|
// The collector really likes arrays.
|
|
267
265
|
// In fact, it kind of insists on them.
|
|
268
|
-
|
|
266
|
+
const environment = [environmentDict]
|
|
269
267
|
|
|
270
268
|
self._connect(environment, callback)
|
|
271
269
|
})
|
|
@@ -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
|
}
|
|
@@ -489,7 +491,7 @@ CollectorAPI.prototype.shutdown = function shutdown(callback) {
|
|
|
489
491
|
|
|
490
492
|
logger.info('Shutting down collector.')
|
|
491
493
|
|
|
492
|
-
|
|
494
|
+
const agent = this._agent
|
|
493
495
|
this._methods.shutdown.invoke(null, this._reqHeadersMap, onShutdown)
|
|
494
496
|
|
|
495
497
|
function onShutdown(error, response) {
|
|
@@ -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))
|
|
@@ -512,12 +511,11 @@ CollectorAPI.prototype.restart = function restart(callback) {
|
|
|
512
511
|
logger.info('Restarting collector.')
|
|
513
512
|
|
|
514
513
|
this._agent.stopAggregators()
|
|
515
|
-
|
|
514
|
+
const 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
|
-
|
|
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
|
-
|
|
17
|
+
const startTime = Date.now()
|
|
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() {
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
const parse = require('url').parse
|
|
9
|
+
const ProxyAgent = require('https-proxy-agent')
|
|
10
|
+
const logger = require('../logger').child({ component: 'http-agent' })
|
|
11
|
+
const certificates = require('./ssl/certificates.js')
|
|
12
12
|
|
|
13
13
|
const https = require('https')
|
|
14
14
|
|
|
@@ -50,57 +50,61 @@ exports.proxyAgent = function proxyAgent(config) {
|
|
|
50
50
|
if (null !== agentProxyWithKeepAlive) {
|
|
51
51
|
return agentProxyWithKeepAlive
|
|
52
52
|
}
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
const opts = proxyOptions(config)
|
|
54
|
+
const proxyUrl = opts.proxy_url
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
host:
|
|
58
|
-
port:
|
|
59
|
-
protocol:
|
|
56
|
+
const 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) {
|
|
81
|
+
let proxyUrl
|
|
78
82
|
if (config.proxy) {
|
|
79
|
-
|
|
83
|
+
const parsedUrl = parse(config.proxy)
|
|
80
84
|
|
|
81
|
-
|
|
82
|
-
protocol:
|
|
83
|
-
host:
|
|
84
|
-
port:
|
|
85
|
-
auth:
|
|
85
|
+
proxyUrl = {
|
|
86
|
+
protocol: parsedUrl.protocol || 'https:',
|
|
87
|
+
host: parsedUrl.hostname,
|
|
88
|
+
port: parsedUrl.port || 80,
|
|
89
|
+
auth: parsedUrl.auth
|
|
86
90
|
}
|
|
87
91
|
} else {
|
|
88
|
-
|
|
92
|
+
let proxyAuth = config.proxy_user
|
|
89
93
|
if (config.proxy_pass !== '') {
|
|
90
|
-
|
|
94
|
+
proxyAuth += ':' + config.proxy_pass
|
|
91
95
|
}
|
|
92
96
|
|
|
93
97
|
// Unless a proxy config is provided, default to HTTP.
|
|
94
|
-
|
|
98
|
+
proxyUrl = {
|
|
95
99
|
protocol: 'https:',
|
|
96
100
|
host: config.proxy_host || 'localhost',
|
|
97
101
|
port: config.proxy_port || 80,
|
|
98
|
-
auth:
|
|
102
|
+
auth: proxyAuth
|
|
99
103
|
}
|
|
100
104
|
}
|
|
101
105
|
|
|
102
|
-
|
|
103
|
-
proxy_url:
|
|
106
|
+
const opts = {
|
|
107
|
+
proxy_url: proxyUrl
|
|
104
108
|
}
|
|
105
109
|
|
|
106
110
|
if (config.certificates && config.certificates.length > 0) {
|
|
@@ -110,7 +114,7 @@ function proxyOptions(config) {
|
|
|
110
114
|
if (config.feature_flag.certificate_bundle) {
|
|
111
115
|
logger.info(
|
|
112
116
|
'Using a proxy with a special cert. This enables our cert bundle which, combined ' +
|
|
113
|
-
|
|
117
|
+
'with some versions of node, exacerbates a leak in node core TLS.'
|
|
114
118
|
)
|
|
115
119
|
|
|
116
120
|
const certWarningMessage = [
|