newrelic 9.6.0 → 9.7.1
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 +40 -16
- package/THIRD_PARTY_NOTICES.md +203 -2
- package/api.js +155 -101
- package/bin/test-naming-rules.js +1 -1
- package/esm-loader.mjs +1 -3
- package/lib/adaptive-sampler.js +1 -2
- package/lib/agent.js +29 -80
- package/lib/aggregators/event-aggregator.js +2 -2
- package/lib/attributes.js +2 -4
- package/lib/collector/api.js +252 -211
- package/lib/collector/facts.js +1 -3
- package/lib/collector/parse-response.js +3 -1
- package/lib/collector/remote-method.js +8 -9
- package/lib/config/attribute-filter.js +42 -34
- package/lib/config/default.js +60 -17
- package/lib/config/harvest-config-validator.js +3 -5
- package/lib/config/index.js +263 -199
- package/lib/environment.js +22 -17
- package/lib/errors/error-collector.js +123 -51
- package/lib/errors/helper.js +10 -18
- package/lib/errors/index.js +63 -47
- package/lib/grpc/connection.js +12 -5
- package/lib/header-attributes.js +4 -2
- package/lib/header-processing.js +2 -2
- package/lib/instrumentation/@hapi/hapi.js +56 -48
- package/lib/instrumentation/@node-redis/client.js +50 -39
- package/lib/instrumentation/amqplib.js +116 -149
- package/lib/instrumentation/core/{async_hooks.js → async-hooks.js} +26 -9
- package/lib/instrumentation/core/globals.js +12 -9
- package/lib/instrumentation/core/http-outbound.js +200 -83
- package/lib/instrumentation/core/http.js +10 -8
- package/lib/instrumentation/core/timers.js +106 -57
- package/lib/instrumentation/fastify.js +1 -3
- package/lib/instrumentation/grpc-js/grpc.js +14 -3
- package/lib/instrumentation/memcached.js +5 -0
- package/lib/instrumentation/mongodb/common.js +88 -83
- package/lib/instrumentation/mongodb/v2-mongo.js +6 -3
- package/lib/instrumentation/mongodb.js +1 -1
- package/lib/instrumentation/nr-winston-transport.js +3 -4
- package/lib/instrumentation/redis.js +112 -88
- package/lib/instrumentation/undici.js +204 -190
- 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/metrics/mapper.js +2 -3
- package/lib/metrics/metric-aggregator.js +1 -3
- package/lib/metrics/names.js +19 -15
- package/lib/metrics/normalizer/rule.js +6 -7
- package/lib/metrics/normalizer/tx_segment.js +3 -2
- package/lib/metrics/normalizer.js +5 -3
- package/lib/parse-proc-cpuinfo.js +11 -6
- package/lib/serverless/api-gateway.js +3 -4
- package/lib/serverless/aws-lambda.js +3 -3
- package/lib/shim/conglomerate-shim.js +2 -3
- package/lib/shim/datastore-shim.js +22 -104
- package/lib/shim/index.js +7 -0
- package/lib/shim/message-shim.js +2 -0
- package/lib/shim/promise-shim.js +48 -42
- package/lib/shim/shim.js +9 -7
- package/lib/shim/webframework-shim.js +21 -0
- package/lib/spans/map-to-streaming-type.js +0 -2
- package/lib/spans/span-context.js +2 -0
- package/lib/spans/span-event-aggregator.js +2 -2
- package/lib/spans/span-event.js +2 -2
- package/lib/spans/span-streamer.js +4 -0
- package/lib/spans/streaming-span-event-aggregator.js +2 -4
- package/lib/spans/streaming-span-event.js +3 -2
- package/lib/symbols.js +1 -0
- package/lib/system-info.js +241 -166
- package/lib/timer.js +8 -6
- package/lib/transaction/dt-payload.js +4 -3
- package/lib/transaction/handle.js +12 -2
- package/lib/transaction/index.js +19 -18
- package/lib/transaction/name-state.js +17 -2
- package/lib/transaction/trace/aggregator.js +4 -12
- package/lib/transaction/trace/index.js +7 -5
- package/lib/transaction/trace/segment.js +6 -11
- package/lib/transaction/tracecontext.js +10 -6
- package/lib/transaction/tracer/index.js +23 -25
- package/lib/transaction/transaction-event-aggregator.js +1 -3
- package/lib/util/async-each-limit.js +30 -0
- package/lib/util/attribute-types.js +1 -2
- package/lib/util/attributes.js +159 -0
- package/lib/util/byte-limit.js +1 -3
- package/lib/util/cat.js +16 -13
- package/lib/util/code-level-metrics.js +58 -0
- package/lib/util/codec.js +0 -2
- package/lib/util/copy.js +1 -2
- package/lib/util/deep-equal.js +11 -137
- package/lib/util/flatten.js +4 -6
- package/lib/util/hashes.js +1 -3
- package/lib/util/process-version.js +2 -3
- package/lib/util/properties.js +2 -5
- package/lib/util/stream-sink.js +2 -0
- package/lib/util/urltils.js +4 -10
- package/newrelic.js +1 -1
- package/package.json +6 -4
- package/lib/instrumentation/promise.js +0 -569
package/lib/collector/api.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
+
const http = require('http')
|
|
8
9
|
const CollectorResponse = require('./response')
|
|
9
10
|
const facts = require('./facts')
|
|
10
11
|
const logger = require('../logger').child({ component: 'collector_api' })
|
|
@@ -36,8 +37,8 @@ const FAILURE_DISCARD_DATA = new Set([400, 403, 404, 405, 407, 411, 413, 414, 41
|
|
|
36
37
|
const AGENT_RUN_BEHAVIOR = CollectorResponse.AGENT_RUN_BEHAVIOR
|
|
37
38
|
|
|
38
39
|
/**
|
|
39
|
-
* @param errors
|
|
40
|
-
* @param name
|
|
40
|
+
* @param {Array} errors list of errors
|
|
41
|
+
* @param {string} name collector endpoint name
|
|
41
42
|
*/
|
|
42
43
|
function dumpErrors(errors, name) {
|
|
43
44
|
let index = 1
|
|
@@ -54,7 +55,7 @@ function dumpErrors(errors, name) {
|
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
/**
|
|
57
|
-
* @param agent
|
|
58
|
+
* @param {Agent} agent New Relic agent
|
|
58
59
|
*/
|
|
59
60
|
function CollectorAPI(agent) {
|
|
60
61
|
this._agent = agent
|
|
@@ -89,11 +90,15 @@ function CollectorAPI(agent) {
|
|
|
89
90
|
}
|
|
90
91
|
}
|
|
91
92
|
|
|
93
|
+
CollectorAPI.prototype._throwCallbackError = function _throwCallbackError() {
|
|
94
|
+
throw new TypeError('callback is required')
|
|
95
|
+
}
|
|
96
|
+
|
|
92
97
|
/**
|
|
93
98
|
* Updates all methods except preconnect w/ new host/port pairs sent down from server
|
|
94
99
|
* during preconnect (via redirect_host). Preconnect does not update.
|
|
95
100
|
*
|
|
96
|
-
* @param endpoint
|
|
101
|
+
* @param {string} endpoint collector name
|
|
97
102
|
*/
|
|
98
103
|
CollectorAPI.prototype._updateEndpoints = function _updateEndpoints(endpoint) {
|
|
99
104
|
logger.trace('Updating endpoints to: ', endpoint)
|
|
@@ -107,112 +112,116 @@ CollectorAPI.prototype._updateEndpoints = function _updateEndpoints(endpoint) {
|
|
|
107
112
|
|
|
108
113
|
CollectorAPI.prototype.connect = function connect(callback) {
|
|
109
114
|
if (!callback) {
|
|
110
|
-
|
|
115
|
+
this._throwCallbackError()
|
|
111
116
|
}
|
|
112
117
|
|
|
113
118
|
logger.trace('Starting collector.')
|
|
114
119
|
|
|
115
120
|
this._agent.setState('connecting')
|
|
116
121
|
|
|
117
|
-
const api = this
|
|
118
|
-
const max = BACKOFFS.length
|
|
119
|
-
const errors = []
|
|
120
|
-
let attempts = 1
|
|
121
|
-
|
|
122
|
-
const metric = this._agent.metrics.getOrCreateMetric(
|
|
123
|
-
NAMES.SUPPORTABILITY.REGISTRATION + '/Attempts'
|
|
124
|
-
)
|
|
125
|
-
|
|
126
122
|
// Reset headers map for good measure
|
|
127
123
|
if (this._reqHeadersMap) {
|
|
128
124
|
this._reqHeadersMap = null
|
|
129
125
|
}
|
|
130
126
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
*
|
|
137
|
-
* @param {Error} error
|
|
138
|
-
* @returns {boolean}
|
|
139
|
-
*/
|
|
140
|
-
function isProxyMisconfigured(error) {
|
|
141
|
-
const config = api._agent.config
|
|
142
|
-
return (
|
|
143
|
-
error &&
|
|
144
|
-
['EPROTO', 'ECONNRESET'].includes(error.code) &&
|
|
145
|
-
config.proxy_host &&
|
|
146
|
-
config.proxy_port &&
|
|
147
|
-
!config.proxy
|
|
148
|
-
)
|
|
127
|
+
const ctx = {
|
|
128
|
+
callback,
|
|
129
|
+
max: BACKOFFS.length,
|
|
130
|
+
errors: [],
|
|
131
|
+
attempts: 1
|
|
149
132
|
}
|
|
133
|
+
this._login(this._retry.bind(this, ctx))
|
|
134
|
+
}
|
|
150
135
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
136
|
+
/**
|
|
137
|
+
* Checks if proxy is configured to connect via `proxy_host` and `proxy_port`
|
|
138
|
+
* and if error code is EPROTO or ECONNRESET. This is an indication their proxy
|
|
139
|
+
* server only accepts HTTP connections, and we should provide an actionable warning to
|
|
140
|
+
* fix the misconfiguration by setting `proxy` to a fully qualified URL
|
|
141
|
+
*
|
|
142
|
+
* @param {Error} error response error
|
|
143
|
+
* @returns {boolean} determines if proxy is properly configured
|
|
144
|
+
*/
|
|
145
|
+
CollectorAPI.prototype._isProxyMisconfigured = function _isProxyMisconfigured(error) {
|
|
146
|
+
const config = this._agent.config
|
|
147
|
+
return (
|
|
148
|
+
error &&
|
|
149
|
+
['EPROTO', 'ECONNRESET'].includes(error.code) &&
|
|
150
|
+
config.proxy_host &&
|
|
151
|
+
config.proxy_port &&
|
|
152
|
+
!config.proxy
|
|
153
|
+
)
|
|
154
|
+
}
|
|
157
155
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
156
|
+
/**
|
|
157
|
+
* @param {object} ctx context object to pass from parent and between recursions.
|
|
158
|
+
* @param {Error} error response error
|
|
159
|
+
* @param {http.ServerResponse} response response from collector
|
|
160
|
+
* @returns {void}
|
|
161
|
+
*/
|
|
162
|
+
CollectorAPI.prototype._retry = function _retry(ctx, error, response) {
|
|
163
|
+
const api = this
|
|
164
|
+
const metric = this._agent.metrics.getOrCreateMetric(
|
|
165
|
+
NAMES.SUPPORTABILITY.REGISTRATION + '/Attempts'
|
|
166
|
+
)
|
|
167
167
|
|
|
168
|
-
|
|
169
|
-
if (response.status === 410 || response.agentRun === AGENT_RUN_BEHAVIOR.SHUTDOWN) {
|
|
170
|
-
logger.error('The New Relic collector rejected this agent.')
|
|
171
|
-
return callback(null, CollectorResponse.fatal(response.payload))
|
|
172
|
-
} else if (response.status === 401) {
|
|
173
|
-
logger.warn(
|
|
174
|
-
error,
|
|
175
|
-
'Your license key appears to be invalid. Reattempting connection to New' +
|
|
176
|
-
' Relic. If the problem persists, please contact support@newrelic.com.' +
|
|
177
|
-
' (status code %s)',
|
|
178
|
-
response.status
|
|
179
|
-
)
|
|
180
|
-
} else if (isProxyMisconfigured(error)) {
|
|
181
|
-
logger.warn(
|
|
182
|
-
error,
|
|
183
|
-
'Your proxy server appears to be configured to accept connections over http. ' +
|
|
184
|
-
'When setting `proxy_host` and `proxy_port` New Relic attempts to connect over ' +
|
|
185
|
-
'SSL(https). If your proxy is configured to accept connections over http, try ' +
|
|
186
|
-
'setting `proxy` to a fully qualified URL(e.g http://proxy-host:8080).'
|
|
187
|
-
)
|
|
188
|
-
}
|
|
168
|
+
metric.incrementCallCount()
|
|
189
169
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
170
|
+
if (error) {
|
|
171
|
+
ctx.errors.push(error)
|
|
172
|
+
} else if (response && SUCCESS.has(response.status)) {
|
|
173
|
+
dumpErrors(ctx.errors, 'connect')
|
|
174
|
+
ctx.callback(null, CollectorResponse.success(response.payload))
|
|
175
|
+
return
|
|
176
|
+
}
|
|
177
|
+
if (!response) {
|
|
178
|
+
response = CollectorResponse.retry()
|
|
179
|
+
}
|
|
194
180
|
|
|
195
|
-
|
|
181
|
+
// Retry everything except for an explicit Disconnect response code.
|
|
182
|
+
if (response.status === 410 || response.agentRun === AGENT_RUN_BEHAVIOR.SHUTDOWN) {
|
|
183
|
+
logger.error('The New Relic collector rejected this agent.')
|
|
184
|
+
return ctx.callback(null, CollectorResponse.fatal(response.payload))
|
|
185
|
+
} else if (response.status === 401) {
|
|
186
|
+
logger.warn(
|
|
187
|
+
error,
|
|
188
|
+
'Your license key appears to be invalid. Reattempting connection to New' +
|
|
189
|
+
' Relic. If the problem persists, please contact support@newrelic.com.' +
|
|
190
|
+
' (status code %s)',
|
|
191
|
+
response.status
|
|
192
|
+
)
|
|
193
|
+
} else if (this._isProxyMisconfigured(error)) {
|
|
194
|
+
logger.warn(
|
|
196
195
|
error,
|
|
197
|
-
'
|
|
198
|
-
|
|
199
|
-
|
|
196
|
+
'Your proxy server appears to be configured to accept connections over http. ' +
|
|
197
|
+
'When setting `proxy_host` and `proxy_port` New Relic attempts to connect over ' +
|
|
198
|
+
'SSL(https). If your proxy is configured to accept connections over http, try ' +
|
|
199
|
+
'setting `proxy` to a fully qualified URL(e.g http://proxy-host:8080).'
|
|
200
200
|
)
|
|
201
|
+
}
|
|
201
202
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}, backoff.interval * TO_MILLIS)
|
|
206
|
-
timeout.unref()
|
|
203
|
+
const backoff = BACKOFFS[Math.min(ctx.attempts, ctx.max) - 1]
|
|
204
|
+
if (backoff.warn) {
|
|
205
|
+
logger.warn('No connection has been established to New Relic after %d attempts.', ctx.attempts)
|
|
207
206
|
}
|
|
208
207
|
|
|
209
|
-
|
|
208
|
+
logger.debug(
|
|
209
|
+
error,
|
|
210
|
+
'Failed to connect to New Relic after attempt %d, waiting %ds to retry.',
|
|
211
|
+
ctx.attempts,
|
|
212
|
+
backoff.interval
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
++ctx.attempts
|
|
216
|
+
const timeout = setTimeout(function again() {
|
|
217
|
+
api._login(api._retry.bind(api, ctx))
|
|
218
|
+
}, backoff.interval * TO_MILLIS)
|
|
219
|
+
timeout.unref()
|
|
210
220
|
}
|
|
211
221
|
|
|
212
222
|
CollectorAPI.prototype._login = function _login(callback) {
|
|
213
223
|
const methods = this._methods
|
|
214
224
|
const agent = this._agent
|
|
215
|
-
const self = this
|
|
216
225
|
|
|
217
226
|
const preconnectData = { high_security: agent.config.high_security }
|
|
218
227
|
if (agent.config.security_policies_token) {
|
|
@@ -221,56 +230,73 @@ CollectorAPI.prototype._login = function _login(callback) {
|
|
|
221
230
|
|
|
222
231
|
const payload = [preconnectData]
|
|
223
232
|
|
|
224
|
-
methods.preconnect.invoke(payload,
|
|
233
|
+
methods.preconnect.invoke(payload, this._onPreConnect.bind(this, callback))
|
|
234
|
+
}
|
|
225
235
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
236
|
+
/**
|
|
237
|
+
* @param {Function} callback function to run after processing response
|
|
238
|
+
* @param {Error} error response error
|
|
239
|
+
* @param {http.ServerResponse} response collector response from pre connect
|
|
240
|
+
* @returns {void}
|
|
241
|
+
*/
|
|
242
|
+
CollectorAPI.prototype._onPreConnect = function _onPreConnect(callback, error, response) {
|
|
243
|
+
const agent = this._agent
|
|
244
|
+
if (error || !SUCCESS.has(response.status)) {
|
|
245
|
+
callback(error, response)
|
|
246
|
+
return
|
|
247
|
+
}
|
|
234
248
|
|
|
235
|
-
|
|
236
|
-
|
|
249
|
+
const res = response.payload || Object.create(null)
|
|
250
|
+
this._handlePreConnectResponse(res)
|
|
251
|
+
|
|
252
|
+
const policies = res.security_policies || Object.create(null)
|
|
253
|
+
|
|
254
|
+
const laspResponse = agent.config.applyLasp(agent, policies)
|
|
255
|
+
if (laspResponse.shouldShutdownRun()) {
|
|
256
|
+
callback(null, laspResponse)
|
|
257
|
+
return
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
this._getFacts(laspResponse.payload, callback)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Checks the redirect_host and determines based on the URL if the collector
|
|
265
|
+
* needs to update the endpoint with new endpoint
|
|
266
|
+
*
|
|
267
|
+
* @param {http.ServerResponse} res collector response
|
|
268
|
+
*/
|
|
269
|
+
CollectorAPI.prototype._handlePreConnectResponse = function _handlePreConnectResponse(res) {
|
|
270
|
+
const agent = this._agent
|
|
271
|
+
|
|
272
|
+
if (!res.redirect_host) {
|
|
273
|
+
logger.error(
|
|
274
|
+
"Requesting this account's collector from %s failed; trying default.",
|
|
275
|
+
agent.config.host
|
|
276
|
+
)
|
|
277
|
+
} else {
|
|
278
|
+
const parts = res.redirect_host.split(':')
|
|
279
|
+
if (parts.length > 2) {
|
|
237
280
|
logger.error(
|
|
238
|
-
"Requesting
|
|
239
|
-
agent.config.host
|
|
281
|
+
"Requesting collector from %s returned bogus result '%s'; trying default.",
|
|
282
|
+
agent.config.host,
|
|
283
|
+
res.redirect_host
|
|
240
284
|
)
|
|
241
285
|
} else {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
res.redirect_host
|
|
248
|
-
)
|
|
249
|
-
} else {
|
|
250
|
-
logger.debug(
|
|
251
|
-
"Requesting this account's collector from %s returned %s; reconfiguring.",
|
|
252
|
-
agent.config.host,
|
|
253
|
-
res.redirect_host
|
|
254
|
-
)
|
|
255
|
-
|
|
256
|
-
const [host, port] = parts
|
|
257
|
-
const newEndpoint = {
|
|
258
|
-
host: host,
|
|
259
|
-
port: port || DEFAULT_PORT
|
|
260
|
-
}
|
|
286
|
+
logger.debug(
|
|
287
|
+
"Requesting this account's collector from %s returned %s; reconfiguring.",
|
|
288
|
+
agent.config.host,
|
|
289
|
+
res.redirect_host
|
|
290
|
+
)
|
|
261
291
|
|
|
262
|
-
|
|
292
|
+
const [host, port] = parts
|
|
293
|
+
const newEndpoint = {
|
|
294
|
+
host: host,
|
|
295
|
+
port: port || DEFAULT_PORT
|
|
263
296
|
}
|
|
264
|
-
}
|
|
265
297
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
const laspResponse = agent.config.applyLasp(agent, policies)
|
|
269
|
-
if (laspResponse.shouldShutdownRun()) {
|
|
270
|
-
return callback(null, laspResponse)
|
|
298
|
+
this._updateEndpoints(newEndpoint)
|
|
271
299
|
}
|
|
272
|
-
|
|
273
|
-
self._getFacts(laspResponse.payload, callback)
|
|
274
300
|
}
|
|
275
301
|
}
|
|
276
302
|
|
|
@@ -292,50 +318,56 @@ CollectorAPI.prototype._getFacts = function _getFacts(lasp, callback) {
|
|
|
292
318
|
}
|
|
293
319
|
|
|
294
320
|
CollectorAPI.prototype._connect = function _connect(env, callback) {
|
|
295
|
-
const collector = this
|
|
296
321
|
const methods = this._methods
|
|
297
|
-
|
|
322
|
+
methods.connect.invoke(env, this._onConnect.bind(this, callback))
|
|
323
|
+
}
|
|
298
324
|
|
|
299
|
-
|
|
325
|
+
/**
|
|
326
|
+
*
|
|
327
|
+
* Handles the response to the connect call
|
|
328
|
+
*
|
|
329
|
+
* @param {Function} callback function to run after processing response
|
|
330
|
+
* @param {Error} error collector response error
|
|
331
|
+
* @param {http.ServerOptions} res collector response
|
|
332
|
+
*/
|
|
333
|
+
CollectorAPI.prototype._onConnect = function _onConnect(callback, error, res) {
|
|
334
|
+
const agent = this._agent
|
|
335
|
+
const methods = this._methods
|
|
300
336
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
function onConnect(error, res) {
|
|
306
|
-
if (error || !SUCCESS.has(res.status)) {
|
|
307
|
-
return callback(error, res)
|
|
308
|
-
}
|
|
337
|
+
if (error || !SUCCESS.has(res.status)) {
|
|
338
|
+
callback(error, res)
|
|
339
|
+
return
|
|
340
|
+
}
|
|
309
341
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
342
|
+
const config = res.payload
|
|
343
|
+
if (!config || !config.agent_run_id) {
|
|
344
|
+
callback(new Error('No agent run ID received from handshake.'), res)
|
|
345
|
+
return
|
|
346
|
+
}
|
|
314
347
|
|
|
315
|
-
|
|
348
|
+
agent.setState('connected')
|
|
316
349
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
350
|
+
logger.info(
|
|
351
|
+
'Connected to %s:%d with agent run ID %s.',
|
|
352
|
+
methods.connect.endpoint.host,
|
|
353
|
+
methods.connect.endpoint.port,
|
|
354
|
+
config.agent_run_id
|
|
355
|
+
)
|
|
323
356
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
357
|
+
// Log "Reporting to..." message from connect response.
|
|
358
|
+
if (config.messages) {
|
|
359
|
+
config.messages.forEach((element) => {
|
|
360
|
+
logger.info(element.message)
|
|
361
|
+
})
|
|
362
|
+
}
|
|
330
363
|
|
|
331
|
-
|
|
332
|
-
|
|
364
|
+
// Store request headers for future collector requests if they're present
|
|
365
|
+
this._reqHeadersMap = config.request_headers_map
|
|
333
366
|
|
|
334
|
-
|
|
335
|
-
|
|
367
|
+
// pass configuration data from the API so automatic reconnect works
|
|
368
|
+
agent.reconfigure(config)
|
|
336
369
|
|
|
337
|
-
|
|
338
|
-
}
|
|
370
|
+
callback(null, res)
|
|
339
371
|
}
|
|
340
372
|
|
|
341
373
|
/**
|
|
@@ -373,13 +405,15 @@ CollectorAPI.prototype.reportSettings = function reportSettings(callback) {
|
|
|
373
405
|
*
|
|
374
406
|
* @param {Array} errors The encoded errors list.
|
|
375
407
|
* @param {Function} callback The continuation / error handler.
|
|
408
|
+
* @returns {void}
|
|
376
409
|
*/
|
|
377
410
|
CollectorAPI.prototype.error_data = function errorData(errors, callback) {
|
|
378
411
|
if (!callback) {
|
|
379
|
-
|
|
412
|
+
this._throwCallbackError()
|
|
380
413
|
}
|
|
381
414
|
if (!errors) {
|
|
382
|
-
|
|
415
|
+
callback(new TypeError('must pass errors to send'))
|
|
416
|
+
return
|
|
383
417
|
}
|
|
384
418
|
|
|
385
419
|
this._sendData(this._methods.errors, errors, callback)
|
|
@@ -387,26 +421,30 @@ CollectorAPI.prototype.error_data = function errorData(errors, callback) {
|
|
|
387
421
|
|
|
388
422
|
CollectorAPI.prototype.error_event_data = function errorEvents(events, callback) {
|
|
389
423
|
if (!callback) {
|
|
390
|
-
|
|
424
|
+
this._throwCallbackError()
|
|
391
425
|
}
|
|
392
426
|
if (!events) {
|
|
393
|
-
|
|
427
|
+
callback(new TypeError('must pass errors to send'))
|
|
428
|
+
return
|
|
394
429
|
}
|
|
395
430
|
|
|
396
431
|
this._sendData(this._methods.errorEvents, events, callback)
|
|
397
432
|
}
|
|
398
433
|
|
|
399
434
|
CollectorAPI.prototype.analytic_event_data = transactionEvents
|
|
435
|
+
|
|
400
436
|
/**
|
|
401
|
-
* @param events
|
|
402
|
-
* @param callback
|
|
437
|
+
* @param {Array} events list of events to send to collector
|
|
438
|
+
* @param {Function} callback handler on response
|
|
439
|
+
* @returns {void}
|
|
403
440
|
*/
|
|
404
441
|
function transactionEvents(events, callback) {
|
|
405
442
|
if (!callback) {
|
|
406
|
-
|
|
443
|
+
this._throwCallbackError()
|
|
407
444
|
}
|
|
408
445
|
if (!events) {
|
|
409
|
-
|
|
446
|
+
callback(new TypeError('must pass events to send'))
|
|
447
|
+
return
|
|
410
448
|
}
|
|
411
449
|
|
|
412
450
|
this._sendData(this._methods.events, events, callback)
|
|
@@ -414,10 +452,11 @@ function transactionEvents(events, callback) {
|
|
|
414
452
|
|
|
415
453
|
CollectorAPI.prototype.custom_event_data = function customEvents(events, callback) {
|
|
416
454
|
if (!callback) {
|
|
417
|
-
|
|
455
|
+
this._throwCallbackError()
|
|
418
456
|
}
|
|
419
457
|
if (!events) {
|
|
420
|
-
|
|
458
|
+
callback(new TypeError('must pass events to send'))
|
|
459
|
+
return
|
|
421
460
|
}
|
|
422
461
|
|
|
423
462
|
this._sendData(this._methods.customEvents, events, callback)
|
|
@@ -441,10 +480,11 @@ CollectorAPI.prototype.custom_event_data = function customEvents(events, callbac
|
|
|
441
480
|
*/
|
|
442
481
|
CollectorAPI.prototype.metric_data = function metricData(metrics, callback) {
|
|
443
482
|
if (!callback) {
|
|
444
|
-
|
|
483
|
+
this._throwCallbackError()
|
|
445
484
|
}
|
|
446
485
|
if (!metrics) {
|
|
447
|
-
|
|
486
|
+
callback(new TypeError('must pass metrics to send'))
|
|
487
|
+
return
|
|
448
488
|
}
|
|
449
489
|
|
|
450
490
|
this._sendData(this._methods.metrics, metrics, callback)
|
|
@@ -464,20 +504,22 @@ CollectorAPI.prototype.metric_data = function metricData(metrics, callback) {
|
|
|
464
504
|
*/
|
|
465
505
|
CollectorAPI.prototype.sql_trace_data = function queryData(queries, callback) {
|
|
466
506
|
if (!callback) {
|
|
467
|
-
|
|
507
|
+
this._throwCallbackError()
|
|
468
508
|
}
|
|
469
509
|
if (!queries) {
|
|
470
|
-
|
|
510
|
+
callback(new TypeError('must pass queries to send'))
|
|
511
|
+
return
|
|
471
512
|
}
|
|
472
513
|
this._sendData(this._methods.queryData, queries, callback)
|
|
473
514
|
}
|
|
474
515
|
|
|
475
516
|
CollectorAPI.prototype.span_event_data = function spanEvents(events, callback) {
|
|
476
517
|
if (!callback) {
|
|
477
|
-
|
|
518
|
+
this._throwCallbackError()
|
|
478
519
|
}
|
|
479
520
|
if (!events) {
|
|
480
|
-
|
|
521
|
+
callback(new TypeError('must pass spans to send'))
|
|
522
|
+
return
|
|
481
523
|
}
|
|
482
524
|
this._sendData(this._methods.spanEvents, events, callback)
|
|
483
525
|
}
|
|
@@ -497,16 +539,18 @@ CollectorAPI.prototype.span_event_data = function spanEvents(events, callback) {
|
|
|
497
539
|
* @param {Function} callback The continuation / error handler.
|
|
498
540
|
*/
|
|
499
541
|
CollectorAPI.prototype.transaction_sample_data = transactionSampleData
|
|
542
|
+
|
|
500
543
|
/**
|
|
501
|
-
* @param traces
|
|
502
|
-
* @param callback
|
|
544
|
+
* @param {Array} traces list of traces to send
|
|
545
|
+
* @param {Function} callback handler on response
|
|
503
546
|
*/
|
|
504
547
|
function transactionSampleData(traces, callback) {
|
|
505
548
|
if (!callback) {
|
|
506
|
-
|
|
549
|
+
this._throwCallbackError()
|
|
507
550
|
}
|
|
508
551
|
if (!traces) {
|
|
509
|
-
|
|
552
|
+
callback(new TypeError('must pass traces to send'))
|
|
553
|
+
return
|
|
510
554
|
}
|
|
511
555
|
|
|
512
556
|
this._sendData(this._methods.traces, traces, callback)
|
|
@@ -521,16 +565,16 @@ function transactionSampleData(traces, callback) {
|
|
|
521
565
|
* 1. An array of logs.
|
|
522
566
|
* 2. A list of common attributes(optional).
|
|
523
567
|
*
|
|
524
|
-
* @param {Array}
|
|
525
|
-
* @param
|
|
526
|
-
* @param {Function} callback The continuation / error handler.
|
|
568
|
+
* @param {Array} logRecords The encoded log entries.
|
|
569
|
+
* @param {Function} callback The continuation / error handler.
|
|
527
570
|
*/
|
|
528
571
|
CollectorAPI.prototype.log_event_data = function logEventData(logRecords, callback) {
|
|
529
572
|
if (!callback) {
|
|
530
|
-
|
|
573
|
+
this._throwCallbackError()
|
|
531
574
|
}
|
|
532
575
|
if (!logRecords) {
|
|
533
|
-
|
|
576
|
+
callback(new TypeError('must pass logRecords to send'))
|
|
577
|
+
return
|
|
534
578
|
}
|
|
535
579
|
|
|
536
580
|
this._sendData(this._methods.logEvents, logRecords, callback)
|
|
@@ -540,12 +584,11 @@ CollectorAPI.prototype.log_event_data = function logEventData(logRecords, callba
|
|
|
540
584
|
* Sends no data aside from the message itself. Clears the run ID, which
|
|
541
585
|
* effectively disconnects the agent from the collector.
|
|
542
586
|
*
|
|
543
|
-
* @param Function callback Runs after the run ID has been cleared.
|
|
544
|
-
* @param callback
|
|
587
|
+
* @param {Function} callback Runs after the run ID has been cleared.
|
|
545
588
|
*/
|
|
546
589
|
CollectorAPI.prototype.shutdown = function shutdown(callback) {
|
|
547
590
|
if (!callback) {
|
|
548
|
-
|
|
591
|
+
this._throwCallbackError()
|
|
549
592
|
}
|
|
550
593
|
|
|
551
594
|
logger.info('Shutting down collector.')
|
|
@@ -554,8 +597,8 @@ CollectorAPI.prototype.shutdown = function shutdown(callback) {
|
|
|
554
597
|
this._methods.shutdown.invoke(null, this._reqHeadersMap, onShutdown)
|
|
555
598
|
|
|
556
599
|
/**
|
|
557
|
-
* @param error
|
|
558
|
-
* @param response
|
|
600
|
+
* @param {Error} error response error
|
|
601
|
+
* @param {http.ServerResponse} response response from collector
|
|
559
602
|
*/
|
|
560
603
|
function onShutdown(error, response) {
|
|
561
604
|
if (error) {
|
|
@@ -593,7 +636,8 @@ CollectorAPI.prototype._runLifecycle = function _runLifecycle(method, body, call
|
|
|
593
636
|
const api = this
|
|
594
637
|
method.invoke(body, this._reqHeadersMap, function standardHandler(error, response) {
|
|
595
638
|
if (error) {
|
|
596
|
-
|
|
639
|
+
callback(error)
|
|
640
|
+
return
|
|
597
641
|
}
|
|
598
642
|
|
|
599
643
|
return api._handleResponseCode(response, method.name, callback)
|
|
@@ -620,6 +664,7 @@ CollectorAPI.prototype._sendData = function _sendData(method, data, callback) {
|
|
|
620
664
|
|
|
621
665
|
// TODO: log the payload if exists?
|
|
622
666
|
|
|
667
|
+
/*
|
|
623
668
|
if (response.agentRun === AGENT_RUN_BEHAVIOR.SHUTDOWN) {
|
|
624
669
|
// TODO: for now, shut handled in _handleResponseCode for consistency
|
|
625
670
|
// either find way to safely change while side-by-side or move
|
|
@@ -635,7 +680,8 @@ CollectorAPI.prototype._sendData = function _sendData(method, data, callback) {
|
|
|
635
680
|
// })
|
|
636
681
|
|
|
637
682
|
callback(null, { retainData: response.retainData })
|
|
638
|
-
|
|
683
|
+
*/
|
|
684
|
+
if (response.agentRun === AGENT_RUN_BEHAVIOR.RESTART) {
|
|
639
685
|
// TODO: almost seems better to leg aggregator finish (cb) then restart?
|
|
640
686
|
|
|
641
687
|
// TODO: ensure harvesting stopped for all other endpoints. same for shutdown.
|
|
@@ -666,60 +712,55 @@ CollectorAPI.prototype.isConnected = function isConnected() {
|
|
|
666
712
|
return !!this._agent.config.run_id
|
|
667
713
|
}
|
|
668
714
|
|
|
715
|
+
CollectorAPI.prototype._handleResponseCode = _handleResponseCode
|
|
716
|
+
|
|
669
717
|
/**
|
|
670
718
|
* Returns appropriate CollectorResponse object according to response code.
|
|
671
719
|
*
|
|
672
|
-
* @param {
|
|
720
|
+
* @param {http.ServerResponse} response response from collector
|
|
673
721
|
* @param {number} response.status - Status code from collector response
|
|
674
722
|
* @param {object} response.payload - Parsed response body, if any
|
|
675
723
|
* @param {string} endpoint - Collector endpoint name
|
|
676
724
|
* @param {Function} cb - CollectorAPI method invocation callback
|
|
677
725
|
*/
|
|
678
|
-
CollectorAPI.prototype._handleResponseCode = _handleResponseCode
|
|
679
|
-
/**
|
|
680
|
-
* @param response
|
|
681
|
-
* @param endpoint
|
|
682
|
-
* @param cb
|
|
683
|
-
*/
|
|
684
726
|
function _handleResponseCode(response, endpoint, cb) {
|
|
685
727
|
const code = response.status
|
|
686
728
|
|
|
687
729
|
/* eslint-disable padded-blocks */
|
|
688
730
|
if (SUCCESS.has(code)) {
|
|
689
731
|
// The request was a success!
|
|
690
|
-
|
|
732
|
+
setImmediate(cb, null, CollectorResponse.success(response.payload))
|
|
691
733
|
} else if (RESTART.has(code)) {
|
|
692
734
|
// The agent needs to disconnect and restart.
|
|
693
735
|
logFailure(endpoint, code, 'Restarting')
|
|
694
|
-
|
|
736
|
+
setImmediate(cb, null, CollectorResponse.reconnect(0, null))
|
|
695
737
|
} else if (FAILURE_DISCARD_DATA.has(code)) {
|
|
696
738
|
// Something was wrong with our payload so we must delete our data.
|
|
697
739
|
logFailure(endpoint, code, 'Discarding harvest data')
|
|
698
|
-
|
|
740
|
+
setImmediate(cb, null, CollectorResponse.discard(null))
|
|
699
741
|
} else if (FAILURE_SAVE_DATA.has(code)) {
|
|
700
742
|
// Something was wrong with the request, but it wasn't our fault. We'll try again.
|
|
701
743
|
logFailure(endpoint, code, 'Retaining data for next harvest')
|
|
702
|
-
|
|
744
|
+
setImmediate(cb, null, CollectorResponse.error(response.payload))
|
|
703
745
|
} else if (code === 410) {
|
|
704
746
|
// New Relic doesn't like us and we shouldn't try to talk to them any more.
|
|
705
747
|
logFailure(endpoint, code, 'Disconnecting from New Relic')
|
|
706
748
|
|
|
707
|
-
|
|
749
|
+
this._agent.stop(function onShutdown() {
|
|
708
750
|
cb(null, CollectorResponse.fatal(response.payload))
|
|
709
751
|
})
|
|
752
|
+
} else {
|
|
753
|
+
// We're not sure what New Relic is trying to tell us. Let's get rid of our
|
|
754
|
+
// data just in case it is our fault.
|
|
755
|
+
logger.error('Agent endpoint %s returned unexpected status %s.', endpoint, code)
|
|
756
|
+
setImmediate(cb, null, CollectorResponse.discard(null))
|
|
710
757
|
}
|
|
711
|
-
/* eslint-enable padded-blocks */
|
|
712
|
-
|
|
713
|
-
// We're not sure what New Relic is trying to tell us. Let's get rid of our
|
|
714
|
-
// data just in case it is our fault.
|
|
715
|
-
logger.error('Agent endpoint %s returned unexpected status %s.', endpoint, code)
|
|
716
|
-
return setImmediate(cb, null, CollectorResponse.discard(null))
|
|
717
758
|
}
|
|
718
759
|
|
|
719
760
|
/**
|
|
720
|
-
* @param endpoint
|
|
721
|
-
* @param code
|
|
722
|
-
* @param action
|
|
761
|
+
* @param {string} endpoint called endpoint
|
|
762
|
+
* @param {string} code http status code
|
|
763
|
+
* @param {string} action describes collector action
|
|
723
764
|
*/
|
|
724
765
|
function logFailure(endpoint, code, action) {
|
|
725
766
|
logger.error('Agent endpoint %s returned %s status. %s.', endpoint, code, action)
|