newrelic 5.13.0 → 6.2.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/.travis.yml +20 -21
- package/NEWS.md +166 -0
- package/README.md +10 -10
- package/api.js +84 -2
- package/bin/run-versioned-tests.sh +3 -1
- package/bin/ssl.sh +43 -1
- package/bin/travis-node.sh +51 -0
- package/bin/travis-setup.sh +0 -4
- package/lib/agent.js +148 -315
- package/lib/aggregators/base-aggregator.js +3 -12
- package/lib/collector/api.js +2 -1
- package/lib/collector/facts.js +1 -1
- package/lib/config/default.js +8 -11
- package/lib/config/env.js +19 -1
- package/lib/config/index.js +52 -8
- package/lib/injector.js +161 -0
- package/lib/instrumentation/bluebird.js +4 -3
- package/lib/instrumentation/core/http-outbound.js +1 -0
- package/lib/instrumentation/mysql.js +10 -2
- package/lib/instrumentations.js +1 -1
- package/lib/shimmer.js +153 -5
- package/lib/spans/span-event-aggregator.js +1 -1
- package/lib/spans/span-event.js +1 -1
- package/lib/transaction/handle.js +11 -0
- package/lib/transaction/index.js +14 -3
- package/lib/transaction/trace/segment.js +10 -0
- package/lib/utilization/common.js +11 -4
- package/package.json +14 -11
- package/stub_api.js +8 -0
- package/lib/event-aggregator.js +0 -94
- package/lib/harvest.js +0 -718
- package/lib/instrumentation/aws-sdk.js +0 -25
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
|
|
package/lib/collector/api.js
CHANGED
|
@@ -469,7 +469,8 @@ CollectorAPI.prototype.restart = function restart(callback) {
|
|
|
469
469
|
CollectorAPI.prototype._runLifecycle = function _runLifecycle(method, body, callback) {
|
|
470
470
|
if (!this.isConnected()) {
|
|
471
471
|
logger.warn('Not connected to New Relic. Not calling.', method.name)
|
|
472
|
-
|
|
472
|
+
const error = new Error('Not connected to collector.', null, null)
|
|
473
|
+
return setImmediate(callback, error)
|
|
473
474
|
}
|
|
474
475
|
|
|
475
476
|
const api = this
|
package/lib/collector/facts.js
CHANGED
|
@@ -52,7 +52,7 @@ function facts(agent, callback) {
|
|
|
52
52
|
|
|
53
53
|
results.event_harvest_config = {
|
|
54
54
|
harvest_limits: {
|
|
55
|
-
analytic_event_data: agent.config.transaction_events.
|
|
55
|
+
analytic_event_data: agent.config.transaction_events.max_samples_stored,
|
|
56
56
|
custom_event_data: agent.config.custom_insights_events.max_samples_stored,
|
|
57
57
|
error_event_data: agent.config.error_collector.max_event_samples_stored,
|
|
58
58
|
span_event_data: Config.SPAN_EVENT_LIMIT
|
package/lib/config/default.js
CHANGED
|
@@ -179,6 +179,13 @@ exports.config = () => ({
|
|
|
179
179
|
filter_cache_limit: 1000
|
|
180
180
|
},
|
|
181
181
|
|
|
182
|
+
diagnostics: {
|
|
183
|
+
code_injector: {
|
|
184
|
+
enabled: false,
|
|
185
|
+
internal_file_pattern: /nodejs_agent\/(?:(?!test))|\/node_modules\/(?:@)?newrelic/
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
|
|
182
189
|
logging: {
|
|
183
190
|
/**
|
|
184
191
|
* Verbosity of the module's logging. This module uses bunyan
|
|
@@ -655,17 +662,7 @@ exports.config = () => ({
|
|
|
655
662
|
* The agent will collect all events up to this number per minute. If
|
|
656
663
|
* there are more than that, a statistical sampling will be collected.
|
|
657
664
|
*/
|
|
658
|
-
|
|
659
|
-
/**
|
|
660
|
-
* This is used if the agent is unable to send events to the collector.
|
|
661
|
-
* The values from the previous harvest cycle will be merged into the next
|
|
662
|
-
* one with this option as the limit.
|
|
663
|
-
*
|
|
664
|
-
* This should be *greater* than max_samples_per_minute or you'll see odd
|
|
665
|
-
* behavior. You probably want at least double the value, but more is okay
|
|
666
|
-
* as long as you can handle the memory overhead.
|
|
667
|
-
*/
|
|
668
|
-
max_samples_stored: 20000
|
|
665
|
+
max_samples_stored: 10000
|
|
669
666
|
},
|
|
670
667
|
|
|
671
668
|
/**
|