newrelic 5.13.0 → 5.13.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 +49 -0
- package/api.js +3 -2
- package/lib/agent.js +148 -315
- package/lib/aggregators/base-aggregator.js +3 -12
- package/lib/collector/api.js +2 -1
- package/lib/config/default.js +7 -0
- package/lib/config/env.js +6 -0
- package/lib/config/index.js +5 -5
- package/lib/injector.js +161 -0
- package/lib/shimmer.js +116 -0
- package/lib/spans/span-event-aggregator.js +1 -1
- package/lib/transaction/index.js +0 -1
- package/lib/utilization/common.js +11 -4
- package/package.json +8 -6
- package/lib/event-aggregator.js +0 -94
- package/lib/harvest.js +0 -718
package/NEWS.md
CHANGED
|
@@ -1,3 +1,52 @@
|
|
|
1
|
+
### 5.13.1 (2019-10-10):
|
|
2
|
+
|
|
3
|
+
* Added back generation of entity stats logging and uninstrumented support metric
|
|
4
|
+
generation on metric harvests.
|
|
5
|
+
|
|
6
|
+
* Removed legacy harvest code from main agent.
|
|
7
|
+
|
|
8
|
+
* Updated `https-proxy-agent` to v3 for security fix.
|
|
9
|
+
|
|
10
|
+
Shoutout to @asturur for the contribution.
|
|
11
|
+
|
|
12
|
+
* Added diagnostic code injector.
|
|
13
|
+
|
|
14
|
+
The agent may now be configured to make transaction state checks via code
|
|
15
|
+
injection. This may be turned on by setting `code_injector.diagnostics.enabled`
|
|
16
|
+
to `true`. While this option is enabled, code around async boundaries will be added
|
|
17
|
+
to track transactions, and log a message when they are not properly reinstated.
|
|
18
|
+
|
|
19
|
+
* Fixed bug where `API.shutdown()` would not properly harvest when configured to.
|
|
20
|
+
|
|
21
|
+
* `primary_application_id` now defaults to 'Unknown' in serverless mode to allow
|
|
22
|
+
Distributed Tracing to function correctly when `NEW_RELIC_PRIMARY_APPLICATION_ID`
|
|
23
|
+
is not defined.
|
|
24
|
+
|
|
25
|
+
* Upgraded `tap` to latest version
|
|
26
|
+
|
|
27
|
+
* Upgraded `mocha` to latest version.
|
|
28
|
+
|
|
29
|
+
* Adds `--exit` flag to mocha test runs to prevent infinite runs on CI.
|
|
30
|
+
|
|
31
|
+
* Fixed bug where multiple agent restarts would cause the number of 'stopped'
|
|
32
|
+
listeners to exceed limit.
|
|
33
|
+
|
|
34
|
+
* Fixed inconsistent async return from collector API.
|
|
35
|
+
|
|
36
|
+
This could result in an infinite loop due to attempting to merge before clearing.
|
|
37
|
+
*This bug should not have impacted normal agent runs but was uncovered for certain
|
|
38
|
+
test cases.*
|
|
39
|
+
|
|
40
|
+
* Fixed tests that leave work scheduled on the event loop.
|
|
41
|
+
|
|
42
|
+
* Fixed issue that could result in vendor utilization detection failure.
|
|
43
|
+
As a part of this fix, the request that hits the timeout will immediately abort
|
|
44
|
+
instead of hanging around for the default timeout.
|
|
45
|
+
|
|
46
|
+
### 5.13.0 (2019-10-01):
|
|
47
|
+
|
|
48
|
+
* Same as 5.12.0
|
|
49
|
+
|
|
1
50
|
### 5.12.0 (2019-10-01):
|
|
2
51
|
|
|
3
52
|
* Now supports Restify 7 and 8.
|
package/api.js
CHANGED
|
@@ -1405,8 +1405,9 @@ function _doShutdown(api, options, callback) {
|
|
|
1405
1405
|
}
|
|
1406
1406
|
|
|
1407
1407
|
agent.on('started', function shutdownHarvest() {
|
|
1408
|
-
agent.
|
|
1408
|
+
agent.forceHarvestAll(afterHarvest)
|
|
1409
1409
|
})
|
|
1410
|
+
|
|
1410
1411
|
agent.on('errored', function logShutdownError(error) {
|
|
1411
1412
|
agent.stop(callback)
|
|
1412
1413
|
if (error) {
|
|
@@ -1417,7 +1418,7 @@ function _doShutdown(api, options, callback) {
|
|
|
1417
1418
|
}
|
|
1418
1419
|
})
|
|
1419
1420
|
} else if (options.collectPendingData) {
|
|
1420
|
-
agent.
|
|
1421
|
+
agent.forceHarvestAll(afterHarvest)
|
|
1421
1422
|
} else {
|
|
1422
1423
|
agent.stop(callback)
|
|
1423
1424
|
}
|
package/lib/agent.js
CHANGED
|
@@ -9,7 +9,6 @@ const ErrorCollector = require('./errors/error-collector')
|
|
|
9
9
|
const ErrorTraceAggregator = require('./errors/error-trace-aggregator')
|
|
10
10
|
const ErrorEventAggregator = require('./errors/error-event-aggregator')
|
|
11
11
|
const EventEmitter = require('events').EventEmitter
|
|
12
|
-
const Harvest = require('./harvest')
|
|
13
12
|
const hashes = require('./util/hashes')
|
|
14
13
|
const logger = require('./logger')
|
|
15
14
|
const MetricMapper = require('./metrics/mapper')
|
|
@@ -26,8 +25,6 @@ const TxSegmentNormalizer = require('./metrics/normalizer/tx_segment')
|
|
|
26
25
|
const uninstrumented = require('./uninstrumented')
|
|
27
26
|
const util = require('util')
|
|
28
27
|
|
|
29
|
-
const AGENT_RUN_BEHAVIOR = require('./collector/response').AGENT_RUN_BEHAVIOR
|
|
30
|
-
|
|
31
28
|
// Map of valid states to whether or not data collection is valid
|
|
32
29
|
const STATES = {
|
|
33
30
|
stopped: false,
|
|
@@ -40,9 +37,6 @@ const STATES = {
|
|
|
40
37
|
errored: false
|
|
41
38
|
}
|
|
42
39
|
|
|
43
|
-
// just to make clear what's going on
|
|
44
|
-
const TO_MILLIS = 1e3
|
|
45
|
-
|
|
46
40
|
const MAX_ERROR_TRACES_DEFAULT = 20
|
|
47
41
|
const INITIAL_HARVEST_DELAY_MS = 1000
|
|
48
42
|
const DEFAULT_HARVEST_INTERVAL_MS = 60000
|
|
@@ -67,8 +61,6 @@ function Agent(config) {
|
|
|
67
61
|
this.version = this.config.version
|
|
68
62
|
|
|
69
63
|
if (config.serverless_mode.enabled) {
|
|
70
|
-
// TODO: once all harvesting is done through aggregators,
|
|
71
|
-
// change the ServerlessCollector to no longer rely on the harvest class.
|
|
72
64
|
this.collector = new ServerlessCollector(this)
|
|
73
65
|
} else {
|
|
74
66
|
this.collector = new CollectorAPI(this)
|
|
@@ -87,6 +79,11 @@ function Agent(config) {
|
|
|
87
79
|
this.collector
|
|
88
80
|
)
|
|
89
81
|
|
|
82
|
+
this.metrics.on(
|
|
83
|
+
'starting metric_data data send.',
|
|
84
|
+
this._beforeMetricDataSend.bind(this)
|
|
85
|
+
)
|
|
86
|
+
|
|
90
87
|
// Open tracing.
|
|
91
88
|
this.spanEventAggregator = new SpanEventAggregator({
|
|
92
89
|
periodMs: config.event_harvest_config.report_period_ms,
|
|
@@ -150,7 +147,7 @@ function Agent(config) {
|
|
|
150
147
|
this.tracer = new Tracer(this)
|
|
151
148
|
this.traces = new TransactionTraceAggregator(
|
|
152
149
|
{
|
|
153
|
-
periodMs:
|
|
150
|
+
periodMs: DEFAULT_HARVEST_INTERVAL_MS,
|
|
154
151
|
config: this.config,
|
|
155
152
|
isAsync: !config.serverless_mode.enabled,
|
|
156
153
|
method: 'transaction_sample_data'
|
|
@@ -167,7 +164,7 @@ function Agent(config) {
|
|
|
167
164
|
this.queries = new QueryTraceAggregator(
|
|
168
165
|
{
|
|
169
166
|
config: this.config,
|
|
170
|
-
periodMs:
|
|
167
|
+
periodMs: DEFAULT_HARVEST_INTERVAL_MS,
|
|
171
168
|
method: 'sql_trace_data',
|
|
172
169
|
isAsync: !config.serverless_mode.enabled
|
|
173
170
|
},
|
|
@@ -181,12 +178,8 @@ function Agent(config) {
|
|
|
181
178
|
this.totalActiveSegments = 0
|
|
182
179
|
this.segmentsCreatedInHarvest = 0
|
|
183
180
|
this.segmentsClearedInHarvest = 0
|
|
181
|
+
// Used by shutdown code as well as entity tracking stats
|
|
184
182
|
this.activeTransactions = 0
|
|
185
|
-
this.transactionsCreatedInHarvest = 0
|
|
186
|
-
|
|
187
|
-
// Harvest attributes.
|
|
188
|
-
this.harvesterHandle = null
|
|
189
|
-
this._lastHarvest = null
|
|
190
183
|
|
|
191
184
|
// Finally, add listeners for the agent's own events.
|
|
192
185
|
this.on('transactionFinished', this._transactionFinished.bind(this))
|
|
@@ -264,124 +257,7 @@ Agent.prototype.start = function start(callback) {
|
|
|
264
257
|
setTimeout(function afterTimeout() {
|
|
265
258
|
logger.info(`Starting initial ${INITIAL_HARVEST_DELAY_MS}ms harvest.`)
|
|
266
259
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
const metricPromise = new Promise((resolve) => {
|
|
270
|
-
agent.metrics.once(
|
|
271
|
-
'finished metric_data data send.',
|
|
272
|
-
function onMetricsFinished() {
|
|
273
|
-
resolve()
|
|
274
|
-
}
|
|
275
|
-
)
|
|
276
|
-
agent.metrics.send()
|
|
277
|
-
})
|
|
278
|
-
|
|
279
|
-
promises.push(metricPromise)
|
|
280
|
-
|
|
281
|
-
// TODO: plumb config through to aggregators so they can do their own checking.
|
|
282
|
-
if (agent.config.distributed_tracing.enabled &&
|
|
283
|
-
agent.config.span_events.enabled) {
|
|
284
|
-
const spanPromise = new Promise((resolve) => {
|
|
285
|
-
agent.spanEventAggregator.once(
|
|
286
|
-
'finished span_event_data data send.',
|
|
287
|
-
function onSpansFinished() {
|
|
288
|
-
resolve()
|
|
289
|
-
}
|
|
290
|
-
)
|
|
291
|
-
agent.spanEventAggregator.send()
|
|
292
|
-
})
|
|
293
|
-
|
|
294
|
-
promises.push(spanPromise)
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
if (agent.config.custom_insights_events.enabled) {
|
|
298
|
-
const customEventPromise = new Promise((resolve) => {
|
|
299
|
-
agent.customEventAggregator.once(
|
|
300
|
-
'finished custom_event_data data send.',
|
|
301
|
-
function onCustomEventsFinished() {
|
|
302
|
-
resolve()
|
|
303
|
-
}
|
|
304
|
-
)
|
|
305
|
-
agent.customEventAggregator.send()
|
|
306
|
-
})
|
|
307
|
-
|
|
308
|
-
promises.push(customEventPromise)
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
if (agent.config.transaction_events.enabled) {
|
|
312
|
-
const transactionEventPromise = new Promise((resolve) => {
|
|
313
|
-
agent.transactionEventAggregator.once(
|
|
314
|
-
'finished analytic_event_data data send.',
|
|
315
|
-
function onTransactionEventsFinished() {
|
|
316
|
-
resolve()
|
|
317
|
-
}
|
|
318
|
-
)
|
|
319
|
-
agent.transactionEventAggregator.send()
|
|
320
|
-
})
|
|
321
|
-
|
|
322
|
-
promises.push(transactionEventPromise)
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
if (agent.config.transaction_tracer.enabled && agent.config.collect_traces) {
|
|
326
|
-
const transactionTracePromise = new Promise((resolve) => {
|
|
327
|
-
agent.traces.once(
|
|
328
|
-
'finished transaction_sample_data data send.',
|
|
329
|
-
function onTracesFinished() {
|
|
330
|
-
resolve()
|
|
331
|
-
}
|
|
332
|
-
)
|
|
333
|
-
agent.traces.send()
|
|
334
|
-
})
|
|
335
|
-
|
|
336
|
-
promises.push(transactionTracePromise)
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
if (agent.config.slow_sql.enabled) {
|
|
340
|
-
const sqlTracePromise = new Promise((resolve) => {
|
|
341
|
-
agent.queries.once(
|
|
342
|
-
'finished sql_trace_data data send.',
|
|
343
|
-
function onSqlTracesFinished() {
|
|
344
|
-
resolve()
|
|
345
|
-
}
|
|
346
|
-
)
|
|
347
|
-
agent.queries.send()
|
|
348
|
-
})
|
|
349
|
-
|
|
350
|
-
promises.push(sqlTracePromise)
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
const errorCollectorEnabled =
|
|
354
|
-
agent.config.error_collector && agent.config.error_collector.enabled
|
|
355
|
-
|
|
356
|
-
if (errorCollectorEnabled && agent.config.collect_errors) {
|
|
357
|
-
const errorTracePromise = new Promise((resolve) => {
|
|
358
|
-
agent.errors.traceAggregator.once(
|
|
359
|
-
'finished error_data data send.',
|
|
360
|
-
function onErrorTracesFinished() {
|
|
361
|
-
resolve()
|
|
362
|
-
}
|
|
363
|
-
)
|
|
364
|
-
agent.errors.traceAggregator.send()
|
|
365
|
-
})
|
|
366
|
-
|
|
367
|
-
promises.push(errorTracePromise)
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
if (errorCollectorEnabled && agent.config.error_collector.capture_events) {
|
|
371
|
-
const errorEventPromise = new Promise((resolve) => {
|
|
372
|
-
agent.errors.eventAggregator.once(
|
|
373
|
-
'finished error_event_data data send.',
|
|
374
|
-
function onErrorEventsFinished() {
|
|
375
|
-
resolve()
|
|
376
|
-
}
|
|
377
|
-
)
|
|
378
|
-
agent.errors.eventAggregator.send()
|
|
379
|
-
})
|
|
380
|
-
|
|
381
|
-
promises.push(errorEventPromise)
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
Promise.all(promises).then(function afterAllAggregatorsSend() {
|
|
260
|
+
agent.forceHarvestAll(function afterAllAggregatorsSend() {
|
|
385
261
|
agent.startAggregators()
|
|
386
262
|
callback(null, config)
|
|
387
263
|
})
|
|
@@ -393,6 +269,136 @@ Agent.prototype.start = function start(callback) {
|
|
|
393
269
|
})
|
|
394
270
|
}
|
|
395
271
|
|
|
272
|
+
/**
|
|
273
|
+
* Forces all aggregators to send the data collected.
|
|
274
|
+
* @param {Function} callback The callback to invoke when all data types have been sent.
|
|
275
|
+
*/
|
|
276
|
+
Agent.prototype.forceHarvestAll = function forceHarvestAll(callback) {
|
|
277
|
+
const agent = this
|
|
278
|
+
const promises = []
|
|
279
|
+
|
|
280
|
+
const metricPromise = new Promise((resolve) => {
|
|
281
|
+
agent.metrics.once(
|
|
282
|
+
'finished metric_data data send.',
|
|
283
|
+
function onMetricsFinished() {
|
|
284
|
+
resolve()
|
|
285
|
+
}
|
|
286
|
+
)
|
|
287
|
+
agent.metrics.send()
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
promises.push(metricPromise)
|
|
291
|
+
|
|
292
|
+
// TODO: plumb config through to aggregators so they can do their own checking.
|
|
293
|
+
if (agent.config.distributed_tracing.enabled &&
|
|
294
|
+
agent.config.span_events.enabled) {
|
|
295
|
+
const spanPromise = new Promise((resolve) => {
|
|
296
|
+
agent.spanEventAggregator.once(
|
|
297
|
+
'finished span_event_data data send.',
|
|
298
|
+
function onSpansFinished() {
|
|
299
|
+
resolve()
|
|
300
|
+
}
|
|
301
|
+
)
|
|
302
|
+
agent.spanEventAggregator.send()
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
promises.push(spanPromise)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (agent.config.custom_insights_events.enabled) {
|
|
309
|
+
const customEventPromise = new Promise((resolve) => {
|
|
310
|
+
agent.customEventAggregator.once(
|
|
311
|
+
'finished custom_event_data data send.',
|
|
312
|
+
function onCustomEventsFinished() {
|
|
313
|
+
resolve()
|
|
314
|
+
}
|
|
315
|
+
)
|
|
316
|
+
agent.customEventAggregator.send()
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
promises.push(customEventPromise)
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (agent.config.transaction_events.enabled) {
|
|
323
|
+
const transactionEventPromise = new Promise((resolve) => {
|
|
324
|
+
agent.transactionEventAggregator.once(
|
|
325
|
+
'finished analytic_event_data data send.',
|
|
326
|
+
function onTransactionEventsFinished() {
|
|
327
|
+
resolve()
|
|
328
|
+
}
|
|
329
|
+
)
|
|
330
|
+
agent.transactionEventAggregator.send()
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
promises.push(transactionEventPromise)
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (agent.config.transaction_tracer.enabled && agent.config.collect_traces) {
|
|
337
|
+
const transactionTracePromise = new Promise((resolve) => {
|
|
338
|
+
agent.traces.once(
|
|
339
|
+
'finished transaction_sample_data data send.',
|
|
340
|
+
function onTracesFinished() {
|
|
341
|
+
resolve()
|
|
342
|
+
}
|
|
343
|
+
)
|
|
344
|
+
agent.traces.send()
|
|
345
|
+
})
|
|
346
|
+
|
|
347
|
+
promises.push(transactionTracePromise)
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (agent.config.slow_sql.enabled) {
|
|
351
|
+
const sqlTracePromise = new Promise((resolve) => {
|
|
352
|
+
agent.queries.once(
|
|
353
|
+
'finished sql_trace_data data send.',
|
|
354
|
+
function onSqlTracesFinished() {
|
|
355
|
+
resolve()
|
|
356
|
+
}
|
|
357
|
+
)
|
|
358
|
+
agent.queries.send()
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
promises.push(sqlTracePromise)
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const errorCollectorEnabled =
|
|
365
|
+
agent.config.error_collector && agent.config.error_collector.enabled
|
|
366
|
+
|
|
367
|
+
if (errorCollectorEnabled && agent.config.collect_errors) {
|
|
368
|
+
const errorTracePromise = new Promise((resolve) => {
|
|
369
|
+
agent.errors.traceAggregator.once(
|
|
370
|
+
'finished error_data data send.',
|
|
371
|
+
function onErrorTracesFinished() {
|
|
372
|
+
resolve()
|
|
373
|
+
}
|
|
374
|
+
)
|
|
375
|
+
agent.errors.traceAggregator.send()
|
|
376
|
+
})
|
|
377
|
+
|
|
378
|
+
promises.push(errorTracePromise)
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (errorCollectorEnabled && agent.config.error_collector.capture_events) {
|
|
382
|
+
const errorEventPromise = new Promise((resolve) => {
|
|
383
|
+
agent.errors.eventAggregator.once(
|
|
384
|
+
'finished error_event_data data send.',
|
|
385
|
+
function onErrorEventsFinished() {
|
|
386
|
+
resolve()
|
|
387
|
+
}
|
|
388
|
+
)
|
|
389
|
+
agent.errors.eventAggregator.send()
|
|
390
|
+
})
|
|
391
|
+
|
|
392
|
+
promises.push(errorEventPromise)
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
Promise.all(promises).then(() => {
|
|
396
|
+
// Get out of the promise so callback errors aren't treated as
|
|
397
|
+
// promise rejections.
|
|
398
|
+
setImmediate(callback)
|
|
399
|
+
})
|
|
400
|
+
}
|
|
401
|
+
|
|
396
402
|
Agent.prototype.stopAggregators = function stopAggregators() {
|
|
397
403
|
this.metrics.stop()
|
|
398
404
|
this.errors.stop()
|
|
@@ -468,7 +474,6 @@ Agent.prototype.stop = function stop(callback) {
|
|
|
468
474
|
|
|
469
475
|
this.stopAggregators()
|
|
470
476
|
|
|
471
|
-
this._stopHarvester()
|
|
472
477
|
sampler.stop()
|
|
473
478
|
|
|
474
479
|
if (this.collector.isConnected()) {
|
|
@@ -522,82 +527,6 @@ Agent.prototype._resetCustomEvents = function resetCustomEvents() {
|
|
|
522
527
|
this.customEventAggregator.clear()
|
|
523
528
|
}
|
|
524
529
|
|
|
525
|
-
/**
|
|
526
|
-
* On agent startup, an interval timer is started that calls this method once
|
|
527
|
-
* a minute, which in turn invokes the pieces of the harvest cycle. It calls
|
|
528
|
-
* the various collector API methods in order, bailing out if one of them fails,
|
|
529
|
-
* to ensure that the agents don't pummel the collector if it's already
|
|
530
|
-
* struggling.
|
|
531
|
-
*/
|
|
532
|
-
Agent.prototype.harvest = function harvest(callback) {
|
|
533
|
-
logger.trace('Peparing to harvest.')
|
|
534
|
-
|
|
535
|
-
if (!callback) {
|
|
536
|
-
throw new TypeError('callback required!')
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
// Generate metrics for this harvest and then check we are connected to the
|
|
540
|
-
// collector.
|
|
541
|
-
this._generateHarvestMetrics()
|
|
542
|
-
|
|
543
|
-
if (!this.collector.isConnected()) {
|
|
544
|
-
logger.trace('Collector not connected.')
|
|
545
|
-
|
|
546
|
-
return setImmediate(function immediatelyError() {
|
|
547
|
-
callback(new Error('Not connected to New Relic!'))
|
|
548
|
-
})
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
// We have a connection, create a new harvest.
|
|
552
|
-
this.emit('harvestStarted')
|
|
553
|
-
logger.info('Harvest started.')
|
|
554
|
-
|
|
555
|
-
this._lastHarvest = new Harvest(this)
|
|
556
|
-
this._lastHarvest.prepare(Harvest.ALL_ENDPOINTS)
|
|
557
|
-
|
|
558
|
-
// Send the harvest!
|
|
559
|
-
const collector = this.collector
|
|
560
|
-
const agent = this
|
|
561
|
-
|
|
562
|
-
logger.trace('Sending harvest data...')
|
|
563
|
-
this._lastHarvest.send(function afterHarvest(err, agentRunAction) {
|
|
564
|
-
// Do we need to do anything to the agent run?
|
|
565
|
-
if (agentRunAction === AGENT_RUN_BEHAVIOR.SHUTDOWN) {
|
|
566
|
-
agent.emit('harvestFinished')
|
|
567
|
-
logger.info('Harvest finished. Shutdown requested.')
|
|
568
|
-
|
|
569
|
-
agent.stop(function afterStop(stopError) {
|
|
570
|
-
const shutdownError = stopError || err
|
|
571
|
-
callback(shutdownError)
|
|
572
|
-
})
|
|
573
|
-
} else if (agentRunAction === AGENT_RUN_BEHAVIOR.RESTART) {
|
|
574
|
-
logger.info('Restart requested. Harvest will complete upon restart finish.')
|
|
575
|
-
|
|
576
|
-
collector.restart(function afterRestart(restartError) {
|
|
577
|
-
// TODO: What if preconnect/connect respond with shutdown here?
|
|
578
|
-
if (restartError) {
|
|
579
|
-
logger.warn('Failed to restart agent run after harvest')
|
|
580
|
-
callback(restartError)
|
|
581
|
-
} else {
|
|
582
|
-
logger.trace('Restart succeeded. Finishing harvest.')
|
|
583
|
-
_finish(err)
|
|
584
|
-
}
|
|
585
|
-
})
|
|
586
|
-
} else {
|
|
587
|
-
logger.trace('Data sent successfully. Finishing harvest.')
|
|
588
|
-
_finish(err)
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
function _finish(error) {
|
|
592
|
-
agent.emit('harvestFinished')
|
|
593
|
-
logger.info('Harvest finished.')
|
|
594
|
-
|
|
595
|
-
agent._scheduleHarvester(agent.config.data_report_period)
|
|
596
|
-
callback(error)
|
|
597
|
-
}
|
|
598
|
-
})
|
|
599
|
-
}
|
|
600
|
-
|
|
601
530
|
/**
|
|
602
531
|
* This method invokes a harvest synchronously.
|
|
603
532
|
*
|
|
@@ -606,10 +535,6 @@ Agent.prototype.harvest = function harvest(callback) {
|
|
|
606
535
|
Agent.prototype.harvestSync = function harvestSync() {
|
|
607
536
|
logger.trace('Peparing to harvest.')
|
|
608
537
|
|
|
609
|
-
// Generate metrics for this harvest and then check we are connected to the
|
|
610
|
-
// collector.
|
|
611
|
-
this._generateHarvestMetrics()
|
|
612
|
-
|
|
613
538
|
if (!this.collector.isConnected()) {
|
|
614
539
|
throw new Error('Sync harvest not connected/enabled!')
|
|
615
540
|
}
|
|
@@ -618,9 +543,6 @@ Agent.prototype.harvestSync = function harvestSync() {
|
|
|
618
543
|
this.emit('harvestStarted')
|
|
619
544
|
logger.info('Harvest started.')
|
|
620
545
|
|
|
621
|
-
this._lastHarvest = new Harvest(this)
|
|
622
|
-
this._lastHarvest.prepare(Harvest.ALL_ENDPOINTS)
|
|
623
|
-
|
|
624
546
|
const collector = this.collector
|
|
625
547
|
const agent = this
|
|
626
548
|
|
|
@@ -641,7 +563,14 @@ Agent.prototype.harvestSync = function harvestSync() {
|
|
|
641
563
|
logger.info('Harvest finished.')
|
|
642
564
|
}
|
|
643
565
|
|
|
644
|
-
Agent.prototype.
|
|
566
|
+
Agent.prototype._beforeMetricDataSend = function _beforeMetricDataSend() {
|
|
567
|
+
this._generateEntityStatsAndClear()
|
|
568
|
+
|
|
569
|
+
// Send uninstrumented supportability metrics every metric harvest cycle
|
|
570
|
+
uninstrumented.createMetrics(this.metrics)
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
Agent.prototype._generateEntityStatsAndClear = function _generateHarvestMetrics() {
|
|
645
574
|
// Note some information about the size of this harvest.
|
|
646
575
|
if (logger.traceEnabled()) {
|
|
647
576
|
logger.trace({
|
|
@@ -649,20 +578,12 @@ Agent.prototype._generateHarvestMetrics = function _generateHarvestMetrics() {
|
|
|
649
578
|
harvestCreated: this.segmentsCreatedInHarvest,
|
|
650
579
|
harvestCleared: this.segmentsClearedInHarvest,
|
|
651
580
|
activeTransactions: this.activeTransactions
|
|
652
|
-
}, 'Entity stats on harvest')
|
|
581
|
+
}, 'Entity stats on metric harvest')
|
|
653
582
|
}
|
|
654
|
-
this.recordSupportability(
|
|
655
|
-
'Nodejs/Transactions/Created',
|
|
656
|
-
this.transactionsCreatedInHarvest
|
|
657
|
-
)
|
|
658
|
-
|
|
659
|
-
// Send uninstrumented supportability metrics every harvest cycle
|
|
660
|
-
uninstrumented.createMetrics(this.metrics)
|
|
661
583
|
|
|
662
584
|
// Reset the counters.
|
|
663
585
|
this.segmentsCreatedInHarvest = 0
|
|
664
586
|
this.segmentsClearedInHarvest = 0
|
|
665
|
-
this.transactionsCreatedInHarvest = 0
|
|
666
587
|
}
|
|
667
588
|
|
|
668
589
|
/**
|
|
@@ -702,94 +623,6 @@ Agent.prototype.canCollectData = function canCollectData() {
|
|
|
702
623
|
return STATES[this._state]
|
|
703
624
|
}
|
|
704
625
|
|
|
705
|
-
/**
|
|
706
|
-
* Server-side configuration value. When run, forces a harvest cycle
|
|
707
|
-
* so as to not cause the agent to go too long without reporting.
|
|
708
|
-
*
|
|
709
|
-
* @param {number} interval Time in seconds between harvest runs.
|
|
710
|
-
*/
|
|
711
|
-
Agent.prototype._harvesterIntervalChange = _harvesterIntervalChange
|
|
712
|
-
|
|
713
|
-
function _harvesterIntervalChange(interval, callback) {
|
|
714
|
-
const agent = this
|
|
715
|
-
|
|
716
|
-
// only change the setup if the harvester is currently running
|
|
717
|
-
if (this.harvesterHandle) {
|
|
718
|
-
// force a harvest now, to be safe
|
|
719
|
-
this.harvest(function onHarvest(error) {
|
|
720
|
-
agent._restartHarvester(interval)
|
|
721
|
-
if (callback) callback(error)
|
|
722
|
-
})
|
|
723
|
-
} else if (callback) {
|
|
724
|
-
process.nextTick(callback)
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
/**
|
|
729
|
-
* Restart the harvest cycle timer.
|
|
730
|
-
*
|
|
731
|
-
* @param {number} harvestSeconds How many seconds between harvests.
|
|
732
|
-
*/
|
|
733
|
-
Agent.prototype._restartHarvester = function _restartHarvester(harvestSeconds) {
|
|
734
|
-
logger.trace('Restarting harvester.')
|
|
735
|
-
|
|
736
|
-
this._stopHarvester()
|
|
737
|
-
this._scheduleHarvester(harvestSeconds)
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
/**
|
|
741
|
-
* Safely stop the harvest cycle timer.
|
|
742
|
-
*/
|
|
743
|
-
Agent.prototype._stopHarvester = function _stopHarvester() {
|
|
744
|
-
logger.trace('Stopping harvester.')
|
|
745
|
-
|
|
746
|
-
if (this.harvesterHandle) {
|
|
747
|
-
clearTimeout(this.harvesterHandle)
|
|
748
|
-
}
|
|
749
|
-
this._lastHarvest = null
|
|
750
|
-
this.harvesterHandle = null
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
/**
|
|
754
|
-
* Safely start the harvest cycle timer, and ensure that the harvest
|
|
755
|
-
* cycle won't keep an application from exiting if nothing else is
|
|
756
|
-
* happening to keep it up.
|
|
757
|
-
*
|
|
758
|
-
* @param {number} harvestSeconds - How many seconds between harvests.
|
|
759
|
-
*/
|
|
760
|
-
Agent.prototype._scheduleHarvester = function _scheduleHarvester(harvestSeconds) {
|
|
761
|
-
// TODO: If this has to persist for an extended time, prevent rescheduling when
|
|
762
|
-
// agent is in a 'stopping' or 'stopped' state.
|
|
763
|
-
|
|
764
|
-
const agent = this
|
|
765
|
-
let harvestDelay = harvestSeconds * TO_MILLIS
|
|
766
|
-
|
|
767
|
-
// If there was a previous harvest, we want to schedule the next one based on
|
|
768
|
-
// its start time.
|
|
769
|
-
const lastHarvestStart = this._lastHarvest && this._lastHarvest.startTime
|
|
770
|
-
if (lastHarvestStart) {
|
|
771
|
-
const timeSinceHarvest = Date.now() - this._lastHarvest.startTime
|
|
772
|
-
harvestDelay = Math.max(0, harvestDelay - timeSinceHarvest)
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
logger.trace(
|
|
776
|
-
'Scheduling harvester. ' +
|
|
777
|
-
`Last harvest start: ${lastHarvestStart}. Next harvest delay: ${harvestDelay}`
|
|
778
|
-
)
|
|
779
|
-
|
|
780
|
-
this.harvesterHandle = setTimeout(function doHarvest() {
|
|
781
|
-
// Agent#harvest handles scheduling the next harvest and properly reacting to
|
|
782
|
-
// any errors or commands. All we need to do is note any errors it spits out.
|
|
783
|
-
agent.harvest(function harvestError(error) {
|
|
784
|
-
if (error) {
|
|
785
|
-
logger.warn(error, 'Error on submission to New Relic.')
|
|
786
|
-
}
|
|
787
|
-
})
|
|
788
|
-
}, harvestDelay)
|
|
789
|
-
|
|
790
|
-
this.harvesterHandle.unref()
|
|
791
|
-
}
|
|
792
|
-
|
|
793
626
|
/**
|
|
794
627
|
* `agent_enabled` changed. This will generally only happen because of a high
|
|
795
628
|
* security mode mismatch between the agent and the collector. This only
|
|
@@ -19,24 +19,20 @@ class Aggregator extends EventEmitter {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
start() {
|
|
22
|
-
// TODO: log something useful on start?
|
|
23
22
|
logger.trace(`${this.method} aggregator started.`)
|
|
24
23
|
|
|
25
24
|
if (!this.sendTimer) {
|
|
26
|
-
// TODO: need to keep track of start time / last harvest?
|
|
27
|
-
|
|
28
25
|
this.sendTimer = setInterval(this.send.bind(this), this.periodMs)
|
|
29
26
|
this.sendTimer.unref()
|
|
30
27
|
}
|
|
31
28
|
}
|
|
32
29
|
|
|
33
30
|
stop() {
|
|
34
|
-
logger.trace(`${this.method} aggregator stopped.`)
|
|
35
|
-
|
|
36
31
|
if (this.sendTimer) {
|
|
37
|
-
// TODO: log something useful on stop
|
|
38
32
|
clearInterval(this.sendTimer)
|
|
39
33
|
this.sendTimer = null
|
|
34
|
+
|
|
35
|
+
logger.trace(`${this.method} aggregator stopped.`)
|
|
40
36
|
}
|
|
41
37
|
}
|
|
42
38
|
|
|
@@ -74,11 +70,6 @@ class Aggregator extends EventEmitter {
|
|
|
74
70
|
|
|
75
71
|
_runSend(data, payload) {
|
|
76
72
|
if (!payload) {
|
|
77
|
-
// TODO: log something about no data to send.
|
|
78
|
-
// or maybe not since handled in topayload?
|
|
79
|
-
// maybe do just here?
|
|
80
|
-
// May be better to handle ont he tranport side
|
|
81
|
-
// as a consistent spot
|
|
82
73
|
this._afterSend(false)
|
|
83
74
|
this.emit(`finished ${this.method} data send.`)
|
|
84
75
|
return
|
|
@@ -97,7 +88,6 @@ class Aggregator extends EventEmitter {
|
|
|
97
88
|
}
|
|
98
89
|
|
|
99
90
|
send() {
|
|
100
|
-
// TODO: log?
|
|
101
91
|
logger.info(`${this.method} Aggregator data send.`)
|
|
102
92
|
this.emit(`starting ${this.method} data send.`)
|
|
103
93
|
|
|
@@ -109,6 +99,7 @@ class Aggregator extends EventEmitter {
|
|
|
109
99
|
} else {
|
|
110
100
|
this._runSend(data, this._toPayloadSync())
|
|
111
101
|
}
|
|
102
|
+
|
|
112
103
|
this.clear()
|
|
113
104
|
}
|
|
114
105
|
|