atatus-nodejs
Version:
Atatus APM agent for Node.js
248 lines (189 loc) • 6.84 kB
JavaScript
const Transporter = require('../transporter')
function Reporter(agent, aggregator) {
this.agent = agent
this.aggregator = aggregator
this.transporter = new Transporter(agent)
}
Reporter.prototype.start = function start(callback) {
if (!callback) throw new TypeError("callback required!")
let reporter = this
// For quicker data display, flush in 10 seconds after the startup
setTimeout(function intitial_delayed_flush() {
reporter.flush(function cb_flush(error) {
reporter._startReporter(reporter.agent._conf.metricsInterval)
reporter.transporter.sendHostInfo(callback)
})
}, 10000)
}
Reporter.prototype.stop = function stop(callback) {
if (!callback) throw new TypeError("callback required!")
this._stopReporter()
process.nextTick(callback)
}
Reporter.prototype.flush = function flush(callback) {
if (!callback) throw new TypeError("callback required!")
let reporter = this
let reporterSteps = [
'_reportTransactions',
'_reportTraces',
'_reportErrorEvents',
'_reportErrorMetrics',
'_reportHostInfo',
'_reportMetrics',
'_reportAnalytics',
]
runReporterStep(0)
function runReporterStep(n) {
reporter[reporterSteps[n++]](next)
function next(error) {
if (error || n >= reporterSteps.length) return callback(error)
runReporterStep(n)
}
}
}
Reporter.prototype._restartReporter = function _restartReporter(flushSeconds) {
this._stopReporter()
this._startReporter(flushSeconds)
}
Reporter.prototype._stopReporter = function _stopReporter() {
if (this.lifeCycleThread) clearInterval(this.lifeCycleThread)
this.lifeCycleThread = undefined
}
Reporter.prototype._startReporter = function _startReporter(flushSeconds) {
let reporter = this
function onError(error) {
if (error) {
reporter.agent.logger.info(error && error.message, "Unable to send data to Atatus server.")
}
}
function flush() {
reporter.flush(onError)
}
this.lifeCycleThread = setInterval(flush, flushSeconds * 1000)
if (this.lifeCycleThread.unref) this.lifeCycleThread.unref()
}
Reporter.prototype._reportTransactions = function _reportTransactions(callback) {
if (this.aggregator.isTransactionsEmpty()) {
this.agent.logger.debug("No transactions to send.")
return process.nextTick(callback)
}
let reporter = this
let payload = this.aggregator.getAndResetTransactionsPayload();
this.transporter.send('transactions', payload, function cb_transactions(error) {
if (error) reporter.aggregator.mergeTransactions(payload)
callback(error)
})
}
Reporter.prototype._reportAnalytics = function _reportAnalytics(callback) {
// Here we don't need to verify backend config analytics
// Because if host info set backend config analytics to false,
// then analytics payload queue will be there forever.
// Once backend config analytic set to false, then we will drop in aggregator.
if (!this.agent._conf.analytics) {
this.agent.logger.debug("Analytics is not enabled.")
this.aggregator.resetAnalyticsEvents()
return process.nextTick(callback)
}
if (this.aggregator.isAnalyticsEmpty()) {
this.agent.logger.debug("No analytic events to send.")
return process.nextTick(callback)
}
let reporter = this
let payload = this.aggregator.getAndResetAnalyticsPayload();
let analyticsSanitizedData = []
let analyticsPayloadLen = 0
let requests = payload.requests
if (payload.size > 6 * 1024 * 1024) {
for (let i = 0; i < requests.length; i++) {
analyticsSanitizedData.push(requests[i])
analyticsPayloadLen += (requests[i].bodyLength || 0)
if (analyticsPayloadLen > 6 * 1024 * 1024) {
payload.requests = analyticsSanitizedData
this.transporter.send('analytics', payload, function cb_analytics(error) {
if (error) reporter.aggregator.mergeAnalyticsEvents(payload)
})
analyticsSanitizedData = []
analyticsPayloadLen = 0
}
}
} else {
analyticsSanitizedData = requests;
}
if (analyticsSanitizedData.length > 0) {
payload.requests = analyticsSanitizedData
this.transporter.send('analytics', payload, function cb_analytics(error) {
if (error) reporter.aggregator.mergeAnalyticsEvents(payload)
callback(error)
})
analyticsSanitizedData = []
analyticsPayloadLen = 0
} else {
callback(null)
}
}
Reporter.prototype._reportTraces = function _reportTraces(callback) {
if (this.aggregator.isTracesEmpty()) {
this.agent.logger.debug("No traces to send.")
return process.nextTick(callback)
}
let reporter = this
let payload = this.aggregator.getAndResetTracesPayload();
this.transporter.send('traces', payload, function cb_traces(error) {
if (error) reporter.aggregator.mergeTraces(payload)
callback(error)
})
}
Reporter.prototype._reportErrorEvents = function _reportErrorEvents(callback) {
if (this.agent._conf.captureExceptions) {
if (this.aggregator.isErrorEventsEmpty()) {
this.agent.logger.debug("No error events to send.")
return process.nextTick(callback)
}
let reporter = this
let payload = this.aggregator.getAndResetErrorEventsPayload()
this.transporter.send('errorEvents', payload, function cb_errorEvents(error) {
if (error) reporter.aggregator.mergeErrorEventsPayload(payload)
callback(error)
})
} else {
this.aggregator.resetErrorEvents()
process.nextTick(callback)
}
}
Reporter.prototype._reportErrorMetrics = function _reportErrorMetrics(callback) {
if (this.aggregator.isErrorMetricsEmpty()) {
this.agent.logger.debug("No error metrics to send.")
return process.nextTick(callback)
}
let reporter = this
let payload = this.aggregator.getAndResetErrorMetricsPayload()
this.transporter.send('errorMetrics', payload, function cb_errorMetrics(error) {
if (error) reporter.aggregator.mergeErrorMetrics(payload)
callback(error)
})
}
Reporter.prototype._reportHostInfo = function _reportHostInfo(callback) {
let currentMinute = new Date().getMinutes()
if (currentMinute === 0 ||
currentMinute === 30) {
// Only send host info for every 30 minutes
this.transporter.sendHostInfo(function cb_hostInfo(error) {
callback(error)
})
} else {
return process.nextTick(callback)
}
}
Reporter.prototype._reportMetrics = function _reportMetrics(callback) {
if (this.aggregator.isMetricsEmpty()) {
this.agent.logger.debug("No system metrics to send.")
return process.nextTick(callback)
}
let reporter = this
let payload = this.aggregator.getAndResetMetrics();
this.transporter.send('metrics', payload, function cb_metrics(error) {
if (error) reporter.aggregator.mergeMetrics(payload)
callback(error)
})
}
module.exports = Reporter