appdynamics
Version:
Performance Profiler and Monitor
249 lines (217 loc) • 7.16 kB
JavaScript
/*
Copyright (c) AppDynamics, Inc., and its affiliates
2015
All Rights Reserved
*/
;
var LibagentTransactionReporter = require('./transactions/transaction-reporter').TransactionReporter;
var cluster = require('cluster');
var fs = require('fs');
var os = require('os');
function LibAgent(agent) {
this.agent = agent;
this.transactionReporter = new LibagentTransactionReporter(this);
var self = this;
this.agent.on('nodeIndexComputed', function() {
self.agent.libagentConnector.init();
});
this.nodeIndexComputed = false;
// For unit-testing
this.libagent = true;
}
exports.LibAgent = LibAgent;
LibAgent.prototype.init = function() {
this.transactionReporter.init();
};
LibAgent.prototype.addNodeIndexToNodeName = function() {
var self = this;
self.indexDir = self.agent.tmpDir + '/index';
// disable waiting for BT info response
self.agent.opts.btEntryPointDelayDisabled = true;
// emit start agent event along with node index
self.identifyNodeIndex(function(err, nodeIndex) {
if (err) {
self.agent.logger.error(err);
return;
}
process.nextTick(function() {
if (cluster.isMaster && self.agent.opts.monitorClusterMaster === false) {
// do not monitor cluster master node
return;
}
if (process.env.NODE_OPTIONS !== undefined && process.env.NODE_OPTIONS.includes("shim.js")) {
// do not monitor NODE_OPTIONS with npm or yarn
if (process.argv.filter(arg => arg.includes("yarn")).length !== 0) {
return;
}
if (process.argv.filter(arg => arg.includes("npm")).length !== 0) {
return;
}
}
// create or update node name
var computedNodeName = (self.agent.opts.nodeName || os.hostname());
if (!self.agent.opts.noNodeNameSuffix) {
computedNodeName += '-' + nodeIndex;
}
self.agent.opts.nodeName = computedNodeName;
self.nodeIndexComputed = true;
self.agent.emit('nodeIndexComputed');
});
});
};
LibAgent.prototype.identifyNodeIndex = function(callback) {
var self = this;
if (cluster.isMaster) {
var nodeIndex = self.agent.opts.nodeIndex || 0;
callback(null, nodeIndex);
}
else if ('pm_id' in process.env && !isNaN(process.env.pm_id)) {
callback(null, Number(process.env.pm_id));
}
else {
self.agent.timers.setTimeout(function() {
self.readNodeIndex(function(nodeIndex) {
if (nodeIndex !== null) {
callback(null, nodeIndex);
}
else {
self.agent.timers.setTimeout(function() {
self.readNodeIndex(function(nodeIndex) {
if (nodeIndex !== null) {
callback(null, nodeIndex);
}
else {
// return pid instead of index if indexing is not available,
// e.g. this process is forked from a worker
callback(null, process.pid);
}
});
}, 4000);
}
});
}, 1000);
}
};
/* istanbul ignore next */
LibAgent.prototype.readNodeIndex = function(callback) {
var self = this;
var callbackCalled = false;
function callbackOnce(ret) {
if(!callbackCalled) {
callbackCalled = true;
callback(ret);
}
}
fs.exists(self.indexDir, function(exists) {
if (!exists) return;
fs.readdir(self.indexDir, function(err, indexFiles) {
if (err) return self.agent.logger.error(err);
indexFiles.forEach(function(indexFile) {
var nodeIndex = parseInt(indexFile.split('.')[0]);
if (!isNaN(nodeIndex)) {
fs.readFile(self.indexDir + '/' + indexFile, function(err, pid) {
if (err) return self.agent.logger.error(err);
if (pid == process.pid) {
callbackOnce(nodeIndex);
}
});
}
});
});
});
self.agent.timers.setTimeout(function() {
callbackOnce(null);
}, 2000);
};
LibAgent.prototype.initializeLogger = function() {
var self = this;
self.agent.logger.setLibAgentConnector(self.agent.libagentConnector);
self.agent.logger.init(self.agent.opts.logging);
};
LibAgent.prototype.createCLRDirectories = function() {
// This function is not needed for libagent.
// It is added only to match the libproxy ProxyCustom object.
};
LibAgent.prototype.intializeAgentHelpers = function() {
this.agent.transactionSender.init();
this.agent.processSnapshotSender.init();
this.agent.metricSender.init();
this.agent.instanceInfoSender.init();
};
LibAgent.prototype.startAgent = function(metadata, filters) {
var self = this;
if (self.nodeIndexComputed) {
self.agent.emit('agentStarted', metadata, filters);
} else {
// Wait for the nodeAgent to be initialized
self.agent.on('nodeIndexComputed', function() {
self.agent.emit('agentStarted', metadata, filters);
});
}
};
LibAgent.prototype.createExitCall = function(time, exitCallInfo) {
var self = this;
var exitType = exitCallInfo.exitType.replace(/^EXIT_/, '');
var exitCallObj = {
threadId: time.threadId,
exitPointType: exitType,
exitPointSubType: exitCallInfo.exitSubType,
backendName: exitCallInfo.backendName,
category: exitCallInfo.category || '',
command: exitCallInfo.command || '',
properties: exitCallInfo.supportedProperties,
useBackendConfig: exitCallInfo.useBackendConfig,
protocol: exitCallInfo.protocol,
addAnalyticsData: function(key, value) {
this.userData = this.userData || [];
if (value instanceof Date) {
this.userData.push({ name: key, value: value.toISOString() });
} else {
this.userData.push({ name: key, value: value });
}
}
};
var transaction = self.agent.profiler.transactions[exitCallObj.threadId];
if (transaction && !transaction.skip) {
if (transaction.api && transaction.api.beforeExitCall) {
exitCallObj = transaction.api.beforeExitCall(exitCallObj);
if (!exitCallObj) {
return;
}
}
self.agent.emit('exitCallStarted', transaction, exitCallObj);
if (!transaction.startedExitCalls) {
transaction.startedExitCalls = [];
}
if (exitCallObj.exitCallGuid !== undefined) {
transaction.startedExitCalls.push(exitCallObj);
}
}
return exitCallObj;
};
LibAgent.prototype.stopExitCall = function(exitCall, error) {
var self = this;
var transaction = self.agent.profiler.transactions[exitCall.threadId];
if (transaction) {
self.agent.emit('exitCallStopped', transaction, exitCall, error);
}
};
LibAgent.prototype.createSnapshotTrigger = function() {
return {
attachSnapshot: true,
snapshotTrigger: 'REQUIRED' // FIXME: override this within NodeAgent
};
};
LibAgent.prototype.getCorrelationHeader = function(exitCall) {
if ('correlationHeader' in exitCall) {
return exitCall.correlationHeader;
}
};
LibAgent.prototype.startProcessSnapshot = function() {
var self = this;
self.agent.libagentConnector.startProcessSnapshot();
};
LibAgent.prototype.setRequiresNamingRules = function (flag) {
var self = this;
self.agent.setRequiresNamingRules(flag);
};