atatus-nodejs
Version:
Atatus APM agent for Node.js
211 lines (170 loc) • 6.04 kB
JavaScript
const os = require('os')
const util = require('util')
const path = require('path')
const parseUrl = require('url').parse
const getContainerInfo = require('container-info')
const findPackageJson = require('./lib/find-package-json')
const sysinfo = require('./lib/sysinfo')
const Aggregator = require('./aggregator')
const Reporter = require('./reporter')
const getPackagesJSON = require('../packages')
// const flush = Symbol('flush')
const hostname = os.hostname()
const containerInfo = getContainerInfo.sync()
// const node8 = process.version.indexOf('v8.') === 0
module.exports = Collector
function Collector (agent) {
if (!(this instanceof Collector)) return new Collector(agent)
this.agent = agent
this.config(agent)
this.aggregator = new Aggregator(agent)
this.reporter = new Reporter(agent, this.aggregator)
}
async function getNodePackages(agent) {
try {
const packages = await getPackagesJSON(agent);
return packages
} catch (error) {
agent.logger.debug('Error getting JSON:', error);
}
}
Collector.prototype.start = function () {
this.reporter.start(() => {});
}
Collector.prototype.destroy = function () {
this.reporter.stop(() => {});
}
Collector.prototype.addMetadataFilter = function (fn) {
// TODO: To be done later
}
Collector.prototype.setExtraMetadata = function (metadata) {
// TODO: To be done later
}
Collector.prototype.lambdaStart = function () {
// TODO: To be done later
}
Collector.prototype.lambdaShouldRegisterTransactions = function () {
// TODO: To be done later
return true;
}
Collector.prototype.lambdaRegisterTransaction = function (trans, awsRequestId) {
// TODO: To be done later
}
Collector.prototype.supportsKeepingUnsampledTransaction = function () {
// TODO: To be done later
return true;
}
Collector.prototype.supportsActivationMethodField = function () {
// TODO: To be done later
return true;
}
Collector.prototype.supportsConfiguredAndDetectedHostname = function () {
// TODO: To be done later
return true;
}
Collector.prototype.config = function (agent) {
if (!agent._conf) {
agent._conf = {};
}
if (!agent._conf.hostname) {
agent._conf.hostname = hostname
}
if (containerInfo) {
if (!agent._conf.containerId && containerInfo.containerId) {
agent._conf.containerId = containerInfo.containerId
}
if (!agent._conf.kubernetesPodUID && containerInfo.podId) {
agent._conf.kubernetesPodUID = containerInfo.podId
}
if (!agent._conf.kubernetesPodName && containerInfo.podId) {
agent._conf.kubernetesPodName = hostname
}
}
sysinfo.osInfo(function (osInfo) {
agent.logger.debug('OS info: ', osInfo)
agent._conf.hostDetails = osInfo
})
try {
// Find node packages and go deep into previous folders unto 5 levels
let rootDir = process.argv[1] ? path.dirname(process.argv[1]) : process.cwd()
let packages = getNodePackages(agent);
packages
.then(result => {
// const resultdata = result[0].reduce((acc, item) => {
// try {
// const [key, value] = JSON.parse(item);
// acc[key] = value;
// } catch (error) {
// console.error('Error parsing item:', item, error);
// }
// return acc;
// }, {});
if (Array.isArray(result)) {
agent._conf.dependencies = result[0]
}
})
.catch(error => {
agent.logger.debug("Error with packages:", error)
});
// let finder = findPackageJson(rootDir)
// for(let i = 0; i < 5; i++) {
// let pkg = finder.next()
// if (pkg.value) {
// agent._conf.dependencies = pkg.value.dependencies
// break;
// }
// if (pkg.done) {
// break;
// }
// }
} catch (e) {
agent.logger.debug('Unable to get packages: ', e)
}
}
Collector.prototype.sendSpan = function (span, cb) {
let backendTracing = this.agent._conf.backendConfig && this.agent._conf.backendConfig.tracing
if (this.agent._conf._dtApmClient && this.agent._conf.tracing && backendTracing) {
this.agent._conf._dtApmClient.sendSpan(span)
}
this.agent.logger.debug('Adding Span: ', util.inspect(span, { depth: null }))
this.aggregator.addSpan(span)
}
Collector.prototype.sendTransaction = function (transaction, cb) {
let backendTracing = this.agent._conf.backendConfig && this.agent._conf.backendConfig.tracing
if (this.agent._conf._dtApmClient && this.agent._conf.tracing && backendTracing) {
this.agent._conf._dtApmClient.sendTransaction(transaction)
}
if (transaction.name.indexOf('static file') !== -1) {
return
}
try {
if (this.agent._conf.skip && this.agent._conf.skip(transaction)) {
this.agent.logger.debug('Skipped transaction event: ' + transaction.name)
return
}
} catch (e) {
this.agent.logger.error('Transaction skip function failed with exception: %s', e.message)
}
this.agent.logger.debug('Adding Transaction: ', util.inspect(transaction, { depth: null }))
let statusCode = transaction.context &&
transaction.context.response &&
transaction.context.response.status_code
if (statusCode >= 400 && this.agent._conf.ignoreStatusCodes.indexOf(statusCode) === -1) {
this.aggregator.addErrorMetrics(statusCode, transaction)
}
// FIXME: Sometimes addTxn calls before some span gets added to txn.
// Here we need to call addTxn after 5-10 ms to allow spans to add to existing transactions.
this.aggregator.addTxn(transaction)
}
Collector.prototype.sendError = function (error, cb) {
this.agent.logger.debug('Adding Error: ', util.inspect(error, {depth: null}))
this.aggregator.addErrorEvents(error)
}
Collector.prototype.sendMetricSet = function (metricset, cb) {
this.agent.logger.debug('Adding metric set: ', metricset)
this.aggregator.addMetric(metricset)
}
Collector.prototype.flush = function (opts, cb) {
return;
}